package health import ( "fmt" "io" "net/http" "net/http/httptest" "testing" ) func TestBasicHealthHandler(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/__health", nil) w := httptest.NewRecorder() basicHealth(w, req) res := w.Result() defer res.Body.Close() data, err := io.ReadAll(res.Body) if err != nil { t.Errorf("expected error to be nil got %v", err) } if string(data) != "ok" { t.Fail() t.Errorf("expected ok got %q", string(data)) } } func TestProbeHandlers(t *testing.T) { // Test with separate handlers for each probe type srv := NewServer(nil, WithLivenessHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }), WithReadinessHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }), WithStartupHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }), WithServiceName("test-service"), ) tests := []struct { handler http.HandlerFunc expectedStatus int expectedBody string }{ {srv.createProbeHandler("liveness"), 200, `{"status":"alive"}`}, {srv.createProbeHandler("readiness"), 200, `{"ready":true}`}, {srv.createProbeHandler("startup"), 200, `{"started":true}`}, {srv.createGeneralHandler(), 200, `{"service":"test-service","status":"healthy"}`}, } for i, tt := range tests { t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", nil) w := httptest.NewRecorder() tt.handler(w, req) if w.Code != tt.expectedStatus { t.Errorf("expected status %d, got %d", tt.expectedStatus, w.Code) } body := w.Body.String() if body != tt.expectedBody+"\n" { // json.Encoder adds newline t.Errorf("expected body %q, got %q", tt.expectedBody, body) } }) } } func TestProbeHandlerFallback(t *testing.T) { // Test fallback to general handler when no specific handler is configured generalHandler := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } srv := NewServer(generalHandler, WithServiceName("test-service")) tests := []struct { handler http.HandlerFunc expectedStatus int expectedBody string }{ {srv.createProbeHandler("liveness"), 200, `{"status":"alive"}`}, {srv.createProbeHandler("readiness"), 200, `{"ready":true}`}, {srv.createProbeHandler("startup"), 200, `{"started":true}`}, } for i, tt := range tests { t.Run(fmt.Sprintf("fallback_%d", i), func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", nil) w := httptest.NewRecorder() tt.handler(w, req) if w.Code != tt.expectedStatus { t.Errorf("expected status %d, got %d", tt.expectedStatus, w.Code) } body := w.Body.String() if body != tt.expectedBody+"\n" { // json.Encoder adds newline t.Errorf("expected body %q, got %q", tt.expectedBody, body) } }) } } func TestUnhealthyProbeHandlers(t *testing.T) { // Test with handlers that return unhealthy status srv := NewServer(nil, WithLivenessHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusServiceUnavailable) }), WithReadinessHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusServiceUnavailable) }), WithStartupHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusServiceUnavailable) }), WithServiceName("test-service"), ) tests := []struct { handler http.HandlerFunc expectedStatus int expectedBody string }{ {srv.createProbeHandler("liveness"), 503, `{"status":"unhealthy"}`}, {srv.createProbeHandler("readiness"), 503, `{"ready":false}`}, {srv.createProbeHandler("startup"), 503, `{"started":false}`}, } for i, tt := range tests { t.Run(fmt.Sprintf("unhealthy_%d", i), func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", nil) w := httptest.NewRecorder() tt.handler(w, req) if w.Code != tt.expectedStatus { t.Errorf("expected status %d, got %d", tt.expectedStatus, w.Code) } body := w.Body.String() if body != tt.expectedBody+"\n" { // json.Encoder adds newline t.Errorf("expected body %q, got %q", tt.expectedBody, body) } }) } }