You've already forked agentic-coding-workflow
91 lines
2.6 KiB
Go
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")
|
|
}
|