comprehensive_test.go
1 package test 2 3 import ( 4 "context" 5 "os" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/TransformerOS/kamaji-go/internal/agents" 11 "github.com/TransformerOS/kamaji-go/internal/providers" 12 "github.com/TransformerOS/kamaji-go/internal/tools" 13 ) 14 15 func TestAllComponents(t *testing.T) { 16 t.Run("AllTools", testAllTools) 17 t.Run("AgentExecution", testAgentExecution) 18 t.Run("RAGFunctionality", testRAGFunctionality) 19 t.Run("MemorySystem", testMemorySystem) 20 } 21 22 func testAllTools(t *testing.T) { 23 allTools := tools.GetAll() 24 25 if len(allTools) == 0 { 26 t.Fatal("No tools found") 27 } 28 29 t.Logf("Found %d tools", len(allTools)) 30 31 // Test each tool type 32 toolTypes := map[string]bool{ 33 "file_read": false, "file_write": false, "list_directory": false, "file_append": false, 34 "shell_execute": false, "get_current_directory": false, "change_directory": false, 35 "git_status": false, "git_add": false, "git_commit": false, 36 } 37 38 for _, tool := range allTools { 39 name := tool.Name() 40 if _, exists := toolTypes[name]; exists { 41 toolTypes[name] = true 42 } 43 t.Logf("✅ Tool: %s - %s", name, tool.Description()) 44 } 45 46 // Check critical tools are present 47 missing := []string{} 48 for toolName, found := range toolTypes { 49 if !found { 50 missing = append(missing, toolName) 51 } 52 } 53 54 if len(missing) > 0 { 55 t.Errorf("Missing critical tools: %v", missing) 56 } 57 58 // Test file operations 59 t.Run("FileOperations", func(t *testing.T) { 60 tmpFile := createTempFile(t, "test content for tools") 61 defer os.Remove(tmpFile) 62 63 // Test file read 64 readTool := tools.FileReadTool{} 65 content, err := readTool.Call(context.Background(), tmpFile) 66 if err != nil { 67 t.Fatalf("FileReadTool failed: %v", err) 68 } 69 if content != "test content for tools" { 70 t.Errorf("Expected 'test content for tools', got '%s'", content) 71 } 72 73 // Test file write 74 writeTool := tools.FileWriteTool{} 75 writeInput := tmpFile + ".new|new content" 76 result, err := writeTool.Call(context.Background(), writeInput) 77 if err != nil { 78 t.Fatalf("FileWriteTool failed: %v", err) 79 } 80 if !strings.Contains(result, "Successfully wrote") { 81 t.Errorf("Unexpected write result: %s", result) 82 } 83 defer os.Remove(tmpFile + ".new") 84 }) 85 86 // Test shell operations 87 t.Run("ShellOperations", func(t *testing.T) { 88 shellTool := tools.ShellExecuteTool{} 89 result, err := shellTool.Call(context.Background(), "echo 'shell test'") 90 if err != nil { 91 t.Fatalf("ShellExecuteTool failed: %v", err) 92 } 93 if !strings.Contains(result, "shell test") { 94 t.Errorf("Expected 'shell test' in output, got: %s", result) 95 } 96 97 // Test directory operations 98 dirTool := tools.GetCurrentDirectoryTool{} 99 dir, err := dirTool.Call(context.Background(), "") 100 if err != nil { 101 t.Fatalf("GetCurrentDirectoryTool failed: %v", err) 102 } 103 if dir == "" { 104 t.Error("Current directory should not be empty") 105 } 106 }) 107 } 108 109 func testAgentExecution(t *testing.T) { 110 // Create mock LLM 111 llm := providers.NewMockProvider("http://test", "test-model") 112 113 // Get tools 114 allTools := tools.GetAll() 115 if len(allTools) == 0 { 116 t.Skip("No tools available for agent test") 117 } 118 119 // Create agent 120 agent := agents.NewBasicAgentExecutor(llm, allTools, true) 121 if agent == nil { 122 t.Fatal("Failed to create agent") 123 } 124 125 // Test agent status 126 status := agent.GetStatus() 127 if status.Status != "ready" { 128 t.Errorf("Expected agent status 'ready', got '%s'", status.Status) 129 } 130 131 // Test agent execution 132 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 133 defer cancel() 134 135 result, err := agent.Execute(ctx, "List the current directory") 136 if err != nil { 137 t.Fatalf("Agent execution failed: %v", err) 138 } 139 140 if result == "" { 141 t.Error("Agent returned empty result") 142 } 143 144 t.Logf("Agent result: %s", result) 145 146 // Verify agent used tools 147 newStatus := agent.GetStatus() 148 if newStatus.TasksRun == 0 { 149 t.Error("Agent should have executed at least one task") 150 } 151 152 // Test agent tools access 153 agentTools := agent.GetTools() 154 if len(agentTools) != len(allTools) { 155 t.Errorf("Agent should have %d tools, got %d", len(allTools), len(agentTools)) 156 } 157 } 158 159 func testRAGFunctionality(t *testing.T) { 160 // Create test documents 161 doc1 := createTempFile(t, "This is document 1 about Go programming and testing.") 162 doc2 := createTempFile(t, "This is document 2 about AI agents and tools.") 163 defer os.Remove(doc1) 164 defer os.Remove(doc2) 165 166 // Test RAG via CLI (simulate) 167 llm := providers.NewMockProvider("http://test", "test-model") 168 169 // Build RAG context (simulate what enhance command does) 170 content1, _ := os.ReadFile(doc1) 171 content2, _ := os.ReadFile(doc2) 172 173 ragContext := "Document 1:\n" + string(content1) + "\n\nDocument 2:\n" + string(content2) 174 175 if len(ragContext) == 0 { 176 t.Fatal("RAG context is empty") 177 } 178 179 // Test RAG query 180 query := "What do these documents discuss?" 181 prompt := "Based on the following documents, answer: " + query + "\n\nDocuments:\n" + ragContext 182 183 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 184 defer cancel() 185 186 response, err := llm.Call(ctx, prompt) 187 if err != nil { 188 t.Fatalf("RAG query failed: %v", err) 189 } 190 191 if response == "" { 192 t.Error("RAG response is empty") 193 } 194 195 if !strings.Contains(response, "test prompt") { 196 t.Error("RAG response should reference the prompt") 197 } 198 199 t.Logf("RAG response: %s", response) 200 } 201 202 func testMemorySystem(t *testing.T) { 203 // Test conversation memory (basic implementation) 204 conversationHistory := []string{} 205 206 // Simulate conversation 207 conversationHistory = append(conversationHistory, "Human: What is Go?") 208 conversationHistory = append(conversationHistory, "Assistant: Go is a programming language.") 209 conversationHistory = append(conversationHistory, "Human: Tell me more about it.") 210 211 if len(conversationHistory) != 3 { 212 t.Errorf("Expected 3 conversation entries, got %d", len(conversationHistory)) 213 } 214 215 // Test memory context building 216 context := strings.Join(conversationHistory, "\n") 217 if !strings.Contains(context, "Go is a programming language") { 218 t.Error("Memory context should contain previous responses") 219 } 220 221 // Test memory limits (simulate keeping last N exchanges) 222 maxEntries := 4 223 for len(conversationHistory) > maxEntries { 224 conversationHistory = conversationHistory[1:] 225 } 226 227 if len(conversationHistory) > maxEntries { 228 t.Errorf("Memory should be limited to %d entries, got %d", maxEntries, len(conversationHistory)) 229 } 230 231 t.Logf("Memory system working with %d entries", len(conversationHistory)) 232 } 233 234 func createTempFile(t *testing.T, content string) string { 235 tmpFile, err := os.CreateTemp("", "kamaji_test_*.txt") 236 if err != nil { 237 t.Fatalf("Failed to create temp file: %v", err) 238 } 239 240 if _, err := tmpFile.WriteString(content); err != nil { 241 t.Fatalf("Failed to write to temp file: %v", err) 242 } 243 244 tmpFile.Close() 245 return tmpFile.Name() 246 }