suite_test.go
1 package test 2 3 import ( 4 "context" 5 "os" 6 "testing" 7 "time" 8 9 "github.com/TransformerOS/kamaji-go/internal/agents" 10 "github.com/TransformerOS/kamaji-go/internal/config" 11 "github.com/TransformerOS/kamaji-go/internal/providers" 12 "github.com/TransformerOS/kamaji-go/internal/tools" 13 "github.com/TransformerOS/kamaji-go/internal/types" 14 ) 15 16 // TestSuite runs the complete Kamaji test suite 17 func TestSuite(t *testing.T) { 18 t.Run("Config", testConfig) 19 t.Run("Tools", testTools) 20 t.Run("Providers", testProviders) 21 t.Run("Agents", testAgents) 22 t.Run("Integration", testIntegration) 23 } 24 25 func testConfig(t *testing.T) { 26 t.Run("LoadDefault", func(t *testing.T) { 27 cfg, err := config.Load() 28 if err != nil { 29 t.Fatalf("Failed to load config: %v", err) 30 } 31 32 if cfg.Provider == "" { 33 t.Error("Provider should not be empty") 34 } 35 36 if cfg.Model == "" { 37 t.Error("Model should not be empty") 38 } 39 40 if cfg.Temperature < 0 || cfg.Temperature > 1 { 41 t.Errorf("Temperature should be 0-1, got %f", cfg.Temperature) 42 } 43 }) 44 45 t.Run("SaveLoad", func(t *testing.T) { 46 cfg := &config.Config{ 47 Provider: "test", 48 Model: "test-model", 49 BaseURL: "http://test", 50 Temperature: 0.5, 51 MaxTokens: 1000, 52 } 53 54 if err := config.Save(cfg); err != nil { 55 t.Fatalf("Failed to save config: %v", err) 56 } 57 58 loaded, err := config.Load() 59 if err != nil { 60 t.Fatalf("Failed to load saved config: %v", err) 61 } 62 63 if loaded.Provider != cfg.Provider { 64 t.Errorf("Expected provider %s, got %s", cfg.Provider, loaded.Provider) 65 } 66 }) 67 } 68 69 func testTools(t *testing.T) { 70 allTools := tools.GetAll() 71 72 t.Run("ToolsAvailable", func(t *testing.T) { 73 if len(allTools) == 0 { 74 t.Fatal("No tools available") 75 } 76 77 expectedTools := []string{ 78 "file_read", "file_write", "list_directory", "file_append", 79 "shell_execute", "get_current_directory", "change_directory", 80 "git_status", "git_add", "git_commit", "git_diff", "git_log", 81 } 82 83 toolMap := make(map[string]bool) 84 for _, tool := range allTools { 85 toolMap[tool.Name()] = true 86 } 87 88 for _, expected := range expectedTools { 89 if !toolMap[expected] { 90 t.Errorf("Expected tool %s not found", expected) 91 } 92 } 93 }) 94 95 t.Run("ToolInterface", func(t *testing.T) { 96 for _, tool := range allTools { 97 if tool.Name() == "" { 98 t.Errorf("Tool %T has empty name", tool) 99 } 100 101 if tool.Description() == "" { 102 t.Errorf("Tool %s has empty description", tool.Name()) 103 } 104 } 105 }) 106 107 t.Run("FileReadTool", func(t *testing.T) { 108 tmpFile := createTempFile(t, "test content") 109 defer os.Remove(tmpFile) 110 111 tool := tools.FileReadTool{} 112 result, err := tool.Call(context.Background(), tmpFile) 113 if err != nil { 114 t.Fatalf("FileReadTool failed: %v", err) 115 } 116 117 if result != "test content" { 118 t.Errorf("Expected 'test content', got '%s'", result) 119 } 120 }) 121 122 t.Run("ShellExecuteTool", func(t *testing.T) { 123 tool := tools.ShellExecuteTool{} 124 result, err := tool.Call(context.Background(), "echo hello") 125 if err != nil { 126 t.Fatalf("ShellExecuteTool failed: %v", err) 127 } 128 129 if !strings.Contains(result, "hello") { 130 t.Errorf("Expected output to contain 'hello', got '%s'", result) 131 } 132 }) 133 } 134 135 func testProviders(t *testing.T) { 136 t.Run("MockProvider", func(t *testing.T) { 137 provider := providers.NewMockProvider("http://test", "test-model") 138 139 result, err := provider.Call(context.Background(), "test prompt") 140 if err != nil { 141 t.Fatalf("Mock provider failed: %v", err) 142 } 143 144 if !strings.Contains(result, "test prompt") { 145 t.Errorf("Expected response to contain prompt, got '%s'", result) 146 } 147 }) 148 149 t.Run("GetLLM", func(t *testing.T) { 150 // This will use mock provider since no real providers are configured 151 llm, err := providers.GetLLM(providers.LLMOptions{}) 152 if err != nil { 153 t.Fatalf("Failed to get LLM: %v", err) 154 } 155 156 if llm == nil { 157 t.Fatal("LLM is nil") 158 } 159 }) 160 } 161 162 func testAgents(t *testing.T) { 163 t.Run("BasicAgentExecutor", func(t *testing.T) { 164 llm := providers.NewMockProvider("http://test", "test-model") 165 availableTools := []tools.Tool{tools.FileReadTool{}} 166 167 agent := agents.NewBasicAgentExecutor(llm, availableTools, false) 168 if agent == nil { 169 t.Fatal("Agent is nil") 170 } 171 172 status := agent.GetStatus() 173 if status.Status != "ready" { 174 t.Errorf("Expected status 'ready', got '%s'", status.Status) 175 } 176 177 agentTools := agent.GetTools() 178 if len(agentTools) != 1 { 179 t.Errorf("Expected 1 tool, got %d", len(agentTools)) 180 } 181 }) 182 183 t.Run("AgentExecution", func(t *testing.T) { 184 llm := providers.NewMockProvider("http://test", "test-model") 185 availableTools := []tools.Tool{} 186 187 agent := agents.NewBasicAgentExecutor(llm, availableTools, false) 188 189 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 190 defer cancel() 191 192 result, err := agent.Execute(ctx, "test task") 193 if err != nil { 194 t.Fatalf("Agent execution failed: %v", err) 195 } 196 197 if result == "" { 198 t.Error("Agent returned empty result") 199 } 200 201 status := agent.GetStatus() 202 if status.TasksRun != 1 { 203 t.Errorf("Expected 1 task run, got %d", status.TasksRun) 204 } 205 }) 206 } 207 208 func testIntegration(t *testing.T) { 209 t.Run("FullWorkflow", func(t *testing.T) { 210 // Create temp file 211 tmpFile := createTempFile(t, "integration test content") 212 defer os.Remove(tmpFile) 213 214 // Get LLM and tools 215 llm, err := providers.GetLLM(providers.LLMOptions{}) 216 if err != nil { 217 t.Fatalf("Failed to get LLM: %v", err) 218 } 219 220 allTools := tools.GetAll() 221 if len(allTools) == 0 { 222 t.Fatal("No tools available for integration test") 223 } 224 225 // Create agent 226 agent := agents.NewBasicAgentExecutor(llm, allTools, false) 227 228 // Execute task 229 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 230 defer cancel() 231 232 task := "List the current directory" 233 result, err := agent.Execute(ctx, task) 234 if err != nil { 235 t.Fatalf("Integration test failed: %v", err) 236 } 237 238 if result == "" { 239 t.Error("Integration test returned empty result") 240 } 241 242 // Verify agent status 243 status := agent.GetStatus() 244 if status.TasksRun == 0 { 245 t.Error("No tasks were executed") 246 } 247 }) 248 } 249 250 // Helper functions 251 func createTempFile(t *testing.T, content string) string { 252 tmpFile, err := os.CreateTemp("", "kamaji_test_*.txt") 253 if err != nil { 254 t.Fatalf("Failed to create temp file: %v", err) 255 } 256 257 if _, err := tmpFile.WriteString(content); err != nil { 258 t.Fatalf("Failed to write to temp file: %v", err) 259 } 260 261 tmpFile.Close() 262 return tmpFile.Name() 263 } 264 265 // Benchmark tests 266 func BenchmarkToolExecution(b *testing.B) { 267 tool := tools.ShellExecuteTool{} 268 ctx := context.Background() 269 270 b.ResetTimer() 271 for i := 0; i < b.N; i++ { 272 _, err := tool.Call(ctx, "echo test") 273 if err != nil { 274 b.Fatalf("Tool execution failed: %v", err) 275 } 276 } 277 } 278 279 func BenchmarkAgentExecution(b *testing.B) { 280 llm := providers.NewMockProvider("http://test", "test-model") 281 tools := []tools.Tool{tools.ShellExecuteTool{}} 282 agent := agents.NewBasicAgentExecutor(llm, tools, false) 283 284 b.ResetTimer() 285 for i := 0; i < b.N; i++ { 286 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 287 _, err := agent.Execute(ctx, "test task") 288 cancel() 289 if err != nil { 290 b.Fatalf("Agent execution failed: %v", err) 291 } 292 } 293 }