/ go / test / comprehensive_test.go
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  }