package main import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) type IntegrationTestSuite struct { suite.Suite router *gin.Engine } func (suite *IntegrationTestSuite) SetupSuite() { gin.SetMode(gin.TestMode) suite.router = gin.Default() // Add CORS middleware suite.router.Use(func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(http.StatusNoContent) return } c.Next() }) // Setup routes suite.setupRoutes() } func (suite *IntegrationTestSuite) setupRoutes() { // Health endpoint suite.router.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "ok", "message": "YourDreamNameHere API is running", "timestamp": time.Now(), "version": "1.0.0", }) }) // API status endpoint suite.router.GET("/api/status", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "operational", "services": gin.H{ "ovh": "connected", "stripe": "connected", "cloudron": "ready", "dolibarr": "connected", }, "uptime": "0h 0m", }) }) // Launch endpoint suite.router.POST("/api/launch", func(c *gin.Context) { var req struct { Domain string `json:"domain" binding:"required"` Email string `json:"email" binding:"required,email"` CardNumber string `json:"cardNumber" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid request format", }) return } // Validate inputs if req.Domain == "" || req.Email == "" || req.CardNumber == "" { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "All fields are required", }) return } // Return success response c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Your hosting business is being provisioned! You'll receive an email when setup is complete.", "customer_id": "test-customer-" + time.Now().Format("20060102150405"), "domain": req.Domain, "provisioned": false, }) }) // Customer status endpoint suite.router.GET("/api/status/:customerID", func(c *gin.Context) { customerID := c.Param("customerID") c.JSON(http.StatusOK, gin.H{ "customer_id": customerID, "status": "provisioning", "progress": 25, "estimated_time": "15 minutes", "steps": []gin.H{ {"name": "Domain Registration", "status": "completed"}, {"name": "VPS Provisioning", "status": "in_progress"}, {"name": "Cloudron Installation", "status": "pending"}, {"name": "DNS Configuration", "status": "pending"}, {"name": "Business Setup", "status": "pending"}, }, }) }) } func (suite *IntegrationTestSuite) TestCompleteUserFlow() { t := suite.T() // Step 1: Check API health t.Run("Health Check", func(t *testing.T) { req, _ := http.NewRequest("GET", "/health", nil) w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "ok", response["status"]) }) // Step 2: Check system status t.Run("System Status", func(t *testing.T) { req, _ := http.NewRequest("GET", "/api/status", nil) w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "operational", response["status"]) services := response["services"].(map[string]interface{}) assert.Equal(t, "connected", services["ovh"]) assert.Equal(t, "connected", services["stripe"]) assert.Equal(t, "ready", services["cloudron"]) assert.Equal(t, "connected", services["dolibarr"]) }) // Step 3: Launch new hosting business t.Run("Launch Business", func(t *testing.T) { payload := map[string]string{ "domain": "test-business.com", "email": "customer@example.com", "cardNumber": "4242424242424242", } jsonPayload, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "/api/launch", bytes.NewBuffer(jsonPayload)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) 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)) assert.Equal(t, "test-business.com", response["domain"]) assert.Contains(t, response["customer_id"], "test-customer-") assert.False(t, response["provisioned"].(bool)) }) // Step 4: Check provisioning status t.Run("Check Provisioning Status", func(t *testing.T) { req, _ := http.NewRequest("GET", "/api/status/test-customer-12345", nil) w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "test-customer-12345", response["customer_id"]) assert.Equal(t, "provisioning", response["status"]) assert.Equal(t, float64(25), response["progress"]) steps := response["steps"].([]interface{}) assert.Len(t, steps, 5) // Check first step is completed firstStep := steps[0].(map[string]interface{}) assert.Equal(t, "Domain Registration", firstStep["name"]) assert.Equal(t, "completed", firstStep["status"]) // Check second step is in progress secondStep := steps[1].(map[string]interface{}) assert.Equal(t, "VPS Provisioning", secondStep["name"]) assert.Equal(t, "in_progress", secondStep["status"]) }) } func (suite *IntegrationTestSuite) TestErrorScenarios() { t := suite.T() t.Run("Invalid Launch Request - Missing Domain", func(t *testing.T) { payload := map[string]string{ "email": "customer@example.com", "cardNumber": "4242424242424242", } jsonPayload, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "/api/launch", bytes.NewBuffer(jsonPayload)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.False(t, response["success"].(bool)) }) t.Run("Invalid Launch Request - Bad Email", func(t *testing.T) { payload := map[string]string{ "domain": "test.com", "email": "invalid-email", "cardNumber": "4242424242424242", } jsonPayload, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "/api/launch", bytes.NewBuffer(jsonPayload)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) t.Run("Malformed JSON", func(t *testing.T) { req, _ := http.NewRequest("POST", "/api/launch", bytes.NewBuffer([]byte("{invalid json"))) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) } func (suite *IntegrationTestSuite) TestConcurrency() { t := suite.T() // Simulate multiple concurrent launch requests t.Run("Concurrent Launch Requests", func(t *testing.T) { numRequests := 10 results := make(chan bool, numRequests) for i := 0; i < numRequests; i++ { go func(id int) { payload := map[string]string{ "domain": fmt.Sprintf("test%d.com", id), "email": fmt.Sprintf("user%d@example.com", id), "cardNumber": "4242424242424242", } jsonPayload, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "/api/launch", bytes.NewBuffer(jsonPayload)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) results <- w.Code == http.StatusOK }(i) } // Wait for all requests to complete successCount := 0 for i := 0; i < numRequests; i++ { if <-results { successCount++ } } assert.Equal(t, numRequests, successCount, "All concurrent requests should succeed") }) } func (suite *IntegrationTestSuite) TestResponseHeaders() { t := suite.T() t.Run("CORS Headers", func(t *testing.T) { req, _ := http.NewRequest("GET", "/health", nil) w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin")) assert.Contains(t, w.Header().Get("Access-Control-Allow-Methods"), "GET") assert.Contains(t, w.Header().Get("Access-Control-Allow-Methods"), "POST") }) t.Run("Options Request", func(t *testing.T) { req, _ := http.NewRequest("OPTIONS", "/api/launch", nil) w := httptest.NewRecorder() suite.router.ServeHTTP(w, req) assert.Equal(t, http.StatusNoContent, w.Code) }) } func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) }