package tests import ( "bytes" "net/http" "net/http/httptest" "testing" "veza-backend-api/internal/api" "veza-backend-api/internal/config" "veza-backend-api/internal/database" "veza-backend-api/internal/eventbus" // Added "veza-backend-api/internal/metrics" // Added "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "go.uber.org/zap/zaptest" "gorm.io/driver/sqlite" "gorm.io/gorm" "github.com/redis/go-redis/v9" // Added ) // Helper function to create a test Gin engine with routes set up func setupTestRouter(t *testing.T) (*gin.Engine, func()) { gin.SetMode(gin.TestMode) router := gin.New() logger := zaptest.NewLogger(t) // Create a minimal mock *gorm.DB instance // This avoids AutoMigrate failures with PostgreSQL-specific DDL in SQLite. // We're essentially mocking the DB connection for the routes that don't need real persistence. mockGormDB, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{}) assert.NoError(t, err) mockDB := &database.Database{ GormDB: mockGormDB, Logger: logger, } // Mock Config mockConfig := &config.Config{ AppPort: 8080, CORSOrigins: []string{"*"}, JWTSecret: "test-secret", UploadDir: "uploads/test", StreamServerURL: "http://localhost:8000", Database: mockDB, // Corrected from testDB Logger: logger, // Pass the logger to the config RedisClient: &redis.Client{}, // Provide a dummy RedisClient RabbitMQEventBus: &eventbus.RabbitMQEventBus{}, // Provide a dummy RabbitMQEventBus ErrorMetrics: metrics.NewErrorMetrics(), // Initialize ErrorMetrics } apiRouter := api.NewAPIRouter(mockDB, mockConfig) apiRouter.Setup(router) cleanup := func() { // No specific cleanup needed for in-memory SQLite in this setup // GORM closes the DB when the gormDB object is garbage collected. } return router, cleanup } func TestPublicCoreRoutes(t *testing.T) { router, cleanup := setupTestRouter(t) defer cleanup() // Define test cases for public core routes testCases := []struct { name string method string legacyPath string modernPath string expectedStatus int expectDeprecatedHeader bool }{ { name: "Health Check", method: http.MethodGet, legacyPath: "/health", modernPath: "/api/v1/health", expectedStatus: http.StatusOK, expectDeprecatedHeader: true, }, { name: "Liveness Check", method: http.MethodGet, legacyPath: "/healthz", modernPath: "/api/v1/healthz", expectedStatus: http.StatusOK, expectDeprecatedHeader: true, }, { name: "Readiness Check", method: http.MethodGet, legacyPath: "/readyz", modernPath: "/api/v1/readyz", expectedStatus: http.StatusOK, expectDeprecatedHeader: true, }, // Metrics endpoints might return different body content due to dynamic nature, // so we primarily check status code. { name: "Metrics", method: http.MethodGet, legacyPath: "/metrics", modernPath: "/api/v1/metrics", expectedStatus: http.StatusOK, expectDeprecatedHeader: true, }, { name: "Aggregated Metrics", method: http.MethodGet, legacyPath: "/metrics/aggregated", modernPath: "/api/v1/metrics/aggregated", expectedStatus: http.StatusOK, expectDeprecatedHeader: true, }, { name: "System Metrics", method: http.MethodGet, legacyPath: "/system/metrics", modernPath: "/api/v1/system/metrics", expectedStatus: http.StatusOK, expectDeprecatedHeader: true, }, } for _, tc := range testCases { t.Run("Legacy "+tc.name, func(t *testing.T) { req, _ := http.NewRequest(tc.method, tc.legacyPath, nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, tc.expectedStatus, w.Code) if tc.expectDeprecatedHeader { assert.Contains(t, w.Header().Get("Deprecated"), "true") } }) t.Run("Modern "+tc.name, func(t *testing.T) { req, _ := http.NewRequest(tc.method, tc.modernPath, nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, tc.expectedStatus, w.Code) assert.NotContains(t, w.Header().Get("Deprecated"), "true") // Modern routes should NOT be deprecated }) } } func TestInternalTrackStreamCallbackRoutes(t *testing.T) { router, cleanup := setupTestRouter(t) defer cleanup() // Test case for internal track stream callback testCases := []struct { name string method string legacyPath string modernPath string expectedStatus int expectDeprecatedHeader bool }{ { name: "Track Stream Ready Callback", method: http.MethodPost, // This is a POST request legacyPath: "/internal/tracks/123e4567-e89b-12d3-a456-426614174000/stream-ready", // Example UUID modernPath: "/api/v1/internal/tracks/123e4567-e89b-12d3-a456-426614174000/stream-ready", // Example UUID expectedStatus: http.StatusNotFound, // Assuming 404 because track 123 won't exist expectDeprecatedHeader: true, }, } for _, tc := range testCases { t.Run("Legacy "+tc.name, func(t *testing.T) { req, _ := http.NewRequest(tc.method, tc.legacyPath, bytes.NewBufferString("{}")) // POST needs a body req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, tc.expectedStatus, w.Code) if tc.expectDeprecatedHeader { assert.Contains(t, w.Header().Get("Deprecated"), "true") } }) t.Run("Modern "+tc.name, func(t *testing.T) { req, _ := http.NewRequest(tc.method, tc.modernPath, bytes.NewBufferString("{}")) // POST needs a body req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, tc.expectedStatus, w.Code) assert.NotContains(t, w.Header().Get("Deprecated"), "true") // Modern routes should NOT be deprecated }) } }