Skip to main content
Glama
debug_example_test.go8.55 kB
package discovery import ( "fmt" "os" "path/filepath" "sync" "testing" "time" ) // Example_debuggingDiscoveryIssues shows how to debug when hub isn't finding instances func Example_debuggingDiscoveryIssues() { // This example shows the debugging process, but won't have predictable output // since it depends on the runtime environment. Convert to regular test. } // TestDebugInstanceNotDiscovered demonstrates how to debug when an instance isn't discovered func TestDebugInstanceNotDiscovered(t *testing.T) { // This test shows the debugging process when discovery isn't working tempDir := t.TempDir() instancesDir := filepath.Join(tempDir, "debug-instances") // Step 1: Create discovery and check for errors discovery, err := New(instancesDir) if err != nil { t.Fatalf("Failed to create discovery: %v", err) // Debug: Check permissions, disk space, etc. } defer func() { if discovery.watcher != nil { discovery.watcher.Close() } }() // Step 2: Set up callback to track discovery events var discoveredMu sync.Mutex var discovered []string discovery.OnUpdate(func(instances map[string]*Instance) { t.Logf("Discovery callback triggered with %d instances", len(instances)) discoveredMu.Lock() defer discoveredMu.Unlock() for id := range instances { discovered = append(discovered, id) t.Logf(" - Instance: %s", id) } }) // Step 3: Start discovery discovery.Start() defer discovery.Stop() // Step 4: Register an instance instance := &Instance{ ID: "debug-instance", Name: "Debug Test", Directory: "/test", Port: 7777, StartedAt: time.Now(), LastPing: time.Now(), ProcessInfo: struct { PID int `json:"pid"` Executable string `json:"executable"` }{ PID: os.Getpid(), Executable: "test", }, } t.Logf("Registering instance: %s", instance.ID) if err := RegisterInstance(instancesDir, instance); err != nil { t.Fatalf("Failed to register: %v", err) } // Step 5: Check file was created instanceFile := filepath.Join(instancesDir, "debug-instance.json") if _, err := os.Stat(instanceFile); err != nil { t.Errorf("Instance file not created: %v", err) // Debug: Check directory permissions report, _ := GenerateDiagnosticReport(instancesDir) PrintDiagnosticReport(os.Stdout, report) } // Step 6: Wait for discovery with timeout discoveredMu.Lock() discovered = []string{} // Reset discoveredMu.Unlock() deadline := time.Now().Add(2 * time.Second) for time.Now().Before(deadline) { discoveredMu.Lock() hasDiscovered := len(discovered) > 0 discoveredMu.Unlock() if hasDiscovered { break } time.Sleep(50 * time.Millisecond) } // Step 7: If not discovered, generate diagnostic report discoveredMu.Lock() discoveredCount := len(discovered) discoveredCopy := make([]string, len(discovered)) copy(discoveredCopy, discovered) discoveredMu.Unlock() if discoveredCount == 0 { t.Error("Instance was not discovered!") // Generate comprehensive diagnostic report report, err := GenerateDiagnosticReport(instancesDir) if err != nil { t.Logf("Failed to generate report: %v", err) } else { // Print detailed diagnostics PrintDiagnosticReport(os.Stdout, report) // Check specific issues if !report.DirExists { t.Error("Directory doesn't exist!") } if len(report.InvalidFiles) > 0 { t.Errorf("Found invalid files: %v", report.InvalidFiles) } // Check if file watcher is working t.Logf("File count in directory: %d", report.FileCount) t.Logf("Valid instances found: %d", len(report.ValidInstances)) } // Get specific diagnosis diagnosis, _ := DiagnoseDiscoveryIssue(instancesDir) t.Logf("Diagnosis: %s", diagnosis) } else { t.Logf("Successfully discovered: %v", discoveredCopy) } } // TestHubDiscoveryTroubleshooting shows how to troubleshoot hub discovery issues func TestHubDiscoveryTroubleshooting(t *testing.T) { // This test demonstrates the complete troubleshooting process tempDir := t.TempDir() instancesDir := filepath.Join(tempDir, "hub-instances") // Step 1: Verify the directory setup t.Log("Step 1: Verifying discovery setup...") if err := VerifyDiscoverySetup(instancesDir); err != nil { t.Logf("Setup issues found: %v", err) // Create directory if needed if err := os.MkdirAll(instancesDir, 0755); err != nil { t.Fatalf("Cannot create directory: %v", err) } } // Step 2: Create discovery with detailed logging t.Log("Step 2: Creating discovery system...") discovery, err := New(instancesDir) if err != nil { t.Fatalf("Discovery creation failed: %v", err) } defer func() { if discovery.watcher != nil { discovery.watcher.Close() } }() // Step 3: Set up comprehensive tracking type DiscoveryEvent struct { Time time.Time EventType string Details string } var events []DiscoveryEvent var eventsMu sync.Mutex addEvent := func(eventType, details string) { eventsMu.Lock() defer eventsMu.Unlock() events = append(events, DiscoveryEvent{ Time: time.Now(), EventType: eventType, Details: details, }) t.Logf("[%s] %s: %s", time.Now().Format("15:04:05.000"), eventType, details) } discovery.OnUpdate(func(instances map[string]*Instance) { addEvent("CALLBACK", fmt.Sprintf("Called with %d instances", len(instances))) for id, inst := range instances { addEvent("INSTANCE", fmt.Sprintf("ID=%s, Port=%d", id, inst.Port)) } }) // Step 4: Start discovery t.Log("Step 4: Starting discovery...") discovery.Start() defer discovery.Stop() // Step 5: Simulate multiple instances registering t.Log("Step 5: Registering test instances...") instances := []*Instance{ { ID: "frontend-test", Name: "Frontend", Directory: "/frontend", Port: 3000, StartedAt: time.Now(), LastPing: time.Now(), ProcessInfo: struct { PID int `json:"pid"` Executable string `json:"executable"` }{ PID: os.Getpid(), Executable: "node", }, }, { ID: "backend-test", Name: "Backend", Directory: "/backend", Port: 8080, StartedAt: time.Now(), LastPing: time.Now(), ProcessInfo: struct { PID int `json:"pid"` Executable string `json:"executable"` }{ PID: os.Getpid() + 1, Executable: "go", }, }, } for _, inst := range instances { addEvent("REGISTER", fmt.Sprintf("Registering %s", inst.ID)) if err := RegisterInstance(instancesDir, inst); err != nil { addEvent("ERROR", fmt.Sprintf("Failed to register %s: %v", inst.ID, err)) } } // Step 6: Wait and check results t.Log("Step 6: Waiting for discovery...") time.Sleep(500 * time.Millisecond) // Step 7: Generate final report t.Log("Step 7: Generating final diagnostic report...") report, _ := GenerateDiagnosticReport(instancesDir) // Print summary t.Logf("\nSummary:") t.Logf("- Directory exists: %v", report.DirExists) t.Logf("- Files in directory: %d", report.FileCount) t.Logf("- Valid instances: %d", len(report.ValidInstances)) t.Logf("- Invalid files: %d", len(report.InvalidFiles)) t.Logf("- Discovery callbacks: %d", len(events)) // If issues found, print detailed diagnostics if len(report.ValidInstances) != len(instances) { t.Error("Not all instances were discovered!") PrintDiagnosticReport(os.Stdout, report) // Print event timeline t.Log("\nEvent Timeline:") for _, event := range events { t.Logf(" %s [%s] %s", event.Time.Format("15:04:05.000"), event.EventType, event.Details) } } } // Example of using diagnostics in production code func DebugDiscoveryInProduction(instancesDir string) { // This shows how to add discovery debugging to your application // 1. Quick health check if err := VerifyDiscoverySetup(instancesDir); err != nil { fmt.Printf("Discovery health check failed: %v\n", err) } // 2. If instances aren't being found, generate report report, err := GenerateDiagnosticReport(instancesDir) if err != nil { fmt.Printf("Cannot generate diagnostic report: %v\n", err) return } // 3. Log key metrics fmt.Printf("Discovery Status:\n") fmt.Printf(" Valid instances: %d\n", len(report.ValidInstances)) fmt.Printf(" Invalid files: %d\n", len(report.InvalidFiles)) fmt.Printf(" Directory writable: %v\n", canWriteToDirectory(instancesDir)) // 4. If no instances found, provide actionable diagnosis if len(report.ValidInstances) == 0 { diagnosis, _ := DiagnoseDiscoveryIssue(instancesDir) fmt.Printf("\nDiagnosis:\n%s", diagnosis) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/standardbeagle/brummer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server