ffd288efea
Test coverage for: - Task package: models, repository (memory + SQLite), service, API handlers - Agent package: registry, lifecycle manager, credentials manager, API handlers - Orchestrator package: queue, scheduler, watcher, ACP message store - Events package: in-memory event bus with pub/sub - ACP protocol: message types, helpers, JSON marshaling All tests pass with 'go test ./...'
187 lines
4.2 KiB
Go
187 lines
4.2 KiB
Go
package protocol
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestMessageType_Constants(t *testing.T) {
|
|
tests := []struct {
|
|
msgType MessageType
|
|
expected string
|
|
}{
|
|
{MessageTypeProgress, "progress"},
|
|
{MessageTypeLog, "log"},
|
|
{MessageTypeResult, "result"},
|
|
{MessageTypeError, "error"},
|
|
{MessageTypeStatus, "status"},
|
|
{MessageTypeHeartbeat, "heartbeat"},
|
|
{MessageTypeControl, "control"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
if string(tt.msgType) != tt.expected {
|
|
t.Errorf("Expected MessageType %s, got %s", tt.expected, tt.msgType)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNewMessage(t *testing.T) {
|
|
agentID := "agent-123"
|
|
taskID := "task-456"
|
|
data := map[string]interface{}{"key": "value"}
|
|
|
|
before := time.Now().UTC()
|
|
msg := NewMessage(MessageTypeProgress, agentID, taskID, data)
|
|
after := time.Now().UTC()
|
|
|
|
if msg.Type != MessageTypeProgress {
|
|
t.Errorf("Expected type %s, got %s", MessageTypeProgress, msg.Type)
|
|
}
|
|
if msg.AgentID != agentID {
|
|
t.Errorf("Expected agentID %s, got %s", agentID, msg.AgentID)
|
|
}
|
|
if msg.TaskID != taskID {
|
|
t.Errorf("Expected taskID %s, got %s", taskID, msg.TaskID)
|
|
}
|
|
if msg.Data["key"] != "value" {
|
|
t.Error("Expected data to contain key=value")
|
|
}
|
|
if msg.Timestamp.Before(before) || msg.Timestamp.After(after) {
|
|
t.Error("Expected timestamp to be set to current time")
|
|
}
|
|
}
|
|
|
|
func TestMessage_MarshalJSON(t *testing.T) {
|
|
fixedTime := time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC)
|
|
msg := &Message{
|
|
Type: MessageTypeLog,
|
|
Timestamp: fixedTime,
|
|
AgentID: "agent-001",
|
|
TaskID: "task-001",
|
|
Data: map[string]interface{}{"level": "info"},
|
|
}
|
|
|
|
data, err := json.Marshal(msg)
|
|
if err != nil {
|
|
t.Fatalf("MarshalJSON failed: %v", err)
|
|
}
|
|
|
|
var result map[string]interface{}
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
t.Fatalf("Failed to unmarshal result: %v", err)
|
|
}
|
|
|
|
if result["type"] != "log" {
|
|
t.Errorf("Expected type 'log', got %v", result["type"])
|
|
}
|
|
if result["agent_id"] != "agent-001" {
|
|
t.Errorf("Expected agent_id 'agent-001', got %v", result["agent_id"])
|
|
}
|
|
if result["task_id"] != "task-001" {
|
|
t.Errorf("Expected task_id 'task-001', got %v", result["task_id"])
|
|
}
|
|
|
|
// Check timestamp is in RFC3339Nano format
|
|
ts, ok := result["timestamp"].(string)
|
|
if !ok {
|
|
t.Fatal("Expected timestamp to be a string")
|
|
}
|
|
_, err = time.Parse(time.RFC3339Nano, ts)
|
|
if err != nil {
|
|
t.Errorf("Timestamp not in RFC3339Nano format: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParse(t *testing.T) {
|
|
jsonData := []byte(`{
|
|
"type": "progress",
|
|
"timestamp": "2024-01-15T10:30:00Z",
|
|
"agent_id": "agent-test",
|
|
"task_id": "task-test",
|
|
"data": {"progress": 50, "message": "Processing..."}
|
|
}`)
|
|
|
|
msg, err := Parse(jsonData)
|
|
if err != nil {
|
|
t.Fatalf("Parse failed: %v", err)
|
|
}
|
|
|
|
if msg.Type != MessageTypeProgress {
|
|
t.Errorf("Expected type %s, got %s", MessageTypeProgress, msg.Type)
|
|
}
|
|
if msg.AgentID != "agent-test" {
|
|
t.Errorf("Expected agentID 'agent-test', got %s", msg.AgentID)
|
|
}
|
|
if msg.TaskID != "task-test" {
|
|
t.Errorf("Expected taskID 'task-test', got %s", msg.TaskID)
|
|
}
|
|
if msg.Data["progress"] != float64(50) {
|
|
t.Errorf("Expected progress 50, got %v", msg.Data["progress"])
|
|
}
|
|
}
|
|
|
|
func TestParse_InvalidJSON(t *testing.T) {
|
|
invalidJSON := []byte(`{invalid json}`)
|
|
|
|
_, err := Parse(invalidJSON)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid JSON")
|
|
}
|
|
}
|
|
|
|
func TestMessage_IsValid(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
msg *Message
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "valid message",
|
|
msg: &Message{
|
|
Type: MessageTypeProgress,
|
|
AgentID: "agent-1",
|
|
TaskID: "task-1",
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "missing type",
|
|
msg: &Message{
|
|
Type: "",
|
|
AgentID: "agent-1",
|
|
TaskID: "task-1",
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "missing agent_id",
|
|
msg: &Message{
|
|
Type: MessageTypeProgress,
|
|
AgentID: "",
|
|
TaskID: "task-1",
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "missing task_id",
|
|
msg: &Message{
|
|
Type: MessageTypeProgress,
|
|
AgentID: "agent-1",
|
|
TaskID: "",
|
|
},
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.msg.IsValid(); got != tt.expected {
|
|
t.Errorf("IsValid() = %v, expected %v", got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|