package handlers import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "veza-backend-api/internal/config" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "go.uber.org/zap" ) // MockConfigReloader mocks ConfigReloader type MockConfigReloader struct { mock.Mock } func (m *MockConfigReloader) ReloadAll() error { args := m.Called() return args.Error(0) } func (m *MockConfigReloader) ReloadLogLevel() error { args := m.Called() return args.Error(0) } func (m *MockConfigReloader) ReloadRateLimits() error { args := m.Called() return args.Error(0) } func (m *MockConfigReloader) GetCurrentConfig() *config.ReloadableConfig { args := m.Called() if args.Get(0) == nil { return nil } return args.Get(0).(*config.ReloadableConfig) } func setupTestConfigReloadRouter(mockReloader *MockConfigReloader) *gin.Engine { gin.SetMode(gin.TestMode) router := gin.New() logger := zap.NewNop() handler := NewConfigReloadHandlerWithInterface(mockReloader, logger) api := router.Group("/api/v1/config") { api.POST("/reload", handler.ReloadConfig()) api.GET("/", handler.GetConfig()) } return router } func TestConfigReloadHandler_ReloadConfig_All(t *testing.T) { // Setup mockReloader := new(MockConfigReloader) router := setupTestConfigReloadRouter(mockReloader) reqBody := map[string]string{"type": "all"} expectedConfig := &config.ReloadableConfig{ LogLevel: "info", RateLimitLimit: 100, RateLimitWindow: 60, } mockReloader.On("ReloadAll").Return(nil) mockReloader.On("GetCurrentConfig").Return(expectedConfig) body, _ := json.Marshal(reqBody) // Execute req, _ := http.NewRequest("POST", "/api/v1/config/reload", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.True(t, response["success"].(bool)) mockReloader.AssertExpectations(t) } func TestConfigReloadHandler_ReloadConfig_LogLevel(t *testing.T) { // Setup mockReloader := new(MockConfigReloader) router := setupTestConfigReloadRouter(mockReloader) reqBody := map[string]string{"type": "log_level"} expectedConfig := &config.ReloadableConfig{ LogLevel: "debug", RateLimitLimit: 100, RateLimitWindow: 60, } mockReloader.On("ReloadLogLevel").Return(nil) mockReloader.On("GetCurrentConfig").Return(expectedConfig) body, _ := json.Marshal(reqBody) // Execute req, _ := http.NewRequest("POST", "/api/v1/config/reload", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) mockReloader.AssertExpectations(t) } func TestConfigReloadHandler_ReloadConfig_RateLimits(t *testing.T) { // Setup mockReloader := new(MockConfigReloader) router := setupTestConfigReloadRouter(mockReloader) reqBody := map[string]string{"type": "rate_limits"} expectedConfig := &config.ReloadableConfig{ LogLevel: "info", RateLimitLimit: 200, RateLimitWindow: 120, } mockReloader.On("ReloadRateLimits").Return(nil) mockReloader.On("GetCurrentConfig").Return(expectedConfig) body, _ := json.Marshal(reqBody) // Execute req, _ := http.NewRequest("POST", "/api/v1/config/reload", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) mockReloader.AssertExpectations(t) } func TestConfigReloadHandler_ReloadConfig_InvalidType(t *testing.T) { // Setup mockReloader := new(MockConfigReloader) router := setupTestConfigReloadRouter(mockReloader) reqBody := map[string]string{"type": "invalid"} body, _ := json.Marshal(reqBody) // Execute req, _ := http.NewRequest("POST", "/api/v1/config/reload", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) mockReloader.AssertNotCalled(t, "ReloadAll") mockReloader.AssertNotCalled(t, "ReloadLogLevel") mockReloader.AssertNotCalled(t, "ReloadRateLimits") } func TestConfigReloadHandler_ReloadConfig_ServiceError(t *testing.T) { // Setup mockReloader := new(MockConfigReloader) router := setupTestConfigReloadRouter(mockReloader) reqBody := map[string]string{"type": "all"} mockReloader.On("ReloadAll").Return(assert.AnError) body, _ := json.Marshal(reqBody) // Execute req, _ := http.NewRequest("POST", "/api/v1/config/reload", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusInternalServerError, w.Code) mockReloader.AssertExpectations(t) } func TestConfigReloadHandler_GetConfig_Success(t *testing.T) { // Setup mockReloader := new(MockConfigReloader) router := setupTestConfigReloadRouter(mockReloader) expectedConfig := &config.ReloadableConfig{ LogLevel: "info", RateLimitLimit: 100, RateLimitWindow: 60, } mockReloader.On("GetCurrentConfig").Return(expectedConfig) // Execute req, _ := http.NewRequest("GET", "/api/v1/config/", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.True(t, response["success"].(bool)) mockReloader.AssertExpectations(t) }