Files
orca/internal/transport/metrics_test.go
T
Jon Chery cc53c1a3e4 feat(P01): metrics endpoint — hand-rolled Prometheus text exposition
internal/transport/metrics.go: Metrics struct with counters/gauges,
WritePrometheus text exposition; internal/cli/metrics.go: orca metrics
HTTP server on :9100 serving /metrics + /healthz. No client_golang dep.

---ci---
project: orca
phase: 01
milestone: v0.11
status: execute
---/ci---
2026-08-07 04:24:57 +00:00

127 lines
3.0 KiB
Go

package transport
import (
"context"
"io"
"net"
"net/http"
"strings"
"sync"
"testing"
"time"
)
func TestWritePrometheusFormat(t *testing.T) {
m := NewMetrics()
m.IncCounter("txns_applied_total")
m.AddCounter("txns_applied_total", 41)
m.SetGauge("peers_total", 5)
m.SetGauge("nodes_total", 3.5)
var sb strings.Builder
if err := m.WritePrometheus(&sb); err != nil {
t.Fatalf("WritePrometheus: %v", err)
}
out := sb.String()
want := []string{
"# HELP txns_applied_total Total transactions applied",
"# TYPE txns_applied_total counter",
"txns_applied_total 42",
"# HELP txns_drifted_total Total transactions drifted",
"# TYPE txns_drifted_total counter",
"txns_drifted_total 0",
"# HELP drifts_remediated_total Total drifts remediated",
"# TYPE drifts_remediated_total counter",
"drifts_remediated_total 0",
"# HELP peers_total Current peer count",
"# TYPE peers_total gauge",
"peers_total 5",
"# HELP nodes_total Current node count",
"# TYPE nodes_total gauge",
"nodes_total 3.5",
"# HELP allocs_total Current allocation count",
"# TYPE allocs_total gauge",
"allocs_total 0",
}
for _, w := range want {
if !strings.Contains(out, w+"\n") {
t.Errorf("output missing line %q\n--- got:\n%s", w, out)
}
}
}
func TestMetricsConcurrent(t *testing.T) {
m := NewMetrics()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
m.IncCounter("txns_applied_total")
m.SetGauge("peers_total", 1)
}()
}
wg.Wait()
var sb strings.Builder
if err := m.WritePrometheus(&sb); err != nil {
t.Fatalf("WritePrometheus: %v", err)
}
if !strings.Contains(sb.String(), "txns_applied_total 100\n") {
t.Errorf("expected 100 applied, got:\n%s", sb.String())
}
}
func TestMetricsHTTP(t *testing.T) {
m := NewMetrics()
m.IncCounter("txns_applied_total")
m.SetGauge("nodes_total", 7)
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen: %v", err)
}
addr := ln.Addr().String()
mux := http.NewServeMux()
mux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
_ = m.WritePrometheus(w)
})
srv := &http.Server{Handler: mux}
go srv.Serve(ln)
defer srv.Shutdown(context.Background())
time.Sleep(20 * time.Millisecond)
resp, err := http.Get("http://" + addr + "/metrics")
if err != nil {
t.Fatalf("GET /metrics: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("read body: %v", err)
}
s := string(body)
for _, name := range []string{
"txns_applied_total",
"txns_drifted_total",
"drifts_remediated_total",
"peers_total",
"nodes_total",
"allocs_total",
} {
if !strings.Contains(s, name) {
t.Errorf("response missing metric %q", name)
}
}
if !strings.Contains(s, "txns_applied_total 1\n") {
t.Errorf("counter value wrong in:\n%s", s)
}
if !strings.Contains(s, "nodes_total 7\n") {
t.Errorf("gauge value wrong in:\n%s", s)
}
}