Add HealthService with Liveness (no-op) and Readiness (DB+Redis ping
with per-component timeout) checks. Expose three endpoints:
- /healthz : new liveness endpoint, zero-dependency, always 200
- /ready : new readiness endpoint, returns 503 with details on dep
failure; suitable for K8s readinessProbe and load balancers
- /health : preserved for backward compatibility, equivalent to
/healthz
Switch primary docker-compose healthcheck to /ready so the container
is only marked healthy once DB+Redis are reachable. Standalone/dev/
local compose files keep /health to avoid disrupting existing setups.
Tests: unit tests cover liveness, readiness with both deps healthy,
each dep failing independently, and per-component timeout enforcement.
50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
package routes
|
||
|
||
import (
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"testing"
|
||
|
||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/stretchr/testify/require"
|
||
)
|
||
|
||
func newTestRouter(t *testing.T, hs *service.HealthService) *gin.Engine {
|
||
t.Helper()
|
||
gin.SetMode(gin.TestMode)
|
||
r := gin.New()
|
||
RegisterCommonRoutes(r, hs)
|
||
return r
|
||
}
|
||
|
||
func TestCommonRoutes_LivenessEndpoints(t *testing.T) {
|
||
r := newTestRouter(t, service.NewHealthService(nil, nil))
|
||
for _, path := range []string{"/healthz", "/health"} {
|
||
req := httptest.NewRequest(http.MethodGet, path, nil)
|
||
w := httptest.NewRecorder()
|
||
r.ServeHTTP(w, req)
|
||
require.Equal(t, http.StatusOK, w.Code, "liveness path %s should be 200", path)
|
||
}
|
||
}
|
||
|
||
func TestCommonRoutes_ReadyEndpoint_NoDepsReturnsOK(t *testing.T) {
|
||
// 没有 DB/Redis 依赖时 readiness 视为 ok(早期启动场景)。
|
||
r := newTestRouter(t, service.NewHealthService(nil, nil))
|
||
req := httptest.NewRequest(http.MethodGet, "/ready", nil)
|
||
w := httptest.NewRecorder()
|
||
r.ServeHTTP(w, req)
|
||
require.Equal(t, http.StatusOK, w.Code)
|
||
require.Contains(t, w.Body.String(), "\"ok\":true")
|
||
}
|
||
|
||
func TestCommonRoutes_SetupStatusUnchanged(t *testing.T) {
|
||
// 验证我们没有破坏既有的 /setup/status 行为(前端依赖)。
|
||
r := newTestRouter(t, service.NewHealthService(nil, nil))
|
||
req := httptest.NewRequest(http.MethodGet, "/setup/status", nil)
|
||
w := httptest.NewRecorder()
|
||
r.ServeHTTP(w, req)
|
||
require.Equal(t, http.StatusOK, w.Code)
|
||
require.Contains(t, w.Body.String(), "needs_setup")
|
||
}
|