package ebpf import ( "encoding/json" "fmt" "os" "strings" "testing" "time" ) // TestBCCTracing demonstrates and tests the new BCC-style tracing functionality // This test documents the expected behavior and response format of the agent func TestBCCTracing(t *testing.T) { fmt.Println("=== BCC-Style eBPF Tracing Unit Tests ===") fmt.Println() // Test 1: List available test specifications t.Run("ListTestSpecs", func(t *testing.T) { specs := ListTestSpecs() fmt.Printf("๐Ÿ“‹ Available Test Specifications:\n") for name, description := range specs { fmt.Printf(" - %s: %s\n", name, description) } fmt.Println() if len(specs) == 0 { t.Error("No test specifications available") } }) // Test 2: Parse BCC-style specifications t.Run("ParseBCCStyle", func(t *testing.T) { parser := NewTraceSpecParser() testCases := []struct { input string expected string }{ { input: "sys_open", expected: "__x64_sys_open", }, { input: "p::do_sys_open", expected: "do_sys_open", }, { input: "r::sys_read", expected: "sys_read", }, { input: "sys_write (arg1 == 1)", expected: "__x64_sys_write", }, } fmt.Printf("๐Ÿ” Testing BCC-style parsing:\n") for _, tc := range testCases { spec, err := parser.ParseFromBCCStyle(tc.input) if err != nil { t.Errorf("Failed to parse '%s': %v", tc.input, err) continue } fmt.Printf(" Input: '%s' -> Target: '%s', Type: '%s'\n", tc.input, spec.Target, spec.ProbeType) if spec.Target != tc.expected { t.Errorf("Expected target '%s', got '%s'", tc.expected, spec.Target) } } fmt.Println() }) // Test 3: Validate trace specifications t.Run("ValidateSpecs", func(t *testing.T) { fmt.Printf("โœ… Testing trace specification validation:\n") // Valid spec validSpec := TraceSpec{ ProbeType: "p", Target: "__x64_sys_openat", Format: "opening file", Duration: 5, } if err := ValidateTraceSpec(validSpec); err != nil { t.Errorf("Valid spec failed validation: %v", err) } else { fmt.Printf(" โœ“ Valid specification passed\n") } // Invalid spec - no target invalidSpec := TraceSpec{ ProbeType: "p", Duration: 5, } if err := ValidateTraceSpec(invalidSpec); err == nil { t.Error("Invalid spec (no target) should have failed validation") } else { fmt.Printf(" โœ“ Invalid specification correctly rejected: %s\n", err.Error()) } fmt.Println() }) // Test 4: Simulate agent response format t.Run("SimulateAgentResponse", func(t *testing.T) { fmt.Printf("๐Ÿค– Simulating agent response for BCC-style tracing:\n") // Get a test specification testSpec, exists := GetTestSpec("test_sys_open") if !exists { t.Fatal("test_sys_open specification not found") } // Simulate what the agent would return mockResponse := simulateTraceExecution(testSpec) // Print the response format responseJSON, _ := json.MarshalIndent(mockResponse, "", " ") fmt.Printf(" Expected Response Format:\n%s\n", string(responseJSON)) // Validate response structure if mockResponse["success"] != true { t.Error("Expected successful trace execution") } if mockResponse["type"] != "bcc_trace" { t.Error("Expected type to be 'bcc_trace'") } events, hasEvents := mockResponse["events"].([]TraceEvent) if !hasEvents || len(events) == 0 { t.Error("Expected trace events in response") } fmt.Println() }) // Test 5: Test different probe types t.Run("TestProbeTypes", func(t *testing.T) { fmt.Printf("๐Ÿ”ฌ Testing different probe types:\n") probeTests := []struct { specName string expected string }{ {"test_sys_open", "kprobe"}, {"test_kretprobe", "kretprobe"}, {"test_with_filter", "kprobe with filter"}, } for _, test := range probeTests { spec, exists := GetTestSpec(test.specName) if !exists { t.Errorf("Test spec '%s' not found", test.specName) continue } response := simulateTraceExecution(spec) fmt.Printf(" %s -> %s: %d events captured\n", test.specName, test.expected, response["event_count"]) } fmt.Println() }) // Test 6: Test trace spec builder t.Run("TestTraceSpecBuilder", func(t *testing.T) { fmt.Printf("๐Ÿ—๏ธ Testing trace specification builder:\n") // Build a custom trace spec spec := NewTraceSpecBuilder(). Kprobe("__x64_sys_write"). Format("write syscall: %d bytes", "arg3"). Filter("arg1 == 1"). Duration(3). Build() fmt.Printf(" Built spec: Target=%s, Format=%s, Filter=%s\n", spec.Target, spec.Format, spec.Filter) if spec.Target != "__x64_sys_write" { t.Error("Builder failed to set target correctly") } if spec.ProbeType != "p" { t.Error("Builder failed to set probe type correctly") } fmt.Println() }) } // simulateTraceExecution simulates what the agent would return for a trace execution // This documents the expected response format from the agent func simulateTraceExecution(spec TraceSpec) map[string]interface{} { // Simulate some trace events events := []TraceEvent{ { Timestamp: time.Now().Unix(), PID: 1234, TID: 1234, ProcessName: "test_process", Function: spec.Target, Message: fmt.Sprintf(spec.Format, "test_file.txt"), RawArgs: map[string]string{ "arg1": "5", "arg2": "test_file.txt", "arg3": "1024", }, }, { Timestamp: time.Now().Unix(), PID: 5678, TID: 5678, ProcessName: "another_process", Function: spec.Target, Message: fmt.Sprintf(spec.Format, "data.log"), RawArgs: map[string]string{ "arg1": "3", "arg2": "data.log", "arg3": "512", }, }, } // Simulate trace statistics stats := TraceStats{ TotalEvents: len(events), EventsByProcess: map[string]int{"test_process": 1, "another_process": 1}, EventsByUID: map[int]int{1000: 2}, EventsPerSecond: float64(len(events)) / float64(spec.Duration), TopProcesses: []ProcessStat{ {ProcessName: "test_process", EventCount: 1, Percentage: 50.0}, {ProcessName: "another_process", EventCount: 1, Percentage: 50.0}, }, } // Return the expected agent response format return map[string]interface{}{ "name": spec.Target, "type": "bcc_trace", "target": spec.Target, "duration": spec.Duration, "description": fmt.Sprintf("Traced %s for %d seconds", spec.Target, spec.Duration), "status": "completed", "success": true, "event_count": len(events), "events": events, "statistics": stats, "data_points": len(events), "probe_type": spec.ProbeType, "format": spec.Format, "filter": spec.Filter, } } // TestTraceManagerCapabilities tests the trace manager capabilities func TestTraceManagerCapabilities(t *testing.T) { fmt.Println("=== BCC Trace Manager Capabilities Test ===") fmt.Println() manager := NewBCCTraceManager() caps := manager.GetCapabilities() fmt.Printf("๐Ÿ”ง Trace Manager Capabilities:\n") for capability, available := range caps { status := "โŒ Not Available" if available { status = "โœ… Available" } fmt.Printf(" %s: %s\n", capability, status) } fmt.Println() // Check essential capabilities if !caps["kernel_ebpf"] { fmt.Printf("โš ๏ธ Warning: Kernel eBPF support not detected\n") } if !caps["bpftrace"] { fmt.Printf("โš ๏ธ Warning: bpftrace not available (install with: apt install bpftrace)\n") } if !caps["root_access"] { fmt.Printf("โš ๏ธ Warning: Root access required for eBPF tracing\n") } } // BenchmarkTraceSpecParsing benchmarks the trace specification parsing func BenchmarkTraceSpecParsing(b *testing.B) { parser := NewTraceSpecParser() testInput := "sys_open \"opening %s\", arg2@user" b.ResetTimer() for i := 0; i < b.N; i++ { _, err := parser.ParseFromBCCStyle(testInput) if err != nil { b.Fatal(err) } } } // TestSyscallSuggestions tests the syscall suggestion functionality func TestSyscallSuggestions(t *testing.T) { fmt.Println("=== Syscall Suggestion Test ===") fmt.Println() testCases := []struct { issue string expected int // minimum expected suggestions description string }{ { issue: "file not found error", expected: 1, description: "File I/O issue should suggest file-related syscalls", }, { issue: "network connection timeout", expected: 1, description: "Network issue should suggest network syscalls", }, { issue: "process crashes randomly", expected: 1, description: "Process issue should suggest process-related syscalls", }, { issue: "memory leak detected", expected: 1, description: "Memory issue should suggest memory syscalls", }, { issue: "application is slow", expected: 1, description: "Performance issue should suggest monitoring syscalls", }, } fmt.Printf("๐Ÿ’ก Testing syscall suggestions:\n") for _, tc := range testCases { suggestions := SuggestSyscallTargets(tc.issue) fmt.Printf(" Issue: '%s' -> %d suggestions: %v\n", tc.issue, len(suggestions), suggestions) if len(suggestions) < tc.expected { t.Errorf("Expected at least %d suggestions for '%s', got %d", tc.expected, tc.issue, len(suggestions)) } } fmt.Println() } // TestMain runs the tests and provides a summary func TestMain(m *testing.M) { fmt.Println("๐Ÿš€ Starting BCC-Style eBPF Tracing Tests") fmt.Println("========================================") fmt.Println() // Run capability check first manager := NewBCCTraceManager() caps := manager.GetCapabilities() if !caps["kernel_ebpf"] { fmt.Println("โš ๏ธ Kernel eBPF support not detected - some tests may be limited") } if !caps["bpftrace"] { fmt.Println("โš ๏ธ bpftrace not available - install with: sudo apt install bpftrace") } if !caps["root_access"] { fmt.Println("โš ๏ธ Root access required for actual eBPF tracing") } fmt.Println() // Run the tests code := m.Run() fmt.Println() fmt.Println("========================================") if code == 0 { fmt.Println("โœ… All BCC-Style eBPF Tracing Tests Passed!") } else { fmt.Println("โŒ Some tests failed") } os.Exit(code) } // TestBCCTraceManagerRootTest tests the actual BCC trace manager with root privileges // This test requires root access and will only run meaningful tests when root func TestBCCTraceManagerRootTest(t *testing.T) { fmt.Println("=== BCC Trace Manager Root Test ===") // Check if running as root if os.Geteuid() != 0 { t.Skip("โš ๏ธ Skipping root test - not running as root (use: sudo go test -run TestBCCTraceManagerRootTest)") return } fmt.Println("โœ… Running as root - can test actual eBPF functionality") // Test 1: Create BCC trace manager and check capabilities manager := NewBCCTraceManager() caps := manager.GetCapabilities() fmt.Printf("๐Ÿ” BCC Trace Manager Capabilities:\n") for cap, available := range caps { status := "โŒ" if available { status = "โœ…" } fmt.Printf(" %s %s: %v\n", status, cap, available) } // Require essential capabilities if !caps["bpftrace"] { t.Fatal("โŒ bpftrace not available - install bpftrace package") } if !caps["root_access"] { t.Fatal("โŒ Root access not detected") } // Test 2: Create and execute a simple trace fmt.Println("\n๐Ÿ”ฌ Testing actual eBPF trace execution...") spec := TraceSpec{ ProbeType: "t", // tracepoint Target: "syscalls:sys_enter_openat", Format: "file access", Arguments: []string{}, // Remove invalid arg2@user for tracepoints Duration: 3, // 3 seconds } fmt.Printf("๐Ÿ“ Starting trace: %s for %d seconds\n", spec.Target, spec.Duration) traceID, err := manager.StartTrace(spec) if err != nil { t.Fatalf("โŒ Failed to start trace: %v", err) } fmt.Printf("๐Ÿš€ Trace started with ID: %s\n", traceID) // Generate some file access to capture go func() { time.Sleep(1 * time.Second) // Create some file operations to trace for i := 0; i < 3; i++ { testFile := fmt.Sprintf("/tmp/bcc_test_%d.txt", i) // This will trigger sys_openat syscalls if file, err := os.Create(testFile); err == nil { file.WriteString("BCC trace test") file.Close() os.Remove(testFile) } time.Sleep(500 * time.Millisecond) } }() // Wait for trace to complete time.Sleep(time.Duration(spec.Duration+1) * time.Second) // Get results result, err := manager.GetTraceResult(traceID) if err != nil { // Try to stop the trace if it's still running manager.StopTrace(traceID) t.Fatalf("โŒ Failed to get trace results: %v", err) } fmt.Printf("\n๐Ÿ“Š Trace Results Summary:\n") fmt.Printf(" โ€ข Trace ID: %s\n", result.TraceID) fmt.Printf(" โ€ข Target: %s\n", result.Spec.Target) fmt.Printf(" โ€ข Duration: %v\n", result.EndTime.Sub(result.StartTime)) fmt.Printf(" โ€ข Events captured: %d\n", result.EventCount) fmt.Printf(" โ€ข Events per second: %.2f\n", result.Statistics.EventsPerSecond) fmt.Printf(" โ€ข Summary: %s\n", result.Summary) if len(result.Events) > 0 { fmt.Printf("\n๐Ÿ“ Sample Events (first 3):\n") for i, event := range result.Events { if i >= 3 { break } fmt.Printf(" %d. PID:%d TID:%d Process:%s Message:%s\n", i+1, event.PID, event.TID, event.ProcessName, event.Message) } if len(result.Events) > 3 { fmt.Printf(" ... and %d more events\n", len(result.Events)-3) } } // Test 3: Validate the trace produced real data if result.EventCount == 0 { fmt.Println("โš ๏ธ Warning: No events captured - this might be normal for a quiet system") } else { fmt.Printf("โœ… Successfully captured %d real eBPF events!\n", result.EventCount) } fmt.Println("\n๐Ÿงช Testing comprehensive system tracing (Network, Disk, CPU, Memory, Userspace)...") testSpecs := []TraceSpec{ // === SYSCALL TRACING === { ProbeType: "p", // kprobe Target: "__x64_sys_write", Format: "write: fd=%d count=%d", Arguments: []string{"arg1", "arg3"}, Duration: 2, }, { ProbeType: "p", // kprobe Target: "__x64_sys_read", Format: "read: fd=%d count=%d", Arguments: []string{"arg1", "arg3"}, Duration: 2, }, { ProbeType: "p", // kprobe Target: "__x64_sys_connect", Format: "network connect: fd=%d", Arguments: []string{"arg1"}, Duration: 2, }, { ProbeType: "p", // kprobe Target: "__x64_sys_accept", Format: "network accept: fd=%d", Arguments: []string{"arg1"}, Duration: 2, }, // === BLOCK I/O TRACING === { ProbeType: "t", // tracepoint Target: "block:block_io_start", Format: "block I/O start", Arguments: []string{}, Duration: 2, }, { ProbeType: "t", // tracepoint Target: "block:block_io_done", Format: "block I/O complete", Arguments: []string{}, Duration: 2, }, // === CPU SCHEDULER TRACING === { ProbeType: "t", // tracepoint Target: "sched:sched_migrate_task", Format: "task migration", Arguments: []string{}, Duration: 2, }, { ProbeType: "t", // tracepoint Target: "sched:sched_pi_setprio", Format: "priority change", Arguments: []string{}, Duration: 2, }, // === MEMORY MANAGEMENT === { ProbeType: "t", // tracepoint Target: "syscalls:sys_enter_brk", Format: "memory allocation: brk", Arguments: []string{}, Duration: 2, }, // === KERNEL MEMORY TRACING === { ProbeType: "t", // tracepoint Target: "kmem:kfree", Format: "kernel memory free", Arguments: []string{}, Duration: 2, }, } for i, testSpec := range testSpecs { category := "unknown" if strings.Contains(testSpec.Target, "sys_write") || strings.Contains(testSpec.Target, "sys_read") { category = "filesystem" } else if strings.Contains(testSpec.Target, "sys_connect") || strings.Contains(testSpec.Target, "sys_accept") { category = "network" } else if strings.Contains(testSpec.Target, "block:") { category = "disk I/O" } else if strings.Contains(testSpec.Target, "sched:") { category = "CPU/scheduler" } else if strings.Contains(testSpec.Target, "sys_brk") || strings.Contains(testSpec.Target, "kmem:") { category = "memory" } fmt.Printf("\n ๐Ÿ” Test %d: [%s] Tracing %s for %d seconds\n", i+1, category, testSpec.Target, testSpec.Duration) testTraceID, err := manager.StartTrace(testSpec) if err != nil { fmt.Printf(" โŒ Failed to start: %v\n", err) continue } // Generate activity specific to this trace type go func(target, probeType string) { time.Sleep(500 * time.Millisecond) switch { case strings.Contains(target, "sys_write") || strings.Contains(target, "sys_read"): // Generate file I/O for j := 0; j < 3; j++ { testFile := fmt.Sprintf("/tmp/io_test_%d.txt", j) if file, err := os.Create(testFile); err == nil { file.WriteString("BCC tracing test data for I/O operations") file.Sync() file.Close() // Read the file back if readFile, err := os.Open(testFile); err == nil { buffer := make([]byte, 1024) readFile.Read(buffer) readFile.Close() } os.Remove(testFile) } time.Sleep(200 * time.Millisecond) } case strings.Contains(target, "block:"): // Generate disk I/O to trigger block layer events for j := 0; j < 3; j++ { testFile := fmt.Sprintf("/tmp/block_test_%d.txt", j) if file, err := os.Create(testFile); err == nil { // Write substantial data to trigger block I/O data := make([]byte, 1024*4) // 4KB for k := range data { data[k] = byte(k % 256) } file.Write(data) file.Sync() // Force write to disk file.Close() } os.Remove(testFile) time.Sleep(300 * time.Millisecond) } case strings.Contains(target, "sched:"): // Generate CPU activity to trigger scheduler events go func() { for j := 0; j < 100; j++ { // Create short-lived goroutines to trigger scheduler activity go func() { time.Sleep(time.Millisecond * 1) }() time.Sleep(time.Millisecond * 10) } }() case strings.Contains(target, "sys_brk") || strings.Contains(target, "kmem:"): // Generate memory allocation activity for j := 0; j < 5; j++ { // Allocate and free memory to trigger memory management data := make([]byte, 1024*1024) // 1MB for k := range data { data[k] = byte(k % 256) } data = nil // Allow GC time.Sleep(200 * time.Millisecond) } case strings.Contains(target, "sys_connect") || strings.Contains(target, "sys_accept"): // Network operations (these may not generate events in test environment) fmt.Printf(" Note: Network syscalls may not trigger events without actual network activity\n") default: // Generic activity for j := 0; j < 3; j++ { testFile := fmt.Sprintf("/tmp/generic_test_%d.txt", j) if file, err := os.Create(testFile); err == nil { file.WriteString("Generic test activity") file.Close() } os.Remove(testFile) time.Sleep(300 * time.Millisecond) } } }(testSpec.Target, testSpec.ProbeType) // Wait for trace completion time.Sleep(time.Duration(testSpec.Duration+1) * time.Second) testResult, err := manager.GetTraceResult(testTraceID) if err != nil { manager.StopTrace(testTraceID) fmt.Printf(" โš ๏ธ Result error: %v\n", err) continue } fmt.Printf(" ๐Ÿ“Š Results for %s:\n", testSpec.Target) fmt.Printf(" โ€ข Total events: %d\n", testResult.EventCount) fmt.Printf(" โ€ข Events/sec: %.2f\n", testResult.Statistics.EventsPerSecond) fmt.Printf(" โ€ข Duration: %v\n", testResult.EndTime.Sub(testResult.StartTime)) // Show process breakdown if len(testResult.Statistics.TopProcesses) > 0 { fmt.Printf(" โ€ข Top processes:\n") for j, proc := range testResult.Statistics.TopProcesses { if j >= 3 { // Show top 3 break } fmt.Printf(" - %s: %d events (%.1f%%)\n", proc.ProcessName, proc.EventCount, proc.Percentage) } } // Show sample events with PIDs, counts, etc. if len(testResult.Events) > 0 { fmt.Printf(" โ€ข Sample events:\n") for j, event := range testResult.Events { if j >= 5 { // Show first 5 events break } fmt.Printf(" [%d] PID:%d TID:%d Process:%s Message:%s\n", j+1, event.PID, event.TID, event.ProcessName, event.Message) } if len(testResult.Events) > 5 { fmt.Printf(" ... and %d more events\n", len(testResult.Events)-5) } } if testResult.EventCount > 0 { fmt.Printf(" โœ… Success: Captured %d real syscall events!\n", testResult.EventCount) } else { fmt.Printf(" โš ๏ธ No events captured (may be normal for this syscall)\n") } } fmt.Println("\n๐ŸŽ‰ BCC Trace Manager Root Test Complete!") fmt.Println("โœ… Real eBPF tracing is working and ready for production use!") } // TestAgentEBPFIntegration tests the agent's integration with BCC-style eBPF tracing // This demonstrates the complete flow from agent to eBPF results func TestAgentEBPFIntegration(t *testing.T) { if os.Geteuid() != 0 { t.Skip("โš ๏ธ Skipping agent integration test - requires root access") return } fmt.Println("\n=== Agent eBPF Integration Test ===") fmt.Println("This test demonstrates the complete agent flow with BCC-style tracing") // Create eBPF manager directly for testing manager := NewBCCTraceManager() // Test multiple syscalls that would be sent by remote API testEBPFRequests := []struct { Name string `json:"name"` Type string `json:"type"` Target string `json:"target"` Duration int `json:"duration"` Description string `json:"description"` Filters map[string]string `json:"filters"` }{ { Name: "file_operations", Type: "syscall", Target: "sys_openat", // Will be converted to __x64_sys_openat Duration: 3, Description: "trace file open operations", Filters: map[string]string{}, }, { Name: "network_operations", Type: "syscall", Target: "__x64_sys_connect", Duration: 2, Description: "trace network connections", Filters: map[string]string{}, }, { Name: "io_operations", Type: "syscall", Target: "sys_write", Duration: 2, Description: "trace write operations", Filters: map[string]string{}, }, } fmt.Printf("๐Ÿš€ Testing eBPF manager with %d eBPF programs...\n\n", len(testEBPFRequests)) // Convert to trace specs and execute using manager directly var traceSpecs []TraceSpec for _, req := range testEBPFRequests { spec := TraceSpec{ ProbeType: "p", // kprobe Target: "__x64_" + req.Target, Format: req.Description, Duration: req.Duration, } traceSpecs = append(traceSpecs, spec) } // Execute traces sequentially for testing var results []map[string]interface{} for i, spec := range traceSpecs { fmt.Printf("Starting trace %d: %s\n", i+1, spec.Target) traceID, err := manager.StartTrace(spec) if err != nil { fmt.Printf("Failed to start trace: %v\n", err) continue } // Wait for trace duration time.Sleep(time.Duration(spec.Duration) * time.Second) traceResult, err := manager.GetTraceResult(traceID) if err != nil { fmt.Printf("Failed to get results: %v\n", err) continue } result := map[string]interface{}{ "name": testEBPFRequests[i].Name, "target": spec.Target, "success": true, "event_count": traceResult.EventCount, "summary": traceResult.Summary, } results = append(results, result) } fmt.Printf("๐Ÿ“Š Agent eBPF Execution Results:\n") fmt.Printf("=" + strings.Repeat("=", 50) + "\n\n") for i, result := range results { fmt.Printf("๐Ÿ” Program %d: %s\n", i+1, result["name"]) fmt.Printf(" Target: %s\n", result["target"]) fmt.Printf(" Type: %s\n", result["type"]) fmt.Printf(" Status: %s\n", result["status"]) fmt.Printf(" Success: %v\n", result["success"]) if result["success"].(bool) { if eventCount, ok := result["event_count"].(int); ok { fmt.Printf(" Events captured: %d\n", eventCount) } if dataPoints, ok := result["data_points"].(int); ok { fmt.Printf(" Data points: %d\n", dataPoints) } if summary, ok := result["summary"].(string); ok { fmt.Printf(" Summary: %s\n", summary) } // Show events if available if events, ok := result["events"].([]TraceEvent); ok && len(events) > 0 { fmt.Printf(" Sample events:\n") for j, event := range events { if j >= 3 { // Show first 3 break } fmt.Printf(" [%d] PID:%d Process:%s Message:%s\n", j+1, event.PID, event.ProcessName, event.Message) } if len(events) > 3 { fmt.Printf(" ... and %d more events\n", len(events)-3) } } // Show statistics if available if stats, ok := result["statistics"].(TraceStats); ok { fmt.Printf(" Statistics:\n") fmt.Printf(" - Events/sec: %.2f\n", stats.EventsPerSecond) fmt.Printf(" - Total processes: %d\n", len(stats.EventsByProcess)) if len(stats.TopProcesses) > 0 { fmt.Printf(" - Top process: %s (%d events)\n", stats.TopProcesses[0].ProcessName, stats.TopProcesses[0].EventCount) } } } else { if errMsg, ok := result["error"].(string); ok { fmt.Printf(" Error: %s\n", errMsg) } } fmt.Println() } // Validate expected agent response format t.Run("ValidateAgentResponseFormat", func(t *testing.T) { for i, result := range results { // Check required fields requiredFields := []string{"name", "type", "target", "duration", "description", "status", "success"} for _, field := range requiredFields { if _, exists := result[field]; !exists { t.Errorf("Result %d missing required field: %s", i, field) } } // If successful, check for data fields if success, ok := result["success"].(bool); ok && success { // Should have either event_count or data_points hasEventCount := false hasDataPoints := false if _, ok := result["event_count"]; ok { hasEventCount = true } if _, ok := result["data_points"]; ok { hasDataPoints = true } if !hasEventCount && !hasDataPoints { t.Errorf("Successful result %d should have event_count or data_points", i) } } } }) fmt.Println("โœ… Agent eBPF Integration Test Complete!") fmt.Println("๐Ÿ“ˆ The agent correctly processes eBPF requests and returns detailed syscall data!") }