Implement Sprint 1 stories: collections, RBAC, audit logging, load testing
Complete 6 Sprint 1 stories for Epic 1 web migration infrastructure. Portfolio Collection: - Add 7 fields: title, slug, url, image, description, websiteType, tags - Configure R2 storage and authenticated access control Categories Collection: - Add nameEn, order, textColor, backgroundColor fields - Add color picker UI configuration Posts Collection: - Add excerpt with 200 char limit and ogImage for social sharing - Add showInFooter checkbox and status select (draft/review/published) Role-Based Access Control: - Add role field to Users collection (admin/editor) - Create adminOnly and authenticated access functions - Apply access rules to Portfolio, Categories, Posts, Users collections Audit Logging System (NFR9): - Create Audit collection with timestamps for 90-day retention - Add auditLogger utility for login/logout/content change tracking - Add auditChange and auditGlobalChange hooks to all collections and globals - Add cleanupAuditLogs job with 90-day retention policy Load Testing Framework (NFR4): - Add k6 load testing with 3 scripts: public-browsing, admin-operations, api-performance - Configure targets: p95 < 500ms, error rate < 1%, 100 concurrent users - Add verification script and comprehensive documentation Other Changes: - Remove unused Form blocks - Add Header/Footer audit hooks - Regenerate Payload TypeScript types
This commit is contained in:
294
apps/backend/tests/k6/README.md
Normal file
294
apps/backend/tests/k6/README.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# K6 Load Testing Framework
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains load testing scripts for the Enchun CMS backend using k6. The tests are designed to validate the non-functional requirement NFR4:
|
||||
|
||||
- **Target:** p95 response time < 500ms
|
||||
- **Error rate:** < 1%
|
||||
- **Concurrent users:** 100
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Install k6:**
|
||||
```bash
|
||||
# macOS
|
||||
brew install k6
|
||||
|
||||
# Linux
|
||||
sudo apt-get install k6
|
||||
|
||||
# Windows (using Chocolatey)
|
||||
choco install k6
|
||||
```
|
||||
|
||||
2. **Set up environment:**
|
||||
```bash
|
||||
cp .env.example .env.k6
|
||||
# Edit .env.k6 with your test environment credentials
|
||||
```
|
||||
|
||||
## Test Scripts
|
||||
|
||||
### 1. Public Browsing Test (`public-browsing.js`)
|
||||
|
||||
Simulates 100 concurrent users browsing public pages:
|
||||
- Homepage
|
||||
- About page
|
||||
- Solutions page
|
||||
- Portfolio list
|
||||
- Blog list
|
||||
- Contact page
|
||||
|
||||
**Run:**
|
||||
```bash
|
||||
k6 run --env BASE_URL=http://localhost:3000 tests/k6/public-browsing.js
|
||||
```
|
||||
|
||||
**Expected Results:**
|
||||
- p95 response time < 500ms
|
||||
- Error rate < 1%
|
||||
- 100 concurrent users sustained for 2 minutes
|
||||
|
||||
### 2. Admin Operations Test (`admin-operations.js`)
|
||||
|
||||
Simulates 20 concurrent admin users performing:
|
||||
- Login
|
||||
- List pages/posts
|
||||
- Create/edit content
|
||||
- Delete content
|
||||
|
||||
**Run:**
|
||||
```bash
|
||||
k6 run --env BASE_URL=http://localhost:3000 \
|
||||
--env ADMIN_EMAIL=admin@example.com \
|
||||
--env ADMIN_PASSWORD=password123 \
|
||||
tests/k6/admin-operations.js
|
||||
```
|
||||
|
||||
**Expected Results:**
|
||||
- p95 response time < 500ms
|
||||
- Error rate < 1%
|
||||
- 20 concurrent users sustained for 3 minutes
|
||||
|
||||
### 3. API Performance Test (`api-performance.js`)
|
||||
|
||||
Tests specific API endpoints:
|
||||
- GraphQL API queries
|
||||
- REST API endpoints
|
||||
- Global API endpoint
|
||||
|
||||
**Run:**
|
||||
```bash
|
||||
k6 run --env BASE_URL=http://localhost:3000 tests/k6/api-performance.js
|
||||
```
|
||||
|
||||
**Expected Results:**
|
||||
- p95 response time < 300ms (faster for API)
|
||||
- Error rate < 0.5%
|
||||
- Throughput > 100 requests/second
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default | Required |
|
||||
|----------|-------------|---------|----------|
|
||||
| `BASE_URL` | Target server URL | `http://localhost:3000` | Yes |
|
||||
| `ADMIN_EMAIL` | Admin user email | - | For admin tests |
|
||||
| `ADMIN_PASSWORD` | Admin user password | - | For admin tests |
|
||||
| `VUS` | Number of virtual users | Varies per test | No |
|
||||
| `DURATION` | Test duration | Varies per test | No |
|
||||
|
||||
### Load Profiles
|
||||
|
||||
Each test uses different load profiles:
|
||||
|
||||
| Test | Virtual Users | Duration | Ramp Up |
|
||||
|------|--------------|----------|---------|
|
||||
| Public Browsing | 100 | 2m | 30s |
|
||||
| Admin Operations | 20 | 3m | 30s |
|
||||
| API Performance | 50 | 5m | 1m |
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Run Single Test
|
||||
|
||||
```bash
|
||||
# Basic run
|
||||
k6 run tests/k6/public-browsing.js
|
||||
|
||||
# With custom environment
|
||||
k6 run --env BASE_URL=https://staging.enchun.tw tests/k6/public-browsing.js
|
||||
|
||||
# With custom stages
|
||||
k6 run --env STAGED_USERS=200 --env STAGED_DURATION=10m tests/k6/public-browsing.js
|
||||
```
|
||||
|
||||
### Run All Tests
|
||||
|
||||
```bash
|
||||
# Using the npm script
|
||||
pnpm test:load
|
||||
|
||||
# Or manually
|
||||
k6 run tests/k6/public-browsing.js
|
||||
k6 run tests/k6/admin-operations.js
|
||||
k6 run tests/k6/api-performance.js
|
||||
```
|
||||
|
||||
### Run with Output Options
|
||||
|
||||
```bash
|
||||
# Generate JSON report
|
||||
k6 run --out json=results.json tests/k6/public-browsing.js
|
||||
|
||||
# Generate HTML report (requires k6-reporter)
|
||||
k6 run --out json=results.json tests/k6/public-browsing.js
|
||||
k6-reporter results.json --output results.html
|
||||
```
|
||||
|
||||
## Interpreting Results
|
||||
|
||||
### Key Metrics
|
||||
|
||||
1. **Response Time (p95):** 95th percentile response time
|
||||
- ✅ Pass: < 500ms
|
||||
- ❌ Fail: >= 500ms
|
||||
|
||||
2. **Error Rate:** Percentage of failed requests
|
||||
- ✅ Pass: < 1%
|
||||
- ❌ Fail: >= 1%
|
||||
|
||||
3. **Throughput:** Requests per second
|
||||
- ✅ Pass: > 100 req/s for API, > 50 req/s for pages
|
||||
- ❌ Fail: Below threshold
|
||||
|
||||
4. **Virtual Users (VUs):** Active concurrent users
|
||||
- Should sustain target VUs for the full duration
|
||||
|
||||
### Example Output
|
||||
|
||||
```
|
||||
✓ Status is 200
|
||||
✓ Response time < 500ms
|
||||
✓ Page content loaded
|
||||
|
||||
checks.........................: 100.0% ✓ 12000 ✗ 0
|
||||
data_received..................: 15 MB 125 kB/s
|
||||
data_sent......................: 2.1 MB 18 kB/s
|
||||
http_req_blocked...............: avg=1.2ms min=0.5µs med=1µs max=125ms
|
||||
http_req_connecting............: avg=500µs min=0s med=0s max=45ms
|
||||
http_req_duration..............: avg=185.3ms min=45ms med=150ms max=850ms p(95)=420ms
|
||||
http_req_failed................: 0.00% ✓ 0 ✗ 12000
|
||||
http_req_receiving.............: avg=15ms min=10µs med=50µs max=250ms
|
||||
http_req_sending...............: avg=50µs min=5µs med=20µs max=5ms
|
||||
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s
|
||||
http_req_waiting...............: avg=170ms min=40ms med=140ms max=800ms
|
||||
http_reqs......................: 12000 100 req/s
|
||||
iteration_duration.............: avg=5.2s min=1.2s med=5s max=12s
|
||||
iterations.....................: 2400 20 /s
|
||||
vus............................: 100 min=100 max=100
|
||||
vus_max........................: 100 min=100 max=100
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
name: Load Tests
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # Daily at 2 AM
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
k6:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: grafana/k6-action@v0.3.1
|
||||
with:
|
||||
filename: tests/k6/public-browsing.js
|
||||
env:
|
||||
BASE_URL: ${{ secrets.STAGING_URL }}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Refused
|
||||
|
||||
**Error:** `connect attempt failed`
|
||||
|
||||
**Solution:**
|
||||
- Ensure the backend server is running
|
||||
- Check `BASE_URL` is correct
|
||||
- Verify firewall settings
|
||||
|
||||
### High Error Rate
|
||||
|
||||
**Error:** `http_req_failed > 1%`
|
||||
|
||||
**Possible Causes:**
|
||||
1. Server overload (reduce VUs)
|
||||
2. Database connection issues
|
||||
3. Authentication failures
|
||||
4. Network issues
|
||||
|
||||
**Debug:**
|
||||
```bash
|
||||
# Run with fewer users
|
||||
k6 run --env STAGED_USERS=10 tests/k6/public-browsing.js
|
||||
|
||||
# Check server logs
|
||||
pnpm dev
|
||||
# In another terminal, watch logs while tests run
|
||||
```
|
||||
|
||||
### Slow Response Times
|
||||
|
||||
**Error:** `p(95) >= 500ms`
|
||||
|
||||
**Possible Causes:**
|
||||
1. Unoptimized database queries
|
||||
2. Missing indexes
|
||||
3. Large payloads
|
||||
4. Server resource constraints
|
||||
|
||||
**Next Steps:**
|
||||
1. Review database queries
|
||||
2. Check caching strategies
|
||||
3. Optimize images/assets
|
||||
4. Scale server resources
|
||||
|
||||
## Performance Baseline
|
||||
|
||||
Initial baseline (to be established):
|
||||
|
||||
| Test | p95 (ms) | Error Rate | Throughput |
|
||||
|------|----------|------------|------------|
|
||||
| Public Browsing | TBD | TBD | TBD |
|
||||
| Admin Operations | TBD | TBD | TBD |
|
||||
| API Performance | TBD | TBD | TBD |
|
||||
|
||||
Update this table after first test run to establish baseline.
|
||||
|
||||
## Resources
|
||||
|
||||
- [k6 Documentation](https://k6.io/docs/)
|
||||
- [k6 Metrics](https://k6.io/docs/using-k6/metrics/)
|
||||
- [Payload CMS Performance](https://payloadcms.com/docs/admin/configuration)
|
||||
- [Web Vitals](https://web.dev/vitals/)
|
||||
|
||||
## Maintenance
|
||||
|
||||
- Review and update test scenarios quarterly
|
||||
- Adjust load profiles based on real traffic patterns
|
||||
- Update thresholds based on business requirements
|
||||
- Add new tests for new features
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-01-31
|
||||
**Owner:** QA Team
|
||||
Reference in New Issue
Block a user