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

136 lines
4.5 KiB
Go

package prometheus
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/itworx/pulse/internal/observability"
)
func TestQueryNormalizesWarningsAndUsesFixedEndpoint(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/api/v1/query" || r.URL.Query().Get("query") != "up" {
t.Fatalf("unexpected request: %s", r.URL.String())
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"status":"success","data":{"resultType":"vector"},"warnings":["partial response"]}`))
}))
defer server.Close()
c, err := New(server.URL, nil, Limits{Timeout: time.Second})
if err != nil {
t.Fatal(err)
}
result, err := c.Query(context.Background(), "up", nil)
if err != nil {
t.Fatal(err)
}
if len(result.Warnings) != 1 || c.Metrics().Requests != 1 {
t.Fatalf("unexpected result/metrics: %+v %+v", result, c.Metrics())
}
}
func TestRejectsUserSuppliedEndpointAndOversizedQuery(t *testing.T) {
if _, err := New("http://prometheus.local/api/v1/query?query=up", nil, Limits{}); err == nil {
t.Fatal("expected URL rejection")
}
c, err := New("http://prometheus.local", nil, Limits{MaxQueryLength: 3})
if err != nil {
t.Fatal(err)
}
if _, err := c.Query(context.Background(), "up + 1", nil); err == nil {
t.Fatal("expected query bound rejection")
}
}
func TestTimeoutIsCounted(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(100 * time.Millisecond) }))
defer server.Close()
c, err := New(server.URL, nil, Limits{Timeout: 10 * time.Millisecond})
if err != nil {
t.Fatal(err)
}
_, err = c.Query(context.Background(), "up", nil)
if err == nil || !strings.Contains(err.Error(), "context deadline") {
t.Fatalf("unexpected timeout: %v", err)
}
if c.Metrics().Timeouts != 1 || c.Metrics().Errors != 1 {
t.Fatalf("unexpected metrics: %+v", c.Metrics())
}
}
func TestRangeBounds(t *testing.T) {
c, err := New("http://prometheus.local", nil, Limits{})
if err != nil {
t.Fatal(err)
}
now := time.Now()
if _, err := c.QueryRange(context.Background(), "up", now, now.Add(time.Minute), 0); err == nil {
t.Fatal("expected step validation")
}
}
func TestHealthMapsRequestFailureToUnknown(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "unavailable", http.StatusServiceUnavailable)
}))
defer server.Close()
c, err := New(server.URL, nil, Limits{Timeout: time.Second})
if err != nil {
t.Fatal(err)
}
health := c.Health(context.Background())
if health.State != "unknown" || health.ReasonCode != "PROMETHEUS_UNAVAILABLE" || health.Policy.MaxAge != 30*time.Second {
t.Fatalf("unexpected health: %+v", health)
}
}
func TestQueryLatencyIsMeasuredAndPublished(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
time.Sleep(5 * time.Millisecond)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"status":"success","data":{"resultType":"vector"}}`))
}))
defer server.Close()
c, err := New(server.URL, nil, Limits{Timeout: time.Second})
if err != nil {
t.Fatal(err)
}
if metrics := c.Metrics(); metrics.TotalDuration != 0 || metrics.MaxDuration != 0 {
t.Fatalf("latency counted before any request: %+v", metrics)
}
for index := 0; index < 2; index++ {
if _, err := c.Query(context.Background(), "up", nil); err != nil {
t.Fatal(err)
}
}
metrics := c.Metrics()
if metrics.Requests != 2 || metrics.TotalDuration < 10*time.Millisecond || metrics.MaxDuration < 5*time.Millisecond {
t.Fatalf("query latency was not measured: %+v", metrics)
}
if metrics.MaxDuration > metrics.TotalDuration {
t.Fatalf("max latency exceeds the total: %+v", metrics)
}
registry := observability.NewRegistry(time.Unix(100, 0))
c.PublishMetrics(registry)
exposition := registry.Exposition(time.Unix(101, 0))
for _, name := range []string{"pulse_prometheus_requests_total 2", "pulse_prometheus_errors_total 0", "pulse_prometheus_timeouts_total 0", "pulse_prometheus_request_duration_seconds_sum ", "pulse_prometheus_request_duration_seconds_max "} {
if !strings.Contains(exposition, name) {
t.Fatalf("metric %q missing from exposition: %s", name, exposition)
}
}
}
func TestPublishMetricsToleratesMissingSink(t *testing.T) {
c, err := New("http://prometheus.local", nil, Limits{})
if err != nil {
t.Fatal(err)
}
c.PublishMetrics(nil)
var registry *observability.Registry
c.PublishMetrics(registry)
}