Files
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

64 lines
3.0 KiB
Go

package observability
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
func TestRegistryUsesBoundedRouteAndStatusLabels(t *testing.T) {
registry := NewRegistry(time.Unix(100, 0))
registry.ObserveRequest(http.MethodGet, "/api/v1/entities/secret-id", http.StatusNotFound, 25*time.Millisecond)
registry.ObserveRequest(http.MethodGet, "/api/v1/entities/another-id", http.StatusNotFound, 10*time.Millisecond)
exposition := registry.Exposition(time.Unix(101, 0))
if !strings.Contains(exposition, `route="api_other"`) {
t.Fatalf("expected bounded api route labels, got %s", exposition)
}
if strings.Contains(exposition, "secret-id") || strings.Contains(exposition, "another-id") {
t.Fatalf("request path leaked into metrics: %s", exposition)
}
}
func TestMetricsHandlerIsBoundedAndDeterministic(t *testing.T) {
registry := NewRegistry(time.Unix(100, 0))
registry.SetGauge("pulse_database_ready", 1)
registry.ObserveRequest(http.MethodGet, "/healthz", http.StatusOK, time.Second)
handler := registry.Handler()
request := httptest.NewRequest(http.MethodGet, "/api/v1/system/metrics", nil)
first := httptest.NewRecorder()
handler.ServeHTTP(first, request)
if first.Code != http.StatusOK || first.Header().Get("Content-Type") == "" {
t.Fatalf("unexpected metrics response: %d %s", first.Code, first.Body.String())
}
if !strings.Contains(first.Body.String(), "pulse_http_requests_total") || !strings.Contains(first.Body.String(), "pulse_database_ready 1") {
t.Fatalf("missing expected metrics: %s", first.Body.String())
}
second := httptest.NewRecorder()
handler.ServeHTTP(second, httptest.NewRequest(http.MethodGet, "/api/v1/system/metrics", nil))
if first.Body.String() == second.Body.String() {
t.Fatalf("scrape counter did not change between scrapes")
}
}
func TestRegistryCapsUnexpectedSeries(t *testing.T) {
registry := NewRegistry(time.Unix(100, 0))
methods := []string{http.MethodGet, http.MethodHead, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodOptions}
paths := []string{"/healthz", "/readyz", "/auth/test-login", "/session/logout", "/api/v1/system/status", "/api/v1/system/metrics", "/api/v1/system/diagnostics", "/api/v1/metrics/query", "/api/v1/live"}
for index := 0; index < 500; index++ {
registry.ObserveRequest(methods[index%len(methods)], paths[index%len(paths)], 200+(index%5)*100, time.Millisecond)
}
if got := strings.Count(registry.Exposition(time.Unix(101, 0)), "pulse_http_requests_total{"); got > maxRequestSeries {
t.Fatalf("request series = %d, want at most %d", got, maxRequestSeries)
}
}
func TestMetricsMiddlewareRecordsImplicitStatus(t *testing.T) {
registry := NewRegistry(time.Unix(100, 0))
handler := Middleware(registry, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("ok")) }))
handler.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/healthz", nil))
if !strings.Contains(registry.Exposition(time.Unix(101, 0)), `status_class="2xx"`) {
t.Fatal("implicit 200 response was not measured")
}
}