This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user