package healthhttp_test import ( "encoding/json" "errors" "net/http" "net/http/httptest" "testing" "time" "gitea.dwysokinski.me/twhelp/corev3/internal/health" "gitea.dwysokinski.me/twhelp/corev3/internal/health/healthhttp" "gitea.dwysokinski.me/twhelp/corev3/internal/health/healthtest" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestReadyHandler(t *testing.T) { t.Parallel() tests := []struct { name string options []health.Option expectedStatus int expectedResponse healthhttp.Response }{ { name: "pass", options: []health.Option{ health.WithReadyCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithReadyCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithReadyCheck(healthtest.Checker{Nam: "test2", Err: nil}), }, expectedStatus: http.StatusOK, expectedResponse: healthhttp.Response{ Status: health.StatusPass.String(), Checks: map[string][]healthhttp.SingleCheckResult{ "test": { { Status: health.StatusPass.String(), }, { Status: health.StatusPass.String(), }, }, "test2": { { Status: health.StatusPass.String(), }, }, }, }, }, { name: "2 checks passed, 1 check failed", options: []health.Option{ health.WithReadyCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithReadyCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithReadyCheck(healthtest.Checker{Nam: "test2", Err: errors.New("failed")}), }, expectedStatus: http.StatusServiceUnavailable, expectedResponse: healthhttp.Response{ Status: health.StatusFail.String(), Checks: map[string][]healthhttp.SingleCheckResult{ "test": { { Status: health.StatusPass.String(), }, { Status: health.StatusPass.String(), }, }, "test2": { { Status: health.StatusFail.String(), FailureReason: "failed", }, }, }, }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() rr := httptest.NewRecorder() healthhttp.ReadyHandler(health.New(tt.options...)).ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/readyz", nil)) assert.Equal(t, tt.expectedStatus, rr.Code) assert.Equal(t, "application/json", rr.Header().Get("Content-Type")) var body healthhttp.Response require.NoError(t, json.NewDecoder(rr.Body).Decode(&body)) assert.Empty(t, cmp.Diff( tt.expectedResponse, body, cmpopts.IgnoreTypes(time.Time{}), )) }) } } func TestLiveHandler(t *testing.T) { t.Parallel() tests := []struct { name string options []health.Option expectedStatus int expectedResponse healthhttp.Response }{ { name: "pass", options: []health.Option{ health.WithLiveCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithLiveCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithLiveCheck(healthtest.Checker{Nam: "test2", Err: nil}), }, expectedStatus: http.StatusOK, expectedResponse: healthhttp.Response{ Status: health.StatusPass.String(), Checks: map[string][]healthhttp.SingleCheckResult{ "test": { { Status: health.StatusPass.String(), }, { Status: health.StatusPass.String(), }, }, "test2": { { Status: health.StatusPass.String(), }, }, }, }, }, { name: "2 checks passed, 1 check failed", options: []health.Option{ health.WithLiveCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithLiveCheck(healthtest.Checker{Nam: "test", Err: nil}), health.WithLiveCheck(healthtest.Checker{Nam: "test2", Err: errors.New("failed")}), }, expectedStatus: http.StatusServiceUnavailable, expectedResponse: healthhttp.Response{ Status: health.StatusFail.String(), Checks: map[string][]healthhttp.SingleCheckResult{ "test": { { Status: health.StatusPass.String(), }, { Status: health.StatusPass.String(), }, }, "test2": { { Status: health.StatusFail.String(), FailureReason: "failed", }, }, }, }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() rr := httptest.NewRecorder() healthhttp.LiveHandler(health.New(tt.options...)).ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/livez", nil)) assert.Equal(t, tt.expectedStatus, rr.Code) assert.Equal(t, "application/json", rr.Header().Get("Content-Type")) var body healthhttp.Response require.NoError(t, json.NewDecoder(rr.Body).Decode(&body)) assert.Empty(t, cmp.Diff( tt.expectedResponse, body, cmpopts.IgnoreTypes(time.Time{}), )) }) } }