package health import ( "context" "errors" "net/http" "net/http/httptest" "strings" "testing" ) func TestHandlerReturnsHealthyWhenAllChecksPass(t *testing.T) { handler := NewHandler("vehicle-realtime-api", []Check{ {Name: "redis", Check: func(context.Context) error { return nil }}, {Name: "mysql", Check: func(context.Context) error { return nil }}, }) request := httptest.NewRequest(http.MethodGet, "/readyz", nil) response := httptest.NewRecorder() handler.ServeHTTP(response, request) if response.Code != http.StatusOK { t.Fatalf("status = %d body=%s", response.Code, response.Body.String()) } body := response.Body.String() for _, want := range []string{`"service":"vehicle-realtime-api"`, `"status":"ok"`, `"redis":{"status":"ok"`, `"mysql":{"status":"ok"`} { if !strings.Contains(body, want) { t.Fatalf("response missing %s: %s", want, body) } } } func TestHandlerReturnsServiceUnavailableWhenCheckFails(t *testing.T) { handler := NewHandler("vehicle-history-writer", []Check{ {Name: "tdengine", Check: func(context.Context) error { return errors.New("ping failed") }}, }) request := httptest.NewRequest(http.MethodGet, "/readyz", nil) response := httptest.NewRecorder() handler.ServeHTTP(response, request) if response.Code != http.StatusServiceUnavailable { t.Fatalf("status = %d body=%s", response.Code, response.Body.String()) } body := response.Body.String() for _, want := range []string{`"service":"vehicle-history-writer"`, `"status":"degraded"`, `"tdengine":`, `"status":"error"`, `"error":"ping failed"`} { if !strings.Contains(body, want) { t.Fatalf("response missing %s: %s", want, body) } } } func TestHandlerRejectsUnknownPath(t *testing.T) { handler := NewHandler("vehicle-gateway", nil) request := httptest.NewRequest(http.MethodGet, "/metrics", nil) response := httptest.NewRecorder() handler.ServeHTTP(response, request) if response.Code != http.StatusNotFound { t.Fatalf("status = %d body=%s", response.Code, response.Body.String()) } } func TestNewMuxRegistersHealthAndReadinessRoutes(t *testing.T) { mux := NewMux("vehicle-stat-writer", []Check{ {Name: "mysql", Check: func(context.Context) error { return nil }}, }) for _, path := range []string{"/healthz", "/readyz"} { request := httptest.NewRequest(http.MethodGet, path, nil) response := httptest.NewRecorder() mux.ServeHTTP(response, request) if response.Code != http.StatusOK { t.Fatalf("%s status = %d body=%s", path, response.Code, response.Body.String()) } } } func TestNewServerReturnsNilWhenAddressIsEmpty(t *testing.T) { if server := NewServer("", "vehicle-gateway", nil); server != nil { t.Fatalf("server = %#v, want nil", server) } } func TestNewServerBuildsConfiguredHTTPServer(t *testing.T) { server := NewServer(":20290", "vehicle-gateway", nil) if server == nil { t.Fatal("server is nil") } if server.Addr != ":20290" { t.Fatalf("addr = %q", server.Addr) } if server.ReadHeaderTimeout == 0 { t.Fatal("ReadHeaderTimeout should be configured") } }