|
| 1 | +# Load Testing |
| 2 | + |
| 3 | +k6-based load testing for the Wayfarer GraphQL API. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +1. Install k6: |
| 8 | + ```bash |
| 9 | + brew install k6 # macOS |
| 10 | + # or see https://k6.io/docs/getting-started/installation/ |
| 11 | + ``` |
| 12 | + |
| 13 | +2. Seed the database with test users: |
| 14 | + ```bash |
| 15 | + make seed-large # Creates 10k users |
| 16 | + ``` |
| 17 | + |
| 18 | +3. Start the server: |
| 19 | + ```bash |
| 20 | + make dev |
| 21 | + ``` |
| 22 | + |
| 23 | +## Quick Start |
| 24 | + |
| 25 | +```bash |
| 26 | +# Run the default load test (50 VUs, 5 minutes) |
| 27 | +make loadtest |
| 28 | + |
| 29 | +# Run a quick sanity check (10 VUs, 1 minute) |
| 30 | +make loadtest-quick |
| 31 | +``` |
| 32 | + |
| 33 | +## Available Commands |
| 34 | + |
| 35 | +| Command | Description | |
| 36 | +|---------|-------------| |
| 37 | +| `make loadtest` | Default load test: 50 VUs for 5 minutes | |
| 38 | +| `make loadtest-quick` | Quick test: 10 VUs for 1 minute | |
| 39 | +| `make loadtest-stress` | Stress test: 200 VUs for 10 minutes | |
| 40 | +| `make loadtest-spike` | Spike test only: ramp 0 -> 500 -> 0 VUs | |
| 41 | +| `make loadtest-leaderboard` | Leaderboard stress: 100 requests/second | |
| 42 | +| `make loadtest-gen` | Generate tokens only (1000 users) | |
| 43 | +| `make loadtest-gen-all` | Generate tokens for all users (up to 10k) | |
| 44 | + |
| 45 | +## Test Scenarios |
| 46 | + |
| 47 | +### 1. Steady Load (`steady_load`) |
| 48 | +Simulates typical user traffic with weighted distribution: |
| 49 | +- 30% ChallengesPage |
| 50 | +- 20% ProfilePage |
| 51 | +- 20% StandingsGlobalPage |
| 52 | +- 15% StandingsLocalPage |
| 53 | +- 15% StandingsUnitPage |
| 54 | + |
| 55 | +### 2. Spike Test (`spike_test`) |
| 56 | +Simulates sudden traffic surges: |
| 57 | +- Ramps from 0 to 100 VUs in 30s |
| 58 | +- Peaks at 500 VUs for 1 minute |
| 59 | +- Ramps down to 0 over 1 minute |
| 60 | + |
| 61 | +### 3. Leaderboard Stress (`leaderboard_stress`) |
| 62 | +Focused testing of database-intensive leaderboard queries: |
| 63 | +- Constant 100 requests/second |
| 64 | +- 50% global standings, 30% local, 20% team |
| 65 | + |
| 66 | +## Configuration |
| 67 | + |
| 68 | +### Environment Variables |
| 69 | + |
| 70 | +| Variable | Default | Description | |
| 71 | +|----------|---------|-------------| |
| 72 | +| `STEADY_VUS` | 50 | Virtual users for steady-state test | |
| 73 | +| `DURATION` | 5m | Duration of steady-state test | |
| 74 | +| `SPIKE_START` | 6m | When spike test starts | |
| 75 | +| `SPIKE_PEAK` | 500 | Peak VUs during spike | |
| 76 | +| `LEADERBOARD_START` | 0s | When leaderboard test starts | |
| 77 | +| `LEADERBOARD_DURATION` | 5m | Duration of leaderboard test | |
| 78 | +| `LEADERBOARD_RPS` | 100 | Requests per second | |
| 79 | + |
| 80 | +### Token Generator Flags |
| 81 | + |
| 82 | +```bash |
| 83 | +go run ./cmd/loadtest/tokengen \ |
| 84 | + -limit 1000 \ # Number of users |
| 85 | + -output config.json \ # Output file |
| 86 | + -base-url http://localhost:8080 \ # API URL |
| 87 | + -valid-days 7 \ # Token validity |
| 88 | + -secret "your-jwt-secret" # Override JWT_SECRET |
| 89 | +``` |
| 90 | + |
| 91 | +## Thresholds |
| 92 | + |
| 93 | +The test will fail if: |
| 94 | +- p95 response time > 500ms |
| 95 | +- p99 response time > 1000ms |
| 96 | +- Error rate > 1% |
| 97 | +- GraphQL error rate > 1% |
| 98 | + |
| 99 | +## Custom Test Runs |
| 100 | + |
| 101 | +```bash |
| 102 | +# Run with custom parameters |
| 103 | +k6 run --env STEADY_VUS=100 --env DURATION=10m ./cmd/loadtest/k6/scenarios.js |
| 104 | + |
| 105 | +# Run against a different target |
| 106 | +go run ./cmd/loadtest/tokengen -base-url https://staging.api.example.com -output ./cmd/loadtest/config.json |
| 107 | +k6 run ./cmd/loadtest/k6/scenarios.js |
| 108 | + |
| 109 | +# Output JSON results |
| 110 | +k6 run --out json=results.json ./cmd/loadtest/k6/scenarios.js |
| 111 | +``` |
| 112 | + |
| 113 | +## Output Metrics |
| 114 | + |
| 115 | +Key metrics to watch: |
| 116 | +- `http_req_duration` - Request latency (p50, p95, p99) |
| 117 | +- `http_req_failed` - Failed request percentage |
| 118 | +- `graphql_errors` - GraphQL-specific errors |
| 119 | +- `http_reqs` - Total requests per second |
| 120 | +- `vus` - Active virtual users |
| 121 | + |
| 122 | +## Files |
| 123 | + |
| 124 | +``` |
| 125 | +cmd/loadtest/ |
| 126 | + tokengen/ |
| 127 | + main.go # Go tool to generate JWT tokens |
| 128 | + k6/ |
| 129 | + scenarios.js # Main test script |
| 130 | + lib/ |
| 131 | + graphql.js # GraphQL HTTP helpers |
| 132 | + queries/ |
| 133 | + challenges.js |
| 134 | + profile.js |
| 135 | + standings-global.js |
| 136 | + standings-local.js |
| 137 | + standings-unit.js |
| 138 | + challenge.js |
| 139 | + config.json # Generated tokens (gitignored) |
| 140 | + README.md |
| 141 | +``` |
0 commit comments