Files
2026-08-14 23:41:57 +08:00

210 lines
6.9 KiB
Go

package cli
import (
"testing"
"github.com/smallnest/pigo/internal/agentcore"
)
// TestTelemetryHolderReset verifies that Reset clears the holder to "no telemetry yet".
func TestTelemetryHolderReset(t *testing.T) {
h := NewTelemetryHolder()
if h.HasTelemetry() {
t.Fatal("expected HasTelemetry() = false on new holder")
}
// Fold an event and verify it's present.
h.Fold(agentcore.TelemetryEvent{
Turns: 1,
TruncationCount: 1,
CompactionCount: 1,
ContextTokens: 100,
ContextWindow: 1000,
})
if !h.HasTelemetry() {
t.Fatal("expected HasTelemetry() = true after Fold")
}
if h.Last() == nil {
t.Fatal("expected Last() != nil after Fold")
}
if h.CumulativeTurns() != 1 {
t.Fatalf("expected CumulativeTurns() = 1, got %d", h.CumulativeTurns())
}
// Reset and verify it's cleared.
h.Reset()
if h.HasTelemetry() {
t.Fatal("expected HasTelemetry() = false after Reset")
}
if h.Last() != nil {
t.Fatal("expected Last() = nil after Reset")
}
if h.CumulativeTurns() != 0 {
t.Fatalf("expected CumulativeTurns() = 0 after Reset, got %d", h.CumulativeTurns())
}
if h.CumulativeTruncationCount() != 0 {
t.Fatalf("expected CumulativeTruncationCount() = 0 after Reset, got %d", h.CumulativeTruncationCount())
}
if h.CumulativeCompactionCount() != 0 {
t.Fatalf("expected CumulativeCompactionCount() = 0 after Reset, got %d", h.CumulativeCompactionCount())
}
if h.LatestContextTokens() != 0 {
t.Fatalf("expected LatestContextTokens() = 0 after Reset, got %d", h.LatestContextTokens())
}
if h.LatestContextWindow() != 0 {
t.Fatalf("expected LatestContextWindow() = 0 after Reset, got %d", h.LatestContextWindow())
}
}
// TestTelemetryHolderFoldTwoEvents verifies that folding two synthetic TelemetryEvents
// sums the metrics correctly.
func TestTelemetryHolderFoldTwoEvents(t *testing.T) {
h := NewTelemetryHolder()
// Fold first event.
h.Fold(agentcore.TelemetryEvent{
Turns: 2,
TruncationCount: 1,
CompactionCount: 3,
ContextTokens: 100,
ContextWindow: 1000,
ToolDurationsMs: map[string]agentcore.ToolTiming{
"foo": {Count: 1, TotalMs: 100},
"bar": {Count: 2, TotalMs: 200},
},
})
// Verify the first event is the last one.
if !h.HasTelemetry() {
t.Fatal("expected HasTelemetry() = true after first Fold")
}
last1 := h.Last()
if last1 == nil {
t.Fatal("expected Last() != nil after first Fold")
}
if last1.Turns != 2 {
t.Fatalf("expected Last().Turns = 2, got %d", last1.Turns)
}
// Verify cumulative after first event.
if h.CumulativeTurns() != 2 {
t.Fatalf("expected CumulativeTurns() = 2 after first Fold, got %d", h.CumulativeTurns())
}
if h.CumulativeTruncationCount() != 1 {
t.Fatalf("expected CumulativeTruncationCount() = 1 after first Fold, got %d", h.CumulativeTruncationCount())
}
if h.CumulativeCompactionCount() != 3 {
t.Fatalf("expected CumulativeCompactionCount() = 3 after first Fold, got %d", h.CumulativeCompactionCount())
}
if h.LatestContextTokens() != 100 {
t.Fatalf("expected LatestContextTokens() = 100 after first Fold, got %d", h.LatestContextTokens())
}
if h.LatestContextWindow() != 1000 {
t.Fatalf("expected LatestContextWindow() = 1000 after first Fold, got %d", h.LatestContextWindow())
}
tools1 := h.CumulativeToolDurations()
if tools1["foo"].Count != 1 || tools1["foo"].TotalMs != 100 {
t.Fatalf("expected foo tool timing {1, 100}, got %+v", tools1["foo"])
}
if tools1["bar"].Count != 2 || tools1["bar"].TotalMs != 200 {
t.Fatalf("expected bar tool timing {2, 200}, got %+v", tools1["bar"])
}
// Fold second event.
h.Fold(agentcore.TelemetryEvent{
Turns: 3,
TruncationCount: 2,
CompactionCount: 1,
ContextTokens: 150,
ContextWindow: 1000,
ToolDurationsMs: map[string]agentcore.ToolTiming{
"foo": {Count: 2, TotalMs: 250},
"baz": {Count: 1, TotalMs: 50},
},
})
// Verify the second event is now the last one.
last2 := h.Last()
if last2 == nil {
t.Fatal("expected Last() != nil after second Fold")
}
if last2.Turns != 3 {
t.Fatalf("expected Last().Turns = 3, got %d", last2.Turns)
}
// Verify cumulative after second event (sums of both).
if h.CumulativeTurns() != 5 {
t.Fatalf("expected CumulativeTurns() = 5 after second Fold, got %d", h.CumulativeTurns())
}
if h.CumulativeTruncationCount() != 3 {
t.Fatalf("expected CumulativeTruncationCount() = 3 after second Fold, got %d", h.CumulativeTruncationCount())
}
if h.CumulativeCompactionCount() != 4 {
t.Fatalf("expected CumulativeCompactionCount() = 4 after second Fold, got %d", h.CumulativeCompactionCount())
}
if h.LatestContextTokens() != 150 {
t.Fatalf("expected LatestContextTokens() = 150 after second Fold, got %d", h.LatestContextTokens())
}
if h.LatestContextWindow() != 1000 {
t.Fatalf("expected LatestContextWindow() = 1000 after second Fold, got %d", h.LatestContextWindow())
}
tools2 := h.CumulativeToolDurations()
if tools2["foo"].Count != 3 || tools2["foo"].TotalMs != 350 {
t.Fatalf("expected foo tool timing {3, 350} after sum, got %+v", tools2["foo"])
}
if tools2["bar"].Count != 2 || tools2["bar"].TotalMs != 200 {
t.Fatalf("expected bar tool timing {2, 200} unchanged, got %+v", tools2["bar"])
}
if tools2["baz"].Count != 1 || tools2["baz"].TotalMs != 50 {
t.Fatalf("expected baz tool timing {1, 50} after sum, got %+v", tools2["baz"])
}
}
// TestTelemetryHolderCumulativeContextUtilization verifies context utilization calculation.
func TestTelemetryHolderCumulativeContextUtilization(t *testing.T) {
h := NewTelemetryHolder()
// With unknown window (0), utilization should be 0.
h.Fold(agentcore.TelemetryEvent{
ContextTokens: 100,
ContextWindow: 0,
})
if h.CumulativeContextUtilization() != 0 {
t.Fatalf("expected utilization = 0 with unknown window, got %f", h.CumulativeContextUtilization())
}
// With known window, utilization should be tokens/window.
h.Fold(agentcore.TelemetryEvent{
ContextTokens: 500,
ContextWindow: 1000,
})
if h.CumulativeContextUtilization() != 0.5 {
t.Fatalf("expected utilization = 0.5, got %f", h.CumulativeContextUtilization())
}
}
// TestTelemetryHolderToolDurationsImmutable verifies that CumulativeToolDurations returns
// a copy to prevent external mutation.
func TestTelemetryHolderToolDurationsImmutable(t *testing.T) {
h := NewTelemetryHolder()
h.Fold(agentcore.TelemetryEvent{
ToolDurationsMs: map[string]agentcore.ToolTiming{
"test": {Count: 1, TotalMs: 100},
},
})
// Get the tool durations and mutate the returned map.
tools := h.CumulativeToolDurations()
tools["test"] = agentcore.ToolTiming{Count: 999, TotalMs: 9999}
tools["new"] = agentcore.ToolTiming{Count: 1, TotalMs: 1}
// Verify the internal state was not modified.
tools2 := h.CumulativeToolDurations()
if tools2["test"].Count != 1 || tools2["test"].TotalMs != 100 {
t.Fatalf("expected internal tool timing to remain {1, 100}, got %+v", tools2["test"])
}
if _, ok := tools2["new"]; ok {
t.Fatal("expected 'new' tool not to be present in internal state")
}
}