package services import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" "github.com/ydn/yourdreamnamehere/internal/api" "github.com/ydn/yourdreamnamehere/internal/config" "github.com/ydn/yourdreamnamehere/internal/models" ) // Mock services for API testing type MockUserService struct { mock.Mock } func (m *MockUserService) CreateUser(email, firstName, lastName, password string) (*models.User, error) { args := m.Called(email, firstName, lastName, password) return args.Get(0).(*models.User), args.Error(1) } func (m *MockUserService) AuthenticateUser(email, password string) (string, error) { args := m.Called(email, password) return args.String(0), args.Error(1) } func (m *MockUserService) GetUserByID(userID string) (*models.User, error) { args := m.Called(userID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.User), args.Error(1) } func (m *MockUserService) UpdateUser(userID, firstName, lastName string) (*models.User, error) { args := m.Called(userID, firstName, lastName) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.User), args.Error(1) } type MockStripeService struct { mock.Mock } func (m *MockStripeService) CreateCheckoutSession(email, domainName string) (string, error) { args := m.Called(email, domainName) return args.String(0), args.Error(1) } type MockOVHService struct { mock.Mock } type MockCloudronService struct { mock.Mock } type MockDolibarrService struct { mock.Mock } type MockDeploymentService struct { mock.Mock } type MockEmailService struct { mock.Mock } // API Handler Test Suite type APITestSuite struct { suite.Suite router *gin.Engine handler *api.Handler userService *MockUserService stripeService *MockStripeService } func (suite *APITestSuite) SetupTest() { gin.SetMode(gin.TestMode) // Create mock services suite.userService = new(MockUserService) suite.stripeService = new(MockStripeService) // Create handler with mocks suite.handler = api.NewHandler( suite.userService, suite.stripeService, new(MockOVHService), new(MockCloudronService), new(MockDolibarrService), new(MockDeploymentService), new(MockEmailService), ) // Setup router suite.router = gin.New() suite.handler.RegisterRoutes(suite.router) } func (suite *APITestSuite) TestHealthCheck() { // Arrange w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/health", nil) // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "healthy", response["status"]) } func (suite *APITestSuite) TestRegisterUserSuccess() { // Arrange userData := map[string]interface{}{ "email": "test@example.com", "first_name": "John", "last_name": "Doe", "password": "password123", } expectedUser := &models.User{ Email: "test@example.com", FirstName: "John", LastName: "Doe", } suite.userService.On("CreateUser", "test@example.com", "John", "Doe", "password123"). Return(expectedUser, nil) body, _ := json.Marshal(userData) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/register", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusCreated, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "User created successfully", response["message"]) assert.NotNil(suite.T(), response["user"]) } func (suite *APITestSuite) TestRegisterUserInvalidData() { // Arrange userData := map[string]interface{}{ "email": "invalid-email", // Invalid email "first_name": "John", "last_name": "Doe", "password": "123", // Too short } body, _ := json.Marshal(userData) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/register", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusBadRequest, w.Code) } func (suite *APITestSuite) TestLoginUserSuccess() { // Arrange loginData := map[string]interface{}{ "email": "test@example.com", "password": "password123", } suite.userService.On("AuthenticateUser", "test@example.com", "password123"). Return("mock-jwt-token", nil) body, _ := json.Marshal(loginData) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/login", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "mock-jwt-token", response["token"]) assert.Equal(suite.T(), "Login successful", response["message"]) } func (suite *APITestSuite) TestLoginUserInvalidCredentials() { // Arrange loginData := map[string]interface{}{ "email": "test@example.com", "password": "wrongpassword", } suite.userService.On("AuthenticateUser", "test@example.com", "wrongpassword"). Return("", assert.AnError) body, _ := json.Marshal(loginData) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/login", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusUnauthorized, w.Code) } func (suite *APITestSuite) TestGetPricing() { // Arrange w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/api/v1/pricing", nil) // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(suite.T(), err) assert.NotNil(suite.T(), response["plans"]) plans, ok := response["plans"].([]interface{}) assert.True(suite.T(), ok) assert.Len(suite.T(), plans, 1) } func (suite *APITestSuite) TestCreateCheckoutSession() { // Arrange checkoutData := map[string]interface{}{ "domain_name": "example.com", "email": "test@example.com", } suite.stripeService.On("CreateCheckoutSession", "test@example.com", "example.com"). Return("https://checkout.stripe.com/pay/mock-session-id", nil) body, _ := json.Marshal(checkoutData) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/checkout", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") // Act suite.router.ServeHTTP(w, req) // Assert assert.Equal(suite.T(), http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "https://checkout.stripe.com/pay/mock-session-id", response["checkout_url"]) } // Protected route tests would require JWT middleware setup // For brevity, focusing on public endpoints here // Run the test suite func TestAPITestSuite(t *testing.T) { suite.Run(t, new(APITestSuite)) }