Files
2026-06-22 08:55:57 +08:00

91 lines
2.6 KiB
Go

package metrics
import (
"io"
"net/http/httptest"
"strings"
"testing"
)
func scrape(t *testing.T, m *Metrics) string {
t.Helper()
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/metrics", nil)
m.Handler().ServeHTTP(rec, req)
if rec.Code != 200 {
t.Fatalf("metrics handler status = %d, want 200", rec.Code)
}
body, _ := io.ReadAll(rec.Result().Body)
return string(body)
}
func TestNewRegistersAllCollectors(t *testing.T) {
m := New(func() float64 { return 3 }, func() float64 { return 12.5 })
// CounterVecs emit no series until a label set is observed; touch each once
// so the metric family name surfaces in the scrape.
m.RecordSessionExit("exited")
m.RecordPermissionDecision("auto")
m.RecordDeadLetter("webhook.deliver")
body := scrape(t, m)
for _, name := range []string{
"acp_sessions_active",
"acp_session_exit_total",
"acp_permission_decisions_total",
"jobs_dead_letter_total",
"llm_cost_usd_total",
} {
if !strings.Contains(body, name) {
t.Errorf("metrics output missing %q\n%s", name, body)
}
}
// GaugeFunc values surface immediately even without any Record* call.
if !strings.Contains(body, "acp_sessions_active 3") {
t.Errorf("acp_sessions_active gauge not reporting func value; body:\n%s", body)
}
if !strings.Contains(body, "llm_cost_usd_total 12.5") {
t.Errorf("llm_cost_usd_total gauge not reporting func value; body:\n%s", body)
}
}
func TestRecordHelpersIncrementWithLabels(t *testing.T) {
m := New(nil, nil)
m.RecordSessionExit("crashed")
m.RecordSessionExit("crashed")
m.RecordSessionExit("exited")
m.RecordPermissionDecision("approved")
m.RecordPermissionDecision("denied")
m.RecordPermissionDecision("expired")
m.RecordDeadLetter("webhook.deliver")
body := scrape(t, m)
wants := []string{
`acp_session_exit_total{status="crashed"} 2`,
`acp_session_exit_total{status="exited"} 1`,
`acp_permission_decisions_total{outcome="approved"} 1`,
`acp_permission_decisions_total{outcome="denied"} 1`,
`acp_permission_decisions_total{outcome="expired"} 1`,
`jobs_dead_letter_total{type="webhook.deliver"} 1`,
}
for _, w := range wants {
if !strings.Contains(body, w) {
t.Errorf("metrics output missing %q\n%s", w, body)
}
}
}
func TestRegistryIsolatedNotGlobalDefault(t *testing.T) {
// Two independent Metrics must not collide (would panic if both used the
// global default registry).
_ = New(nil, nil)
_ = New(nil, nil)
}
func TestNilReceiverRecordSafe(t *testing.T) {
var m *Metrics
// Must not panic — callers may hold a nil *Metrics when metrics disabled.
m.RecordSessionExit("exited")
m.RecordPermissionDecision("auto")
m.RecordDeadLetter("x")
}