Public source validation / validate (push) Failing after 3m8s
136 lines
4.5 KiB
Go
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)
|
|
}
|