package main import ( "bytes" "encoding/json" "fmt" "net/http" "sync" "testing" "time" ) const ( baseURL = "http://localhost:9096" token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMjIyMjIyMjItMjIyMi0yMjIyLTIyMjItMjIyMjIyMjIyMjIyIiwiZW1haWwiOiJlcmlrQGxhbmR2ZXguY29tIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzgyMzQ0MDAwfQ.demo" ) // BenchmarkHealthCheck - simple health endpoint func BenchmarkHealthCheck(b *testing.B) { for i := 0; i < b.N; i++ { resp, err := http.Get(baseURL + "/health") if err != nil { b.Fatal(err) } resp.Body.Close() } } // BenchmarkLogin - auth endpoint func BenchmarkLogin(b *testing.B) { payload := map[string]string{ "email": "erik@landvex.com", "password": "password123", } body, _ := json.Marshal(payload) for i := 0; i < b.N; i++ { resp, err := http.Post(baseURL+"/api/v1/auth/login", "application/json", bytes.NewReader(body)) if err != nil { b.Fatal(err) } resp.Body.Close() } } // BenchmarkDashboard - protected endpoint with analytics func BenchmarkDashboard(b *testing.B) { req, _ := http.NewRequest("GET", baseURL+"/api/v1/analytics/dashboard", nil) req.Header.Set("Authorization", "Bearer "+token) client := &http.Client{Timeout: 5 * time.Second} for i := 0; i < b.N; i++ { resp, err := client.Do(req) if err != nil { b.Fatal(err) } resp.Body.Close() } } // BenchmarkQuotesList - database query func BenchmarkQuotesList(b *testing.B) { req, _ := http.NewRequest("GET", baseURL+"/api/v1/sales/quotes", nil) req.Header.Set("Authorization", "Bearer "+token) client := &http.Client{Timeout: 5 * time.Second} for i := 0; i < b.N; i++ { resp, err := client.Do(req) if err != nil { b.Fatal(err) } resp.Body.Close() } } // Concurrent load test func TestConcurrentLoad(t *testing.T) { concurrency := 50 requests := 100 var wg sync.WaitGroup errors := make(chan error, concurrency*requests) start := time.Now() for i := 0; i < concurrency; i++ { wg.Add(1) go func(worker int) { defer wg.Done() client := &http.Client{Timeout: 5 * time.Second} for j := 0; j < requests; j++ { req, _ := http.NewRequest("GET", baseURL+"/health", nil) resp, err := client.Do(req) if err != nil { errors <- fmt.Errorf("worker %d req %d: %v", worker, j, err) continue } if resp.StatusCode != 200 { errors <- fmt.Errorf("worker %d req %d: status %d", worker, j, resp.StatusCode) } resp.Body.Close() } }(i) } wg.Wait() close(errors) duration := time.Since(start) totalRequests := concurrency * requests rps := float64(totalRequests) / duration.Seconds() errCount := 0 for err := range errors { if errCount < 5 { t.Logf("Error: %v", err) } errCount++ } t.Logf("Total: %d requests in %v (%.0f req/sec)", totalRequests, duration, rps) t.Logf("Errors: %d (%.2f%%)", errCount, float64(errCount)/float64(totalRequests)*100) if errCount > totalRequests/10 { t.Fatalf("Too many errors: %d", errCount) } } // TestFullWorkflow - complete business flow func TestFullWorkflow(t *testing.T) { client := &http.Client{Timeout: 10 * time.Second} // 1. Login loginPayload := map[string]string{ "email": "erik@landvex.com", "password": "password123", } body, _ := json.Marshal(loginPayload) resp, err := client.Post(baseURL+"/api/v1/auth/login", "application/json", bytes.NewReader(body)) if err != nil { t.Fatalf("Login failed: %v", err) } var loginResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&loginResp) resp.Body.Close() authToken, ok := loginResp["token"].(string) if !ok { t.Fatal("No token in response") } t.Logf("✓ Login successful") // 2. Create customer customerPayload := map[string]interface{}{ "name": "Stress Test AB", "email": "stress@test.com", "phone": "+46701234567", "address": "Testgatan 1, Stockholm", } body, _ = json.Marshal(customerPayload) req, _ := http.NewRequest("POST", baseURL+"/api/v1/crm/customers", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+authToken) req.Header.Set("Content-Type", "application/json") resp, err = client.Do(req) if err != nil { t.Fatalf("Create customer failed: %v", err) } var customerResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&customerResp) resp.Body.Close() customerID := customerResp["id"].(string) t.Logf("✓ Customer created: %s", customerID) // 3. Create quote quotePayload := map[string]interface{}{ "customer_id": customerID, "title": "Stress Test Quote", "items": []map[string]interface{}{ { "description": "Test Product", "quantity": 10, "unit_price": 1000.00, "tax_rate": 25.0, }, }, } body, _ = json.Marshal(quotePayload) req, _ = http.NewRequest("POST", baseURL+"/api/v1/sales/quotes", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+authToken) req.Header.Set("Content-Type", "application/json") resp, err = client.Do(req) if err != nil { t.Fatalf("Create quote failed: %v", err) } var quoteResp map[string]interface{} json.NewDecoder(resp.Body).Decode("eResp) resp.Body.Close() quoteID := quoteResp["id"].(string) t.Logf("✓ Quote created: %s", quoteID) // 4. Accept quote req, _ = http.NewRequest("POST", baseURL+"/api/v1/sales/quotes/"+quoteID+"/accept", nil) req.Header.Set("Authorization", "Bearer "+authToken) resp, err = client.Do(req) if err != nil { t.Fatalf("Accept quote failed: %v", err) } resp.Body.Close() t.Logf("✓ Quote accepted") // 5. Convert to order req, _ = http.NewRequest("POST", baseURL+"/api/v1/sales/quotes/"+quoteID+"/convert", nil) req.Header.Set("Authorization", "Bearer "+authToken) resp, err = client.Do(req) if err != nil { t.Fatalf("Convert quote failed: %v", err) } var orderResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&orderResp) resp.Body.Close() t.Logf("✓ Quote converted to order: %s", orderResp["order_id"]) // 6. Get dashboard req, _ = http.NewRequest("GET", baseURL+"/api/v1/analytics/dashboard", nil) req.Header.Set("Authorization", "Bearer "+authToken) resp, err = client.Do(req) if err != nil { t.Fatalf("Dashboard failed: %v", err) } resp.Body.Close() t.Logf("✓ Dashboard loaded") t.Logf("\n=== WORKFLOW COMPLETE ===") } // TestPDFGeneration - stress PDF generation func TestPDFGeneration(t *testing.T) { client := &http.Client{Timeout: 10 * time.Second} // Get existing quote req, _ := http.NewRequest("GET", baseURL+"/api/v1/sales/quotes", nil) req.Header.Set("Authorization", "Bearer "+token) resp, err := client.Do(req) if err != nil { t.Fatalf("List quotes failed: %v", err) } var quotesResp map[string]interface{} json.NewDecoder(resp.Body).Decode("esResp) resp.Body.Close() quotes := quotesResp["quotes"].([]interface{}) if len(quotes) == 0 { t.Skip("No quotes to test") } quoteID := quotes[0].(map[string]interface{})["id"].(string) // Generate PDF start := time.Now() req, _ = http.NewRequest("GET", baseURL+"/api/v1/sales/quotes/"+quoteID+"/pdf", nil) req.Header.Set("Authorization", "Bearer "+token) resp, err = client.Do(req) if err != nil { t.Fatalf("PDF generation failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != 200 { t.Fatalf("PDF generation returned %d", resp.StatusCode) } duration := time.Since(start) t.Logf("✓ PDF generated in %v (status: %d, content-type: %s)", duration, resp.StatusCode, resp.Header.Get("Content-Type")) }