package router import ( "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" ) // setupTestDB creates an in-memory SQLite database for health check tests func setupTestDB(t *testing.T) *gorm.DB { t.Helper() db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) require.NoError(t, err) return db } func TestLiveCheck_Returns200(t *testing.T) { e := echo.New() e.GET("/api/health/live", liveCheck) req := httptest.NewRequest(http.MethodGet, "/api/health/live", nil) rec := httptest.NewRecorder() e.ServeHTTP(rec, req) assert.Equal(t, http.StatusOK, rec.Code) var resp map[string]interface{} err := json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Equal(t, "alive", resp["status"]) assert.Equal(t, Version, resp["version"]) assert.Contains(t, resp, "timestamp") } func TestReadinessCheck_HealthyDB_NilCache_Returns200(t *testing.T) { db := setupTestDB(t) deps := &Dependencies{ DB: db, Cache: nil, // No Redis configured } e := echo.New() e.GET("/api/health/", readinessCheck(deps)) req := httptest.NewRequest(http.MethodGet, "/api/health/", nil) rec := httptest.NewRecorder() e.ServeHTTP(rec, req) assert.Equal(t, http.StatusOK, rec.Code) var resp map[string]interface{} err := json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Equal(t, "healthy", resp["status"]) assert.Equal(t, Version, resp["version"]) checks := resp["checks"].(map[string]interface{}) assert.Equal(t, "ok", checks["postgres"]) assert.Equal(t, "not configured", checks["redis"]) } func TestReadinessCheck_DBDown_Returns503(t *testing.T) { // Open an in-memory SQLite DB, then close the underlying sql.DB to simulate failure db := setupTestDB(t) sqlDB, err := db.DB() require.NoError(t, err) sqlDB.Close() deps := &Dependencies{ DB: db, Cache: nil, } e := echo.New() e.GET("/api/health/", readinessCheck(deps)) req := httptest.NewRequest(http.MethodGet, "/api/health/", nil) rec := httptest.NewRecorder() e.ServeHTTP(rec, req) assert.Equal(t, http.StatusServiceUnavailable, rec.Code) var resp map[string]interface{} err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Equal(t, "unhealthy", resp["status"]) checks := resp["checks"].(map[string]interface{}) assert.Contains(t, checks["postgres"], "ping failed") } func TestReadinessCheck_ResponseFormat(t *testing.T) { db := setupTestDB(t) deps := &Dependencies{ DB: db, Cache: nil, } e := echo.New() e.GET("/api/health/", readinessCheck(deps)) req := httptest.NewRequest(http.MethodGet, "/api/health/", nil) rec := httptest.NewRecorder() e.ServeHTTP(rec, req) var resp map[string]interface{} err := json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) // Verify all expected fields are present assert.Contains(t, resp, "status") assert.Contains(t, resp, "version") assert.Contains(t, resp, "checks") assert.Contains(t, resp, "timestamp") // Verify checks is a map with expected keys checks, ok := resp["checks"].(map[string]interface{}) require.True(t, ok, "checks should be a map") assert.Contains(t, checks, "postgres") assert.Contains(t, checks, "redis") }