package router import ( "net/http" "net/http/httptest" "strings" "testing" "github.com/prometheus/client_golang/prometheus" "gitea.mynodes.xyz/ilker/llmgw/internal/config" ) type constantCollector struct{ desc *prometheus.Desc } func (c constantCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.desc } func (c constantCollector) Collect(ch chan<- prometheus.Metric) { ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, 1) } func TestARegisteredCollectorReachesTheMetricsEndpoint(t *testing.T) { // Registering after AdminHandler silently published nothing, because that // is where the registry is built. The fleet metrics were deployed and // absent, and only looking at the live endpoint showed it — a wiring // mistake that no type checks and nothing fails on. e := newFakeEngine(t, "m") rt := newTestRouter(t, baseConfig(config.Endpoint{ID: "a", URL: e.srv.URL, Models: []string{"m"}})) if err := rt.RegisterMetrics(constantCollector{ desc: prometheus.NewDesc("llmgw_test_collector", "proof it was registered", nil, nil), }); err != nil { t.Fatal(err) } mux, err := rt.AdminHandler() if err != nil { t.Fatal(err) } req := httptest.NewRequest(http.MethodGet, "/metrics", nil) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if !strings.Contains(rec.Body.String(), "llmgw_test_collector") { t.Error("a registered collector did not reach /metrics") } } func TestTheMetricsListenerServesMetricsAndNotPprof(t *testing.T) { // The whole reason it exists. pprof can dump the process heap, and API keys // are in that heap in plaintext — so the listener that can be reached from // another machine must not carry it. Sharing one meant a fleet could be // monitored or keep its heap private, and not both. e := newFakeEngine(t, "m") rt := newTestRouter(t, baseConfig(config.Endpoint{ID: "a", URL: e.srv.URL, Models: []string{"m"}})) if _, err := rt.AdminHandler(); err != nil { t.Fatal(err) } h := rt.MetricsHandler() if h == nil { t.Fatal("no metrics handler after AdminHandler") } rec := httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/metrics", nil)) if rec.Code != http.StatusOK { t.Errorf("/metrics returned %d", rec.Code) } if !strings.Contains(rec.Body.String(), "llmgw_") { t.Error("/metrics served nothing recognisable") } for _, path := range []string{ "/debug/pprof/", "/debug/pprof/heap", "/debug/pprof/cmdline", "/debug/pprof/profile", "/debug/pprof/trace", "/api/v1/nodes", "/admin", } { rec := httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, path, nil)) if rec.Code != http.StatusNotFound { t.Errorf("%s returned %d on the metrics listener; it must not be reachable there", path, rec.Code) } } } func TestMetricsStayOnTheAdminListenerToo(t *testing.T) { // Anything already scraping the admin listener keeps working; adding a door // is not the same as moving one. e := newFakeEngine(t, "m") rt := newTestRouter(t, baseConfig(config.Endpoint{ID: "a", URL: e.srv.URL, Models: []string{"m"}})) mux, err := rt.AdminHandler() if err != nil { t.Fatal(err) } rec := httptest.NewRecorder() mux.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/metrics", nil)) if rec.Code != http.StatusOK { t.Errorf("/metrics on the admin listener returned %d", rec.Code) } } func TestTheMetricsHandlerIsNilBeforeTheRegistryExists(t *testing.T) { // Ordering has bitten this exact area once already: a collector registered // after AdminHandler published nothing at all, silently. Saying nil beats // serving an empty page that looks like a working scrape target. e := newFakeEngine(t, "m") rt := newTestRouter(t, baseConfig(config.Endpoint{ID: "a", URL: e.srv.URL, Models: []string{"m"}})) if rt.MetricsHandler() != nil { t.Error("a metrics handler existed before the registry was built") } }