package handler import ( "bytes" "encoding/json" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" "nex/backend/internal/domain" "nex/backend/tests/mocks" ) func TestProviderHandler_CreateProvider_Success(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockProviderService(ctrl) mockSvc.EXPECT().Create(gomock.Any()).Return(nil) h := NewProviderHandler(mockSvc) body, _ := json.Marshal(map[string]string{ "id": "p1", "name": "Test", "api_key": "sk-test", "base_url": "https://api.test.com", }) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("POST", "/api/providers", bytes.NewReader(body)) c.Request.Header.Set("Content-Type", "application/json") h.CreateProvider(c) assert.Equal(t, 201, w.Code) var result domain.Provider require.NoError(t, json.Unmarshal(w.Body.Bytes(), &result)) assert.Equal(t, "p1", result.ID) assert.Contains(t, result.APIKey, "***") } func TestProviderHandler_CreateProvider_WithProtocol(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockProviderService(ctrl) mockSvc.EXPECT().Create(gomock.Any()).Return(nil) h := NewProviderHandler(mockSvc) body, _ := json.Marshal(map[string]string{ "id": "p1", "name": "Test", "api_key": "sk-test", "base_url": "https://api.test.com", "protocol": "anthropic", }) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("POST", "/api/providers", bytes.NewReader(body)) c.Request.Header.Set("Content-Type", "application/json") h.CreateProvider(c) assert.Equal(t, 201, w.Code) } func TestProviderHandler_UpdateProvider(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockProviderService(ctrl) mockSvc.EXPECT().Update(gomock.Eq("p1"), gomock.Any()).Return(nil) mockSvc.EXPECT().Get(gomock.Eq("p1"), gomock.Eq(true)).Return(&domain.Provider{ID: "p1", Name: "Updated", APIKey: "***"}, nil) h := NewProviderHandler(mockSvc) body, _ := json.Marshal(map[string]string{"name": "Updated"}) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "p1"}} c.Request = httptest.NewRequest("PUT", "/api/providers/p1", bytes.NewReader(body)) c.Request.Header.Set("Content-Type", "application/json") h.UpdateProvider(c) assert.Equal(t, 200, w.Code) } func TestProviderHandler_UpdateProvider_InvalidBody(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockProviderService(ctrl) h := NewProviderHandler(mockSvc) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "p1"}} c.Request = httptest.NewRequest("PUT", "/api/providers/p1", nil) h.UpdateProvider(c) assert.Equal(t, 400, w.Code) } func TestProviderHandler_DeleteProvider(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockProviderService(ctrl) mockSvc.EXPECT().Delete(gomock.Eq("p1")).Return(nil) h := NewProviderHandler(mockSvc) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "p1"}} c.Request = httptest.NewRequest("DELETE", "/api/providers/p1", bytes.NewReader([]byte{})) c.Request.Header.Set("Content-Type", "application/json") h.DeleteProvider(c) assert.True(t, w.Code == 204 || w.Code == 200) } func TestModelHandler_DeleteModel(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockModelService(ctrl) mockSvc.EXPECT().Delete(gomock.Eq("m1")).Return(nil) h := NewModelHandler(mockSvc) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "m1"}} c.Request = httptest.NewRequest("DELETE", "/api/models/m1", bytes.NewReader([]byte{})) c.Request.Header.Set("Content-Type", "application/json") h.DeleteModel(c) assert.True(t, w.Code == 204 || w.Code == 200) } func TestModelHandler_CreateModel_Success(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockModelService(ctrl) mockSvc.EXPECT().Create(gomock.Any()).DoAndReturn(func(model *domain.Model) error { model.ID = "mock-uuid-1234" return nil }) h := NewModelHandler(mockSvc) body, _ := json.Marshal(map[string]string{ "provider_id": "p1", "model_name": "gpt-4", }) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("POST", "/api/models", bytes.NewReader(body)) c.Request.Header.Set("Content-Type", "application/json") h.CreateModel(c) assert.Equal(t, 201, w.Code) var result domain.Model require.NoError(t, json.Unmarshal(w.Body.Bytes(), &result)) assert.NotEmpty(t, result.ID) } func TestModelHandler_GetModel(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockModelService(ctrl) mockSvc.EXPECT().Get(gomock.Eq("m1")).Return(&domain.Model{ID: "m1", ModelName: "gpt-4"}, nil) h := NewModelHandler(mockSvc) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "m1"}} c.Request = httptest.NewRequest("GET", "/api/models/m1", nil) h.GetModel(c) assert.Equal(t, 200, w.Code) var result domain.Model require.NoError(t, json.Unmarshal(w.Body.Bytes(), &result)) assert.Equal(t, "gpt-4", result.ModelName) } func TestModelHandler_UpdateModel(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSvc := mocks.NewMockModelService(ctrl) mockSvc.EXPECT().Update(gomock.Eq("m1"), gomock.Any()).Return(nil) mockSvc.EXPECT().Get(gomock.Eq("m1")).Return(&domain.Model{ID: "m1", ModelName: "gpt-4o"}, nil) h := NewModelHandler(mockSvc) body, _ := json.Marshal(map[string]string{"model_name": "gpt-4o"}) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "m1"}} c.Request = httptest.NewRequest("PUT", "/api/models/m1", bytes.NewReader(body)) c.Request.Header.Set("Content-Type", "application/json") h.UpdateModel(c) assert.Equal(t, 200, w.Code) }