Spaces:
Paused
Paused
| /** | |
| * Load Test Configuration for PRIX | |
| * Simulates 500 concurrent users hitting the webhook endpoint | |
| * | |
| * Prerequisites: | |
| * npm install -g k6 | |
| * k6 login cloud (optional for trending) | |
| * | |
| * Usage: | |
| * k6 run scripts/load-test.js | |
| * k6 run --vus 500 --duration 60s scripts/load-test.js | |
| * k6 run --stage rps:10-50:30s,rps:50-100:60s scripts/load-test.js | |
| */ | |
| import http from 'k6/http'; | |
| import { check, sleep, group } from 'k6'; | |
| import { Rate, Trend } from 'k6/metrics'; | |
| // Custom metrics | |
| const errorRate = new Rate('errors'); | |
| const responseTime = new Trend('response_time'); | |
| const webhookSuccess = new Trend('webhook_success'); | |
| const healthCheckTime = new Trend('health_check_time'); | |
| // Test configuration | |
| export const options = { | |
| scenarios: { | |
| // Warmup scenario | |
| warmup: { | |
| executor: 'ramping-arrival-rate', | |
| duration: '30s', | |
| preAllocatedVUs: 50, | |
| maxVUs: 100, | |
| stages: [ | |
| { duration: '10s', target: 10 }, | |
| { duration: '20s', target: 50 }, | |
| ], | |
| }, | |
| // Main load test - 500 concurrent users | |
| load_test: { | |
| executor: 'ramping-vus', | |
| duration: '2m', | |
| maxVUs: 500, | |
| stages: [ | |
| { duration: '30s', target: 100 }, | |
| { duration: '30s', target: 250 }, | |
| { duration: '30s', target: 500 }, | |
| { duration: '30s', target: 500 }, // Hold at 500 | |
| { duration: '30s', target: 0 }, // Ramp down | |
| ], | |
| }, | |
| }, | |
| thresholds: { | |
| http_req_duration: ['p(95)<5000'], // 95% of requests under 5s | |
| http_req_failed: ['rate<0.1'], // Less than 10% failure | |
| errors: ['rate<0.05'], // Less than 5% error rate | |
| webhook_success: ['p(90)<10000'], // 90% of webhooks complete in 10s | |
| }, | |
| }; | |
| // Test data generation | |
| function generateMockGitHubPayload(prNumber) { | |
| const timestamp = Date.now(); | |
| return { | |
| action: 'opened', | |
| number: prNumber, | |
| pull_request: { | |
| number: prNumber, | |
| title: `Load test PR #${prNumber} - ${timestamp}`, | |
| body: 'This is a load test pull request for performance testing', | |
| state: 'open', | |
| user: { | |
| login: `loadtest-user-${prNumber % 100}`, | |
| id: 1000 + (prNumber % 100), | |
| }, | |
| base: { | |
| ref: 'main', | |
| sha: '136795cc20e35ffa9a345771e8eeaaf4bce69ae2', | |
| }, | |
| head: { | |
| ref: `feature/load-test-${prNumber}`, | |
| sha: `${timestamp.toString(16)}`, | |
| }, | |
| }, | |
| repository: { | |
| id: 123456, | |
| name: 'TEST-PRIX', | |
| full_name: 'Rachit-Tiwari-7/TEST-PRIX', | |
| owner: { | |
| login: 'Rachit-Tiwari-7', | |
| id: 789, | |
| }, | |
| }, | |
| installation: { | |
| id: 12345, | |
| }, | |
| }; | |
| } | |
| // Simulated PR file changes | |
| function generateMockFileChanges() { | |
| return [ | |
| { | |
| filename: 'test-file.js', | |
| status: 'modified', | |
| additions: 5, | |
| deletions: 2, | |
| changes: 7, | |
| patch: `@@ -1,3 +1,6 @@ | |
| const x = 1; | |
| const y = 2; | |
| +const z = 3; | |
| +const w = 4; | |
| function calculate() { | |
| return x + y; | |
| } | |
| +function extra() { return z + w; }`, | |
| }, | |
| { | |
| filename: 'calc.py', | |
| status: 'modified', | |
| additions: 2, | |
| deletions: 1, | |
| changes: 3, | |
| patch: `@@ -1,5 +1,6 @@ | |
| if __name__ == "__main__": | |
| print(f"Addition: {add(10, 5)}") | |
| - print(f"Division: {divide(10, 5)}") | |
| + print(f"Division: {divide(10, 5)}") | |
| + print("Load test line") | |
| result = add(5, 3)`, | |
| }, | |
| ]; | |
| } | |
| // Default function - main test loop | |
| export default function () { | |
| const baseUrl = __ENV.TARGET_URL || 'http://localhost:7860'; | |
| const githubToken = __ENV.GITHUB_TOKEN || 'test-token'; | |
| // Health check | |
| group('Health Check', () => { | |
| const healthStart = Date.now(); | |
| const healthRes = http.get(`${baseUrl}/ping`, { | |
| headers: { 'Content-Type': 'application/json' }, | |
| }); | |
| healthCheckTime.add(Date.now() - healthStart); | |
| check(healthRes, { | |
| 'health check status is 200': (r) => r.status === 200, | |
| 'health check has correct response': (r) => r.body.includes('pong') || r.status === 200, | |
| }); | |
| }); | |
| // Simulate webhook payload | |
| group('Webhook Delivery', () => { | |
| const prNumber = 10000 + Math.floor(Math.random() * 1000); | |
| const payload = generateMockGitHubPayload(prNumber); | |
| const files = generateMockFileChanges(); | |
| // Mock GitHub API responses | |
| const mockGitHubResponses = { | |
| 'repos/compareCommits': { | |
| files: files, | |
| commits: [{ sha: 'commit-1' }, { sha: 'commit-2' }], | |
| }, | |
| 'repos/getContent': { | |
| content: Buffer.from('const existing = true;').toString('base64'), | |
| encoding: 'base64', | |
| }, | |
| }; | |
| const webhookStart = Date.now(); | |
| // Note: In real load test against production, you'd hit the actual webhook endpoint | |
| // For local testing, we simulate the webhook processing | |
| const webhookRes = http.post( | |
| `${baseUrl}/api/github/webhooks`, | |
| JSON.stringify(payload), | |
| { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'X-GitHub-Event': 'pull_request', | |
| 'X-GitHub-Delivery': `${Date.now()}`, | |
| 'X-Hub-Signature-256': 'sha256=test-signature', | |
| }, | |
| } | |
| ); | |
| webhookSuccess.add(Date.now() - webhookStart); | |
| responseTime.add(Date.now() - webhookStart); | |
| const isSuccess = check(webhookRes, { | |
| 'webhook status is 200': (r) => r.status === 200, | |
| 'webhook response time < 5s': (r) => r.timings.duration < 5000, | |
| }); | |
| errorRate.add(!isSuccess); | |
| }); | |
| // Random think time between requests (1-3 seconds) | |
| sleep(Math.random() * 2 + 1); | |
| } | |
| // Setup function - runs once before test | |
| export function setup() { | |
| console.log('Starting PRIX Load Test'); | |
| console.log(`Target URL: ${__ENV.TARGET_URL || 'http://localhost:7860'}`); | |
| console.log('Simulating 500 concurrent users...'); | |
| return { startTime: Date.now() }; | |
| } | |
| // Teardown function - runs once after test | |
| export function teardown(data) { | |
| console.log('Load Test Complete'); | |
| console.log(`Total Duration: ${(Date.now() - data.startTime) / 1000}s`); | |
| } |