ai-code-battle/metrics/metrics_test.go
jedarden 5a1130c77a feat(bot): add Pacifist bot (JavaScript) — non-aggressive attrition archetype
PacifistBot never attacks; it survives by maximizing distance from enemies
and retreating toward own core when cornered. Pure evasion strategy that
wins via opponent elimination by third parties.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:32:50 -04:00

154 lines
4.2 KiB
Go

package metrics
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestHandlerReturnsOK(t *testing.T) {
h := Handler()
req := httptest.NewRequest(http.MethodGet, "/health", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", w.Code)
}
body := w.Body.String()
if !strings.Contains(body, `"status":"ok"`) {
t.Fatalf("unexpected body: %s", body)
}
}
func TestMetricsEndpoint(t *testing.T) {
// Increment some metrics to ensure they appear
MatchThroughput.Inc()
JobQueueDepth.Set(42)
HTTPRequestsTotal.WithLabelValues("GET", "/test", "200").Inc()
h := Handler()
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", w.Code)
}
body := w.Body.String()
// Verify §9.9 metrics are present
expectedMetrics := []string{
"acb_match_throughput_total",
"acb_job_queue_depth",
"acb_bot_crashed_total",
"acb_job_stale_count",
"acb_r2_bytes_used",
"acb_replay_upload_latency_seconds",
"acb_evolver_generations_total",
"acb_index_build_duration_seconds",
"acb_http_requests_total",
"acb_bots_active",
"acb_bots_failing",
"acb_worker_matches_total",
"acb_worker_match_errors_total",
"acb_worker_jobs_claimed_total",
"acb_worker_match_duration_seconds",
}
for _, name := range expectedMetrics {
if !strings.Contains(body, name) {
t.Errorf("metrics output missing %q", name)
}
}
// Verify the incremented counter is present
if !strings.Contains(body, "acb_match_throughput_total ") {
t.Error("match throughput counter not found in output")
}
// Verify the gauge value
if !strings.Contains(body, "acb_job_queue_depth 42") {
t.Error("job queue depth gauge not found with expected value")
}
}
func TestHTTPRequestsCounter(t *testing.T) {
HTTPRequestsTotal.WithLabelValues("GET", "/api/status", "200").Inc()
HTTPRequestsTotal.WithLabelValues("POST", "/api/register", "201").Inc()
h := Handler()
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
body := w.Body.String()
if !strings.Contains(body, `method="GET",path="/api/status",status="200"`) {
t.Error("labelled HTTP request counter not found")
}
if !strings.Contains(body, `method="POST",path="/api/register",status="201"`) {
t.Error("labelled HTTP request counter not found")
}
}
func TestHistogramObserved(t *testing.T) {
ReplayUploadLatency.Observe(1.5)
IndexBuildDuration.Observe(30.2)
h := Handler()
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
body := w.Body.String()
if !strings.Contains(body, "acb_replay_upload_latency_seconds_bucket") {
t.Error("replay upload latency histogram not found")
}
if !strings.Contains(body, "acb_index_build_duration_seconds_bucket") {
t.Error("index build duration histogram not found")
}
}
func TestBotHealthGauges(t *testing.T) {
BotsActive.Set(12)
BotsFailing.Set(3)
h := Handler()
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
body := w.Body.String()
if !strings.Contains(body, "acb_bots_active 12") {
t.Error("bots_active gauge not found with expected value")
}
if !strings.Contains(body, "acb_bots_failing 3") {
t.Error("bots_failing gauge not found with expected value")
}
}
func TestWorkerMetrics(t *testing.T) {
WorkerMatchesTotal.Inc()
WorkerMatchErrorsTotal.Inc()
WorkerJobsClaimedTotal.Inc()
WorkerMatchDuration.Observe(45.0)
h := Handler()
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
body := w.Body.String()
if !strings.Contains(body, "acb_worker_matches_total ") {
t.Error("worker matches total counter not found")
}
if !strings.Contains(body, "acb_worker_match_errors_total ") {
t.Error("worker match errors counter not found")
}
if !strings.Contains(body, "acb_worker_jobs_claimed_total ") {
t.Error("worker jobs claimed counter not found")
}
if !strings.Contains(body, "acb_worker_match_duration_seconds_bucket") {
t.Error("worker match duration histogram not found")
}
}