package routes import ( "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" ) func TestRegisterCommonRoutes(t *testing.T) { gin.SetMode(gin.TestMode) r := gin.New() RegisterCommonRoutes(r) // Test /health w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/health", nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) // Test /live w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/live", nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) // Test /ready (no health checker set) w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/ready", nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) // Test /metrics w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/metrics", nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) // Test /setup/status w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/setup/status", nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var setupResp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &setupResp) assert.NoError(t, err) assert.Equal(t, float64(0), setupResp["code"]) // Test POST /api/event_logging/batch w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodPost, "/api/event_logging/batch", nil) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) } func TestHealthHandler_NoHealthChecker(t *testing.T) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/health", nil) healthHandler(c) assert.Equal(t, http.StatusOK, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "ok", resp["status"]) components, ok := resp["components"].(map[string]interface{}) assert.True(t, ok) db, ok := components["database"].(map[string]interface{}) assert.True(t, ok) assert.Equal(t, "unknown", db["status"]) } func TestReadinessHandler_NoHealthChecker(t *testing.T) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/ready", nil) readinessHandler(c) assert.Equal(t, http.StatusOK, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "ready", resp["status"]) } func TestLivenessHandler(t *testing.T) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/live", nil) livenessHandler(c) assert.Equal(t, http.StatusOK, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "alive", resp["status"]) // Verify timestamp is valid ts, ok := resp["timestamp"].(string) assert.True(t, ok) _, err = time.Parse(time.RFC3339, ts) assert.NoError(t, err) } // mockHealthChecker implements HealthChecker for testing type mockHealthChecker struct { dbHealthy bool redisHealthy bool } func (m *mockHealthChecker) CheckDatabase() bool { return m.dbHealthy } func (m *mockHealthChecker) CheckRedis() bool { return m.redisHealthy } func TestHealthHandler_WithHealthyChecker(t *testing.T) { gin.SetMode(gin.TestMode) // Reset the healthChecker for test healthChecker = &mockHealthChecker{dbHealthy: true, redisHealthy: true} w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/health", nil) healthHandler(c) assert.Equal(t, http.StatusOK, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "ok", resp["status"]) } func TestHealthHandler_WithUnhealthyDB(t *testing.T) { gin.SetMode(gin.TestMode) healthChecker = &mockHealthChecker{dbHealthy: false, redisHealthy: true} w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/health", nil) healthHandler(c) assert.Equal(t, http.StatusServiceUnavailable, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "degraded", resp["status"]) } func TestHealthHandler_WithUnhealthyRedis(t *testing.T) { gin.SetMode(gin.TestMode) healthChecker = &mockHealthChecker{dbHealthy: true, redisHealthy: false} w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/health", nil) healthHandler(c) assert.Equal(t, http.StatusServiceUnavailable, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "degraded", resp["status"]) } func TestReadinessHandler_AllHealthy(t *testing.T) { gin.SetMode(gin.TestMode) healthChecker = &mockHealthChecker{dbHealthy: true, redisHealthy: true} w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/ready", nil) readinessHandler(c) assert.Equal(t, http.StatusOK, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "ready", resp["status"]) } func TestReadinessHandler_NotReady(t *testing.T) { gin.SetMode(gin.TestMode) healthChecker = &mockHealthChecker{dbHealthy: true, redisHealthy: false} w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(http.MethodGet, "/ready", nil) readinessHandler(c) assert.Equal(t, http.StatusServiceUnavailable, w.Code) var resp map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, "not_ready", resp["status"]) } func TestDelegatedMetricFunctions(t *testing.T) { // These should not panic - they delegate to prommetrics package RecordHTTPRequest("GET", "/test", 200, 100*time.Millisecond) SetDBConnections(5, 3) SetRedisConnections(10, 4) SetActiveAccounts(50) SetRequestQueueDepth(5) SetOpsHealthScore(90) SetErrorRate(0.1) SetSuccessRate(0.9) SetQPS(100.0) SetTPS(500.0) }