package metrics import ( "context" "io" "net" "net/http" "strings" "testing" "time" ) func TestListenAndServeShutdown(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() errCh := make(chan error, 1) go func() { errCh <- ListenAndServe(ctx, "127.0.0.1:0", "/metrics") }() time.Sleep(50 * time.Millisecond) cancel() select { case err := <-errCh: if err != nil { t.Fatalf("ListenAndServe returned error: %v", err) } case <-time.After(2 * time.Second): t.Fatal("ListenAndServe did not return after context cancel") } } func TestMetricsEndpoint(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } addr := ln.Addr().String() _ = ln.Close() // Increment counters so they appear in output. ConnectionsTotal.WithLabelValues("127.0.0.1:4430", "l4").Inc() FirewallBlockedTotal.WithLabelValues("ip").Inc() ConnectionsActive.WithLabelValues("127.0.0.1:4430").Set(1) go func() { _ = ListenAndServe(ctx, addr, "/metrics") }() time.Sleep(100 * time.Millisecond) resp, err := http.Get("http://" + addr + "/metrics") if err != nil { t.Fatalf("GET /metrics: %v", err) } defer func() { _ = resp.Body.Close() }() if resp.StatusCode != 200 { t.Fatalf("status = %d, want 200", resp.StatusCode) } body, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("reading body: %v", err) } text := string(body) for _, want := range []string{ "mcproxy_connections_total", "mcproxy_firewall_blocked_total", "mcproxy_connections_active", } { if !strings.Contains(text, want) { t.Errorf("response missing %s", want) } } } func TestMetricsDefaultPath(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } addr := ln.Addr().String() _ = ln.Close() go func() { _ = ListenAndServe(ctx, addr, "") }() time.Sleep(100 * time.Millisecond) resp, err := http.Get("http://" + addr + "/metrics") if err != nil { t.Fatalf("GET /metrics: %v", err) } defer func() { _ = resp.Body.Close() }() if resp.StatusCode != 200 { t.Fatalf("status = %d, want 200", resp.StatusCode) } } func TestMetricsSanity(t *testing.T) { // Verify all metric vars can be used without panicking. ConnectionsTotal.WithLabelValues("test:443", "l4").Inc() ConnectionsActive.WithLabelValues("test:443").Set(5) FirewallBlockedTotal.WithLabelValues("ip").Inc() FirewallBlockedTotal.WithLabelValues("cidr").Inc() FirewallBlockedTotal.WithLabelValues("country").Inc() FirewallBlockedTotal.WithLabelValues("rate_limit").Inc() BackendDialDuration.WithLabelValues("127.0.0.1:8080").Observe(0.005) TransferredBytesTotal.WithLabelValues("client_to_backend", "example.com").Add(1024) TransferredBytesTotal.WithLabelValues("backend_to_client", "example.com").Add(2048) L7ResponsesTotal.WithLabelValues("example.com", "200").Inc() L7ResponsesTotal.WithLabelValues("example.com", "502").Inc() L7PolicyBlocksTotal.WithLabelValues("example.com", "block_user_agent").Inc() L7PolicyBlocksTotal.WithLabelValues("example.com", "require_header").Inc() }