Skip to content

Commit e001918

Browse files
committed
update
Signed-off-by: bitliu <[email protected]>
1 parent 1162445 commit e001918

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed

e2e/testcases/stress_test.go

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package testcases
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"net/http"
10+
"strings"
11+
"time"
12+
13+
pkgtestcases "github.com/vllm-project/semantic-router/e2e/pkg/testcases"
14+
"k8s.io/client-go/kubernetes"
15+
)
16+
17+
func init() {
18+
pkgtestcases.Register("stress-test", pkgtestcases.TestCase{
19+
Description: "Send 1000 sequential requests and measure success rate",
20+
Tags: []string{"llm", "stress", "reliability"},
21+
Fn: testStressTest,
22+
})
23+
}
24+
25+
// StressTestResult tracks the result of a single request
26+
type StressTestResult struct {
27+
RequestID int
28+
Success bool
29+
StatusCode int
30+
Duration time.Duration
31+
ErrorMessage string
32+
}
33+
34+
func testStressTest(ctx context.Context, client *kubernetes.Clientset, opts pkgtestcases.TestCaseOptions) error {
35+
if opts.Verbose {
36+
fmt.Println("[Test] Starting stress test: 1000 sequential requests")
37+
}
38+
39+
// Setup service connection and get local port
40+
localPort, stopPortForward, err := setupServiceConnection(ctx, client, opts)
41+
if err != nil {
42+
return err
43+
}
44+
defer stopPortForward() // Ensure port forwarding is stopped when test completes
45+
46+
const totalRequests = 1000
47+
var results []StressTestResult
48+
successCount := 0
49+
totalDuration := time.Duration(0)
50+
51+
// Send 1000 requests sequentially
52+
for i := 1; i <= totalRequests; i++ {
53+
result := sendSingleRequest(ctx, i, localPort, opts.Verbose)
54+
results = append(results, result)
55+
56+
if result.Success {
57+
successCount++
58+
}
59+
totalDuration += result.Duration
60+
61+
// Print progress every 100 requests
62+
if opts.Verbose && i%100 == 0 {
63+
currentSuccessRate := float64(successCount) / float64(i) * 100
64+
fmt.Printf("[Test] Progress: %d/%d requests completed (%.2f%% success rate)\n",
65+
i, totalRequests, currentSuccessRate)
66+
}
67+
}
68+
69+
// Calculate statistics
70+
successRate := float64(successCount) / float64(totalRequests) * 100
71+
failureCount := totalRequests - successCount
72+
avgDuration := totalDuration / time.Duration(totalRequests)
73+
74+
// Set details for reporting
75+
if opts.SetDetails != nil {
76+
opts.SetDetails(map[string]interface{}{
77+
"total_requests": totalRequests,
78+
"successful": successCount,
79+
"failed": failureCount,
80+
"success_rate": fmt.Sprintf("%.2f%%", successRate),
81+
"avg_duration_ms": avgDuration.Milliseconds(),
82+
})
83+
}
84+
85+
// Print summary
86+
printStressTestResults(results, totalRequests, successCount, successRate, avgDuration)
87+
88+
if opts.Verbose {
89+
fmt.Printf("[Test] Stress test completed: %d/%d successful (%.2f%% success rate)\n",
90+
successCount, totalRequests, successRate)
91+
}
92+
93+
return nil
94+
}
95+
96+
func sendSingleRequest(ctx context.Context, requestID int, localPort string, verbose bool) StressTestResult {
97+
result := StressTestResult{
98+
RequestID: requestID,
99+
Success: false,
100+
}
101+
102+
start := time.Now()
103+
104+
// Prepare request body
105+
requestBody := map[string]interface{}{
106+
"model": "MoM",
107+
"messages": []map[string]string{
108+
{
109+
"role": "user",
110+
"content": fmt.Sprintf("Request #%d: What is 2+2?", requestID),
111+
},
112+
},
113+
}
114+
115+
jsonData, err := json.Marshal(requestBody)
116+
if err != nil {
117+
result.ErrorMessage = fmt.Sprintf("marshal error: %v", err)
118+
result.Duration = time.Since(start)
119+
return result
120+
}
121+
122+
url := fmt.Sprintf("http://localhost:%s/v1/chat/completions", localPort)
123+
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
124+
if err != nil {
125+
result.ErrorMessage = fmt.Sprintf("create request error: %v", err)
126+
result.Duration = time.Since(start)
127+
return result
128+
}
129+
130+
req.Header.Set("Content-Type", "application/json")
131+
132+
httpClient := &http.Client{
133+
Timeout: 30 * time.Second,
134+
}
135+
136+
resp, err := httpClient.Do(req)
137+
if err != nil {
138+
result.ErrorMessage = fmt.Sprintf("send request error: %v", err)
139+
result.Duration = time.Since(start)
140+
return result
141+
}
142+
defer resp.Body.Close()
143+
144+
body, err := io.ReadAll(resp.Body)
145+
if err != nil {
146+
result.ErrorMessage = fmt.Sprintf("read response error: %v", err)
147+
result.Duration = time.Since(start)
148+
result.StatusCode = resp.StatusCode
149+
return result
150+
}
151+
152+
result.Duration = time.Since(start)
153+
result.StatusCode = resp.StatusCode
154+
155+
if resp.StatusCode == http.StatusOK {
156+
result.Success = true
157+
} else {
158+
result.ErrorMessage = fmt.Sprintf("status %d: %s", resp.StatusCode, string(body))
159+
}
160+
161+
return result
162+
}
163+
164+
func printStressTestResults(results []StressTestResult, totalRequests, successCount int, successRate float64, avgDuration time.Duration) {
165+
separator := strings.Repeat("=", 80)
166+
fmt.Println("\n" + separator)
167+
fmt.Println("Stress Test Results")
168+
fmt.Println(separator)
169+
fmt.Printf("Total Requests: %d\n", totalRequests)
170+
fmt.Printf("Successful: %d\n", successCount)
171+
fmt.Printf("Failed: %d\n", totalRequests-successCount)
172+
fmt.Printf("Success Rate: %.2f%%\n", successRate)
173+
fmt.Printf("Average Duration: %v\n", avgDuration)
174+
fmt.Println(separator)
175+
176+
// Show first 10 failures if any
177+
failureCount := 0
178+
fmt.Println("\nFirst 10 Failures (if any):")
179+
for _, result := range results {
180+
if !result.Success && failureCount < 10 {
181+
failureCount++
182+
fmt.Printf(" Request #%d: %s (duration: %v)\n",
183+
result.RequestID, result.ErrorMessage, result.Duration)
184+
}
185+
if failureCount >= 10 {
186+
break
187+
}
188+
}
189+
190+
if failureCount == 0 {
191+
fmt.Println(" No failures! 🎉")
192+
}
193+
fmt.Println()
194+
}

0 commit comments

Comments
 (0)