package handler import ( "context" "errors" "net/http" "net/http/httptest" "strings" "testing" "github.com/gin-gonic/gin" ) func TestHealthLiveDoesNotDependOnReadiness(t *testing.T) { gin.SetMode(gin.TestMode) h := NewHealthHandler(map[string]ReadinessCheck{ "mysql": func(context.Context) error { return errors.New("down") }, }) recorder := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(recorder) ctx.Request = httptest.NewRequest(http.MethodGet, "/health", nil) h.Live(ctx) if recorder.Code != http.StatusOK { t.Fatalf("status = %d, want %d", recorder.Code, http.StatusOK) } } func TestHealthReadyReportsDependencyState(t *testing.T) { gin.SetMode(gin.TestMode) tests := []struct { name string checks map[string]ReadinessCheck wantStatus int wantBody string }{ { name: "all dependencies ready", checks: map[string]ReadinessCheck{ "mysql": func(context.Context) error { return nil }, "redis": func(context.Context) error { return nil }, }, wantStatus: http.StatusOK, wantBody: `"status":"ok"`, }, { name: "dependency unavailable", checks: map[string]ReadinessCheck{ "mysql": func(context.Context) error { return errors.New("down") }, "redis": func(context.Context) error { return nil }, }, wantStatus: http.StatusServiceUnavailable, wantBody: `"mysql":"unavailable"`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := NewHealthHandler(tt.checks) recorder := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(recorder) ctx.Request = httptest.NewRequest(http.MethodGet, "/health/ready", nil) h.Ready(ctx) if recorder.Code != tt.wantStatus { t.Fatalf("status = %d, want %d; body=%s", recorder.Code, tt.wantStatus, recorder.Body.String()) } if body := recorder.Body.String(); !strings.Contains(body, tt.wantBody) { t.Fatalf("body = %s, want substring %s", body, tt.wantBody) } }) } }