Skip to main content
Glama
store_collapsed_test.go7.37 kB
package logs import ( "testing" "time" ) func TestLogCollapsing(t *testing.T) { store := NewStore(100, nil) defer store.Close() // Add some identical consecutive logs store.Add("proc1", "test", "This is a test message", false) time.Sleep(1 * time.Millisecond) // Small delay to ensure different timestamps store.Add("proc1", "test", "This is a test message", false) time.Sleep(1 * time.Millisecond) store.Add("proc1", "test", "This is a test message", false) // Add a different log store.Add("proc1", "test", "This is a different message", false) // Add more identical logs store.Add("proc1", "test", "Another repeated message", false) time.Sleep(1 * time.Millisecond) store.Add("proc1", "test", "Another repeated message", false) // Wait for async processing to complete time.Sleep(10 * time.Millisecond) // Get collapsed logs collapsed := store.GetAllCollapsed() // Should have 3 collapsed entries if len(collapsed) != 3 { t.Errorf("Expected 3 collapsed entries, got %d", len(collapsed)) } // First entry should be collapsed with count 3 if !collapsed[0].IsCollapsed { t.Error("First entry should be collapsed") } if collapsed[0].Count != 3 { t.Errorf("First entry should have count 3, got %d", collapsed[0].Count) } if collapsed[0].Content != "This is a test message" { t.Errorf("First entry content incorrect: %s", collapsed[0].Content) } // Second entry should not be collapsed (single occurrence) if collapsed[1].IsCollapsed { t.Error("Second entry should not be collapsed") } if collapsed[1].Count != 1 { t.Errorf("Second entry should have count 1, got %d", collapsed[1].Count) } if collapsed[1].Content != "This is a different message" { t.Errorf("Second entry content incorrect: %s", collapsed[1].Content) } // Third entry should be collapsed with count 2 if !collapsed[2].IsCollapsed { t.Error("Third entry should be collapsed") } if collapsed[2].Count != 2 { t.Errorf("Third entry should have count 2, got %d", collapsed[2].Count) } if collapsed[2].Content != "Another repeated message" { t.Errorf("Third entry content incorrect: %s", collapsed[2].Content) } } func TestLogCollapsingByProcess(t *testing.T) { store := NewStore(100, nil) defer store.Close() // Add logs from different processes store.Add("proc1", "test1", "Message A", false) store.Add("proc2", "test2", "Message A", false) // Same content, different process store.Add("proc1", "test1", "Message A", false) // Same as first // Wait for async processing to complete time.Sleep(10 * time.Millisecond) // Get collapsed logs for proc1 collapsed := store.GetByProcessCollapsed("proc1") // Should have 1 collapsed entry with count 2 if len(collapsed) != 1 { t.Errorf("Expected 1 collapsed entry for proc1, got %d", len(collapsed)) } if !collapsed[0].IsCollapsed { t.Error("Entry should be collapsed") } if collapsed[0].Count != 2 { t.Errorf("Entry should have count 2, got %d", collapsed[0].Count) } // Get collapsed logs for proc2 collapsed2 := store.GetByProcessCollapsed("proc2") // Should have 1 non-collapsed entry if len(collapsed2) != 1 { t.Errorf("Expected 1 entry for proc2, got %d", len(collapsed2)) } if collapsed2[0].IsCollapsed { t.Error("Entry should not be collapsed") } if collapsed2[0].Count != 1 { t.Errorf("Entry should have count 1, got %d", collapsed2[0].Count) } } func TestLogCollapsingWithDifferentLevels(t *testing.T) { store := NewStore(100, nil) defer store.Close() // Add identical content but one as error store.Add("proc1", "test", "Test message", false) store.Add("proc1", "test", "Test message", true) // Same content but error store.Add("proc1", "test", "Test message", false) // Wait for async processing to complete time.Sleep(10 * time.Millisecond) // Get collapsed logs collapsed := store.GetAllCollapsed() // Should have 3 collapsed entries (error and non-error are separate, so we get: non-error, error, non-error) if len(collapsed) != 3 { t.Errorf("Expected 3 collapsed entries, got %d", len(collapsed)) for i, entry := range collapsed { t.Logf("Entry %d: Content='%s', IsError=%v, Count=%d", i, entry.Content, entry.IsError, entry.Count) } return } // First should be single non-error if collapsed[0].IsCollapsed { t.Error("First entry should not be collapsed") } if collapsed[0].IsError { t.Error("First entry should not be error") } // Second should be single error if collapsed[1].IsCollapsed { t.Error("Second entry should not be collapsed") } if !collapsed[1].IsError { t.Error("Second entry should be error") } // Third should be single non-error (different from first because interrupted by error) if collapsed[2].IsCollapsed { t.Error("Third entry should not be collapsed") } if collapsed[2].IsError { t.Error("Third entry should not be error") } } func TestLogCollapsingTimestamps(t *testing.T) { store := NewStore(100, nil) defer store.Close() // Add logs with measurable time differences start := time.Now() store.Add("proc1", "test", "Repeated message", false) time.Sleep(2 * time.Millisecond) // Reduced delay middle := time.Now() store.Add("proc1", "test", "Repeated message", false) time.Sleep(2 * time.Millisecond) // Reduced delay end := time.Now() store.Add("proc1", "test", "Repeated message", false) // Get collapsed logs collapsed := store.GetAllCollapsed() if len(collapsed) != 1 { t.Errorf("Expected 1 collapsed entry, got %d", len(collapsed)) return } entry := collapsed[0] // Check timestamps if entry.FirstSeen.Before(start) || entry.FirstSeen.After(middle) { t.Error("FirstSeen timestamp should be close to start time") } if entry.LastSeen.Before(middle) || entry.LastSeen.After(end.Add(time.Millisecond)) { t.Error("LastSeen timestamp should be close to end time") } if !entry.FirstSeen.Before(entry.LastSeen) { t.Error("FirstSeen should be before LastSeen") } } func TestAreLogsIdentical(t *testing.T) { store := NewStore(100, nil) defer store.Close() now := time.Now() log1 := LogEntry{ ID: "1", ProcessID: "proc1", ProcessName: "test", Timestamp: now, Content: "Test message", Level: LevelInfo, IsError: false, } log2 := LogEntry{ ID: "2", // Different ID ProcessID: "proc1", ProcessName: "test", Timestamp: now.Add(time.Second), // Different timestamp Content: "Test message", Level: LevelInfo, IsError: false, } log3 := LogEntry{ ID: "3", ProcessID: "proc2", // Different process ProcessName: "test", Timestamp: now, Content: "Test message", Level: LevelInfo, IsError: false, } log4 := LogEntry{ ID: "4", ProcessID: "proc1", ProcessName: "test", Timestamp: now, Content: "Different message", // Different content Level: LevelInfo, IsError: false, } // log1 and log2 should be identical (ignore ID and timestamp) if !store.areLogsIdentical(log1, log2) { t.Error("log1 and log2 should be identical") } // log1 and log3 should not be identical (different process) if store.areLogsIdentical(log1, log3) { t.Error("log1 and log3 should not be identical") } // log1 and log4 should not be identical (different content) if store.areLogsIdentical(log1, log4) { t.Error("log1 and log4 should not be identical") } }

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