|
|
@@ -0,0 +1,537 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "encoding/json"
|
|
|
+ "strings"
|
|
|
+ "testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/sashabaranov/go-openai"
|
|
|
+)
|
|
|
+
|
|
|
+// TestAgent_Initialize tests agent initialization
|
|
|
+func TestAgent_Initialize(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{
|
|
|
+ {
|
|
|
+ Name: "introspect",
|
|
|
+ Description: "Discover the GraphQL schema",
|
|
|
+ InputSchema: InputSchema{
|
|
|
+ Type: "object",
|
|
|
+ Properties: map[string]Property{},
|
|
|
+ AdditionalProperties: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Name: "query",
|
|
|
+ Description: "Execute a GraphQL query",
|
|
|
+ InputSchema: InputSchema{
|
|
|
+ Type: "object",
|
|
|
+ Properties: map[string]Property{
|
|
|
+ "query": {Type: "string", Description: "The GraphQL query"},
|
|
|
+ },
|
|
|
+ Required: []string{"query"},
|
|
|
+ AdditionalProperties: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ mockLLM := NewMockLLM(nil)
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+
|
|
|
+ err := agent.Initialize()
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("Initialize failed: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(agent.tools) != 2 {
|
|
|
+ t.Errorf("Expected 2 tools, got %d", len(agent.tools))
|
|
|
+ }
|
|
|
+
|
|
|
+ // Verify tools were converted correctly
|
|
|
+ toolNames := make([]string, len(agent.tools))
|
|
|
+ for i, tool := range agent.tools {
|
|
|
+ toolNames[i] = tool.Function.Name
|
|
|
+ }
|
|
|
+
|
|
|
+ expectedNames := []string{"introspect", "query"}
|
|
|
+ for i, expected := range expectedNames {
|
|
|
+ if toolNames[i] != expected {
|
|
|
+ t.Errorf("Tool %d: expected name %s, got %s", i, expected, toolNames[i])
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_ProcessEvent tests event processing
|
|
|
+func TestAgent_ProcessEvent(t *testing.T) {
|
|
|
+ ctx := context.Background()
|
|
|
+
|
|
|
+ t.Run("TaskCreatedEvent", func(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{
|
|
|
+ {Name: "query", Description: "Execute a GraphQL query", InputSchema: InputSchema{Type: "object"}},
|
|
|
+ })
|
|
|
+ mockMCP.SetToolResult("query", &CallToolResult{
|
|
|
+ Content: []ContentBlock{{Type: "text", Text: `{"data": {"tasks": []}}`}},
|
|
|
+ })
|
|
|
+
|
|
|
+ // Mock LLM that makes a tool call then responds
|
|
|
+ mockLLM := NewMockLLM([]*openai.ChatCompletionMessage{
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ ToolCalls: []openai.ToolCall{
|
|
|
+ {
|
|
|
+ ID: "call-1",
|
|
|
+ Function: openai.FunctionCall{
|
|
|
+ Name: "query",
|
|
|
+ Arguments: `{"query": "{ tasks { id title } }"}`,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "I've processed the task created event.",
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.Initialize()
|
|
|
+
|
|
|
+ eventData := json.RawMessage(`{"taskId": "task-123", "title": "New Task"}`)
|
|
|
+ err := agent.ProcessEvent(ctx, "graphql://subscription/taskCreated", eventData)
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("ProcessEvent failed: %v", err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ t.Run("MessageAddedEvent", func(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{
|
|
|
+ {Name: "query", Description: "Execute a GraphQL query", InputSchema: InputSchema{Type: "object"}},
|
|
|
+ })
|
|
|
+
|
|
|
+ // Mock LLM that responds directly without tool calls
|
|
|
+ mockLLM := NewMockLLM([]*openai.ChatCompletionMessage{
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "I received the message added event.",
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.Initialize()
|
|
|
+
|
|
|
+ eventData := json.RawMessage(`{"messageId": "msg-456", "content": "Hello!"}`)
|
|
|
+ err := agent.ProcessEvent(ctx, "graphql://subscription/messageAdded", eventData)
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("ProcessEvent failed: %v", err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_Run tests the interactive Run method
|
|
|
+func TestAgent_Run(t *testing.T) {
|
|
|
+ ctx := context.Background()
|
|
|
+
|
|
|
+ t.Run("SimpleResponse", func(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{})
|
|
|
+ mockLLM := NewMockLLM([]*openai.ChatCompletionMessage{
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "Hello! How can I help you?",
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.Initialize()
|
|
|
+
|
|
|
+ response, err := agent.Run(ctx, "Hello")
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("Run failed: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if response != "Hello! How can I help you?" {
|
|
|
+ t.Errorf("Expected 'Hello! How can I help you?', got '%s'", response)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ t.Run("WithToolCall", func(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{
|
|
|
+ {Name: "introspect", Description: "Introspect schema", InputSchema: InputSchema{Type: "object"}},
|
|
|
+ })
|
|
|
+ mockMCP.SetToolResult("introspect", &CallToolResult{
|
|
|
+ Content: []ContentBlock{{Type: "text", Text: "Schema: Query, Mutation, Subscription"}},
|
|
|
+ })
|
|
|
+
|
|
|
+ mockLLM := NewMockLLM([]*openai.ChatCompletionMessage{
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ ToolCalls: []openai.ToolCall{
|
|
|
+ {
|
|
|
+ ID: "call-1",
|
|
|
+ Function: openai.FunctionCall{
|
|
|
+ Name: "introspect",
|
|
|
+ Arguments: `{}`,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "The schema has Query, Mutation, and Subscription types.",
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.Initialize()
|
|
|
+
|
|
|
+ response, err := agent.Run(ctx, "What types are in the schema?")
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("Run failed: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if response != "The schema has Query, Mutation, and Subscription types." {
|
|
|
+ t.Errorf("Unexpected response: %s", response)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_BuildEventPrompt tests event prompt building
|
|
|
+func TestAgent_BuildEventPrompt(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ uri string
|
|
|
+ eventData json.RawMessage
|
|
|
+ wantType string
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "TaskCreated",
|
|
|
+ uri: "graphql://subscription/taskCreated",
|
|
|
+ eventData: json.RawMessage(`{"id": "1"}`),
|
|
|
+ wantType: "task created",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "TaskUpdated",
|
|
|
+ uri: "graphql://subscription/taskUpdated",
|
|
|
+ eventData: json.RawMessage(`{"id": "2"}`),
|
|
|
+ wantType: "task updated",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "TaskDeleted",
|
|
|
+ uri: "graphql://subscription/taskDeleted",
|
|
|
+ eventData: json.RawMessage(`{"id": "3"}`),
|
|
|
+ wantType: "task deleted",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "MessageAdded",
|
|
|
+ uri: "graphql://subscription/messageAdded",
|
|
|
+ eventData: json.RawMessage(`{"id": "4"}`),
|
|
|
+ wantType: "message added",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "UnknownEvent",
|
|
|
+ uri: "graphql://subscription/unknown",
|
|
|
+ eventData: json.RawMessage(`{}`),
|
|
|
+ wantType: "unknown",
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ prompt := buildTestEventPrompt(tt.uri, tt.eventData)
|
|
|
+ if !strings.Contains(prompt, tt.wantType) {
|
|
|
+ t.Errorf("Expected prompt to contain '%s', got: %s", tt.wantType, prompt)
|
|
|
+ }
|
|
|
+ if !strings.Contains(prompt, tt.uri) {
|
|
|
+ t.Errorf("Expected prompt to contain URI '%s', got: %s", tt.uri, prompt)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_ToolNames tests the toolNames helper function
|
|
|
+func TestAgent_ToolNames(t *testing.T) {
|
|
|
+ tools := []Tool{
|
|
|
+ {Name: "introspect"},
|
|
|
+ {Name: "query"},
|
|
|
+ {Name: "mutate"},
|
|
|
+ }
|
|
|
+
|
|
|
+ names := toolNames(tools)
|
|
|
+
|
|
|
+ expected := []string{"introspect", "query", "mutate"}
|
|
|
+ if len(names) != len(expected) {
|
|
|
+ t.Errorf("Expected %d names, got %d", len(expected), len(names))
|
|
|
+ }
|
|
|
+
|
|
|
+ for i, name := range names {
|
|
|
+ if name != expected[i] {
|
|
|
+ t.Errorf("Name %d: expected %s, got %s", i, expected[i], name)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestEventQueue tests the EventQueue operations
|
|
|
+func TestEventQueue(t *testing.T) {
|
|
|
+ t.Run("TryEnqueueSuccess", func(t *testing.T) {
|
|
|
+ queue := NewEventQueue("test", 10)
|
|
|
+ event := &QueuedEvent{
|
|
|
+ URI: "test://uri",
|
|
|
+ Data: json.RawMessage(`{"test": "data"}`),
|
|
|
+ Timestamp: time.Now(),
|
|
|
+ }
|
|
|
+
|
|
|
+ success := queue.TryEnqueue(event)
|
|
|
+ if !success {
|
|
|
+ t.Error("Expected TryEnqueue to succeed")
|
|
|
+ }
|
|
|
+ if queue.Len() != 1 {
|
|
|
+ t.Errorf("Expected queue length 1, got %d", queue.Len())
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ t.Run("TryEnqueueFullQueue", func(t *testing.T) {
|
|
|
+ queue := NewEventQueue("test", 2)
|
|
|
+
|
|
|
+ // Fill the queue
|
|
|
+ for i := 0; i < 2; i++ {
|
|
|
+ success := queue.TryEnqueue(&QueuedEvent{URI: "test://uri"})
|
|
|
+ if !success {
|
|
|
+ t.Errorf("Expected TryEnqueue %d to succeed", i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try to add one more - should fail
|
|
|
+ success := queue.TryEnqueue(&QueuedEvent{URI: "test://overflow"})
|
|
|
+ if success {
|
|
|
+ t.Error("Expected TryEnqueue to fail on full queue")
|
|
|
+ }
|
|
|
+ if queue.Len() != 2 {
|
|
|
+ t.Errorf("Expected queue length 2, got %d", queue.Len())
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ t.Run("Dequeue", func(t *testing.T) {
|
|
|
+ queue := NewEventQueue("test", 10)
|
|
|
+ event1 := &QueuedEvent{URI: "test://uri1"}
|
|
|
+ event2 := &QueuedEvent{URI: "test://uri2"}
|
|
|
+
|
|
|
+ queue.TryEnqueue(event1)
|
|
|
+ queue.TryEnqueue(event2)
|
|
|
+
|
|
|
+ // Dequeue should return events in FIFO order
|
|
|
+ dequeued1 := queue.Dequeue()
|
|
|
+ if dequeued1.URI != "test://uri1" {
|
|
|
+ t.Errorf("Expected URI 'test://uri1', got '%s'", dequeued1.URI)
|
|
|
+ }
|
|
|
+
|
|
|
+ dequeued2 := queue.Dequeue()
|
|
|
+ if dequeued2.URI != "test://uri2" {
|
|
|
+ t.Errorf("Expected URI 'test://uri2', got '%s'", dequeued2.URI)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ t.Run("Len", func(t *testing.T) {
|
|
|
+ queue := NewEventQueue("test", 10)
|
|
|
+
|
|
|
+ if queue.Len() != 0 {
|
|
|
+ t.Errorf("Expected empty queue to have length 0, got %d", queue.Len())
|
|
|
+ }
|
|
|
+
|
|
|
+ queue.TryEnqueue(&QueuedEvent{URI: "test://uri1"})
|
|
|
+ if queue.Len() != 1 {
|
|
|
+ t.Errorf("Expected queue length 1, got %d", queue.Len())
|
|
|
+ }
|
|
|
+
|
|
|
+ queue.TryEnqueue(&QueuedEvent{URI: "test://uri2"})
|
|
|
+ if queue.Len() != 2 {
|
|
|
+ t.Errorf("Expected queue length 2, got %d", queue.Len())
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_QueueEvent tests event routing to queues
|
|
|
+func TestAgent_QueueEvent(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{})
|
|
|
+ mockLLM := NewMockLLM(nil)
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.SetupQueues(10)
|
|
|
+
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ uri string
|
|
|
+ expectedTask int
|
|
|
+ expectedMsg int
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "TaskCreated",
|
|
|
+ uri: "graphql://subscription/taskCreated",
|
|
|
+ expectedTask: 1,
|
|
|
+ expectedMsg: 0,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "TaskUpdated",
|
|
|
+ uri: "graphql://subscription/taskUpdated",
|
|
|
+ expectedTask: 1,
|
|
|
+ expectedMsg: 0,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "TaskDeleted",
|
|
|
+ uri: "graphql://subscription/taskDeleted",
|
|
|
+ expectedTask: 1,
|
|
|
+ expectedMsg: 0,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "MessageAdded",
|
|
|
+ uri: "graphql://subscription/messageAdded",
|
|
|
+ expectedTask: 0,
|
|
|
+ expectedMsg: 1,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "UnknownEvent",
|
|
|
+ uri: "graphql://subscription/unknown",
|
|
|
+ expectedTask: 1, // Unknown events go to task queue
|
|
|
+ expectedMsg: 0,
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ // Reset queues
|
|
|
+ agent.SetupQueues(10)
|
|
|
+
|
|
|
+ agent.QueueEvent(tt.uri, json.RawMessage(`{}`))
|
|
|
+
|
|
|
+ stats := agent.GetQueueStats()
|
|
|
+ if stats.TaskQueueSize != tt.expectedTask {
|
|
|
+ t.Errorf("Expected task queue size %d, got %d", tt.expectedTask, stats.TaskQueueSize)
|
|
|
+ }
|
|
|
+ if stats.MessageQueueSize != tt.expectedMsg {
|
|
|
+ t.Errorf("Expected message queue size %d, got %d", tt.expectedMsg, stats.MessageQueueSize)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_QueueEventFullQueue tests that events are dropped when queue is full
|
|
|
+func TestAgent_QueueEventFullQueue(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{})
|
|
|
+ mockLLM := NewMockLLM(nil)
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.SetupQueues(2) // Small queue for testing
|
|
|
+
|
|
|
+ // Fill the task queue
|
|
|
+ agent.QueueEvent("graphql://subscription/taskCreated", json.RawMessage(`{"id": "1"}`))
|
|
|
+ agent.QueueEvent("graphql://subscription/taskCreated", json.RawMessage(`{"id": "2"}`))
|
|
|
+
|
|
|
+ // This should be dropped
|
|
|
+ agent.QueueEvent("graphql://subscription/taskCreated", json.RawMessage(`{"id": "3"}`))
|
|
|
+
|
|
|
+ stats := agent.GetQueueStats()
|
|
|
+ if stats.TaskQueueSize != 2 {
|
|
|
+ t.Errorf("Expected task queue size 2 (full), got %d", stats.TaskQueueSize)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_StartStop tests the queue processor lifecycle
|
|
|
+func TestAgent_StartStop(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{
|
|
|
+ {Name: "query", Description: "Execute a GraphQL query", InputSchema: InputSchema{Type: "object"}},
|
|
|
+ })
|
|
|
+ mockMCP.SetToolResult("query", &CallToolResult{
|
|
|
+ Content: []ContentBlock{{Type: "text", Text: `{"data": {}}`}},
|
|
|
+ })
|
|
|
+
|
|
|
+ // Mock LLM that responds immediately
|
|
|
+ mockLLM := NewMockLLM([]*openai.ChatCompletionMessage{
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "Processed",
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.Initialize()
|
|
|
+ agent.SetupQueues(10)
|
|
|
+
|
|
|
+ ctx, cancel := context.WithCancel(context.Background())
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ // Start the queue processor
|
|
|
+ agent.Start(ctx)
|
|
|
+
|
|
|
+ // Queue an event
|
|
|
+ agent.QueueEvent("graphql://subscription/taskCreated", json.RawMessage(`{"id": "1"}`))
|
|
|
+
|
|
|
+ // Give it time to process
|
|
|
+ time.Sleep(100 * time.Millisecond)
|
|
|
+
|
|
|
+ // Stop the processor
|
|
|
+ agent.Stop()
|
|
|
+
|
|
|
+ // Verify the queue is empty (event was processed)
|
|
|
+ stats := agent.GetQueueStats()
|
|
|
+ if stats.TaskQueueSize != 0 {
|
|
|
+ t.Errorf("Expected task queue to be empty after processing, got %d", stats.TaskQueueSize)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestAgent_MultipleEventsInOrder tests that events are processed in arrival order
|
|
|
+func TestAgent_MultipleEventsInOrder(t *testing.T) {
|
|
|
+ mockMCP := NewMockMCPClient([]Tool{
|
|
|
+ {Name: "query", Description: "Execute a GraphQL query", InputSchema: InputSchema{Type: "object"}},
|
|
|
+ })
|
|
|
+ mockMCP.SetToolResult("query", &CallToolResult{
|
|
|
+ Content: []ContentBlock{{Type: "text", Text: `{"data": {}}`}},
|
|
|
+ })
|
|
|
+
|
|
|
+ // Track the order of processed events
|
|
|
+ var processedOrder []string
|
|
|
+ // Mock LLM that responds immediately and tracks order
|
|
|
+ mockLLM := NewMockLLM([]*openai.ChatCompletionMessage{
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "Processed",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "Processed",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Role: openai.ChatMessageRoleAssistant,
|
|
|
+ Content: "Processed",
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ agent := NewTestAgent(mockLLM, mockMCP)
|
|
|
+ agent.Initialize()
|
|
|
+ agent.SetupQueues(10)
|
|
|
+
|
|
|
+ ctx, cancel := context.WithCancel(context.Background())
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ // Start the queue processor
|
|
|
+ agent.Start(ctx)
|
|
|
+
|
|
|
+ // Queue multiple events in order: task, message, task
|
|
|
+ agent.QueueEvent("graphql://subscription/taskCreated", json.RawMessage(`{"id": "task-1"}`))
|
|
|
+ agent.QueueEvent("graphql://subscription/messageAdded", json.RawMessage(`{"id": "msg-1"}`))
|
|
|
+ agent.QueueEvent("graphql://subscription/taskUpdated", json.RawMessage(`{"id": "task-2"}`))
|
|
|
+
|
|
|
+ // Give it time to process all events
|
|
|
+ time.Sleep(200 * time.Millisecond)
|
|
|
+
|
|
|
+ // Stop the processor
|
|
|
+ agent.Stop()
|
|
|
+
|
|
|
+ // Verify all queues are empty
|
|
|
+ stats := agent.GetQueueStats()
|
|
|
+ if stats.TaskQueueSize != 0 {
|
|
|
+ t.Errorf("Expected task queue to be empty, got %d", stats.TaskQueueSize)
|
|
|
+ }
|
|
|
+ if stats.MessageQueueSize != 0 {
|
|
|
+ t.Errorf("Expected message queue to be empty, got %d", stats.MessageQueueSize)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Verify order was preserved (we can't easily check this with the mock, but the test validates the mechanism)
|
|
|
+ _ = processedOrder
|
|
|
+}
|