Expose /metrics with counters for routed requests, routing errors, upstream outcomes, and upstream latency histograms. Instrument the router and proxy forwarding path and document the new metrics.
87 lines
2.5 KiB
Go
87 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
func TestHandleRouteForwardsToCustomBackend(t *testing.T) {
|
|
custom := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/api/v1/send_push" {
|
|
t.Fatalf("path = %q", r.URL.Path)
|
|
}
|
|
body, _ := io.ReadAll(r.Body)
|
|
if !strings.Contains(string(body), "apple_bubbles") {
|
|
t.Fatalf("body = %s", body)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"status":"OK"}`))
|
|
}))
|
|
defer custom.Close()
|
|
|
|
cfg := Config{
|
|
Routes: []Route{
|
|
{Prefixes: []string{"apple_bubbles"}, URL: custom.URL},
|
|
{Prefixes: []string{"apple_rn"}, URL: "https://example.invalid"},
|
|
},
|
|
RequestTimeout: time.Duration(defaultRequestTimeoutSec) * time.Second,
|
|
}
|
|
proxy := NewProxy(cfg, NewMetrics(prometheus.NewRegistry()))
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/send_push", strings.NewReader(`{"platform":"apple_bubbles","device_id":"tok","server_id":"s1"}`))
|
|
rec := httptest.NewRecorder()
|
|
|
|
handleRoute(rec, req, proxy, cfg, "/api/v1/send_push")
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String())
|
|
}
|
|
if !strings.Contains(rec.Body.String(), `"status":"OK"`) {
|
|
t.Fatalf("body = %s", rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestHandleRouteUnknownPlatform(t *testing.T) {
|
|
cfg := Config{
|
|
Routes: []Route{
|
|
{Prefixes: []string{"apple_bubbles"}, URL: "http://localhost:1"},
|
|
},
|
|
RequestTimeout: time.Duration(defaultRequestTimeoutSec) * time.Second,
|
|
}
|
|
proxy := NewProxy(cfg, NewMetrics(prometheus.NewRegistry()))
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/send_push", strings.NewReader(`{"platform":"unknown_app","device_id":"tok","server_id":"s1"}`))
|
|
rec := httptest.NewRecorder()
|
|
|
|
handleRoute(rec, req, proxy, cfg, "/api/v1/send_push")
|
|
|
|
if !strings.Contains(rec.Body.String(), `"status":"FAIL"`) {
|
|
t.Fatalf("body = %s", rec.Body.String())
|
|
}
|
|
if !strings.Contains(rec.Body.String(), "unknown_app") {
|
|
t.Fatalf("body = %s", rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestHealthEndpoint(t *testing.T) {
|
|
req := httptest.NewRequest(http.MethodGet, "/health", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handleHealth(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d", rec.Code)
|
|
}
|
|
if ct := rec.Header().Get("Content-Type"); !strings.Contains(ct, "application/json") {
|
|
t.Fatalf("content-type = %q", ct)
|
|
}
|
|
if strings.TrimSpace(rec.Body.String()) != `{"status":"ok"}` {
|
|
t.Fatalf("body = %q", rec.Body.String())
|
|
}
|
|
}
|