Skip to content

Commit 22c1f0d

Browse files
author
llins
authored
Merge pull request #238 from Oluwaseyi89/feature/Load-Testing-and-Performance-Optimization
feat: performance optimization, code formatting, and test suite reconciliation
2 parents 3e006f4 + 9c3ecf9 commit 22c1f0d

304 files changed

Lines changed: 9071 additions & 6318 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/performance.yml

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name: Performance Testing
33
on:
44
pull_request:
55
branches: [main]
6+
workflow_dispatch:
67

78
permissions:
89
contents: read
@@ -14,6 +15,167 @@ concurrency:
1415
cancel-in-progress: true
1516

1617
jobs:
18+
load-testing:
19+
name: k6 Load Testing
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 25
22+
services:
23+
postgres:
24+
image: postgres:15
25+
env:
26+
POSTGRES_DB: petchain
27+
POSTGRES_USER: postgres
28+
POSTGRES_PASSWORD: postgres
29+
ports:
30+
- 5432:5432
31+
options: >-
32+
--health-cmd "pg_isready -U postgres -d petchain"
33+
--health-interval 10s
34+
--health-timeout 5s
35+
--health-retries 10
36+
redis:
37+
image: redis:7
38+
ports:
39+
- 6379:6379
40+
options: >-
41+
--health-cmd "redis-cli ping"
42+
--health-interval 10s
43+
--health-timeout 5s
44+
--health-retries 10
45+
steps:
46+
- name: Checkout code
47+
uses: actions/checkout@v4
48+
49+
- name: Setup Node.js
50+
uses: actions/setup-node@v4
51+
with:
52+
node-version: 20
53+
cache: npm
54+
55+
- name: Install dependencies
56+
run: npm ci
57+
58+
- name: Install backend dependencies
59+
run: npm --prefix backend ci
60+
61+
- name: Build Next.js
62+
run: npm run build
63+
64+
- name: Build backend
65+
run: npm --prefix backend run build
66+
67+
- name: Start backend server
68+
env:
69+
NODE_ENV: production
70+
PORT: 3001
71+
API_PREFIX: api/v1
72+
DB_HOST: 127.0.0.1
73+
DB_PORT: 5432
74+
DB_USERNAME: postgres
75+
DB_PASSWORD: postgres
76+
DB_DATABASE: petchain
77+
DB_SYNCHRONIZE: "true"
78+
DB_LOGGING: "false"
79+
REDIS_HOST: 127.0.0.1
80+
REDIS_PORT: 6379
81+
JWT_SECRET: perf-test-jwt-secret-32-chars-min
82+
FIELD_ENCRYPTION_KEY: perf-test-field-encryption-key
83+
FILE_ENCRYPTION_KEY: perf-test-file-encryption-key
84+
run: |
85+
npm --prefix backend run start:prod > backend-server.log 2>&1 &
86+
echo $! > backend-server.pid
87+
88+
- name: Start production server
89+
run: |
90+
npx next start -H 127.0.0.1 -p 3000 > next-server.log 2>&1 &
91+
echo $! > next-server.pid
92+
93+
- name: Wait for backend server
94+
run: |
95+
for attempt in {1..45}; do
96+
if curl -fsS http://127.0.0.1:3001/api/v1/observability/health > /dev/null; then
97+
exit 0
98+
fi
99+
sleep 2
100+
done
101+
echo "Backend server did not start in time" >&2
102+
cat backend-server.log >&2
103+
exit 1
104+
105+
- name: Wait for server
106+
run: |
107+
for attempt in {1..30}; do
108+
if curl -fsS http://127.0.0.1:3000 > /dev/null; then
109+
exit 0
110+
fi
111+
sleep 2
112+
done
113+
echo "Next.js server did not start in time" >&2
114+
cat next-server.log >&2
115+
exit 1
116+
117+
- name: Setup k6
118+
uses: grafana/setup-k6-action@v1
119+
120+
- name: Run smoke profile
121+
run: |
122+
mkdir -p performance/results
123+
k6 run \
124+
--summary-export performance/results/smoke-summary.json \
125+
-e TARGET_FRONTEND_URL=http://127.0.0.1:3000 \
126+
-e TARGET_API_URL=http://127.0.0.1:3001/api/v1 \
127+
performance/k6/smoke.js
128+
129+
- name: Run load profile
130+
run: |
131+
k6 run \
132+
--summary-export performance/results/load-summary.json \
133+
-e TARGET_FRONTEND_URL=http://127.0.0.1:3000 \
134+
-e TARGET_API_URL=http://127.0.0.1:3001/api/v1 \
135+
performance/k6/load.js
136+
137+
- name: Enforce baseline regression gate
138+
run: |
139+
node performance/scripts/compare-baseline.mjs \
140+
performance/results/load-summary.json \
141+
performance/baselines/load-summary-baseline.json \
142+
0.15
143+
144+
- name: Publish benchmark summary
145+
run: |
146+
echo "## k6 Smoke Report" >> "$GITHUB_STEP_SUMMARY"
147+
node performance/scripts/benchmark-report.mjs performance/results/smoke-summary.json >> "$GITHUB_STEP_SUMMARY"
148+
echo >> "$GITHUB_STEP_SUMMARY"
149+
echo "## k6 Load Report" >> "$GITHUB_STEP_SUMMARY"
150+
node performance/scripts/benchmark-report.mjs performance/results/load-summary.json >> "$GITHUB_STEP_SUMMARY"
151+
echo >> "$GITHUB_STEP_SUMMARY"
152+
echo "## Baseline Regression Check" >> "$GITHUB_STEP_SUMMARY"
153+
node performance/scripts/compare-baseline.mjs \
154+
performance/results/load-summary.json \
155+
performance/baselines/load-summary-baseline.json \
156+
0.15 \
157+
--summary-only >> "$GITHUB_STEP_SUMMARY"
158+
159+
- name: Upload load test artifacts
160+
uses: actions/upload-artifact@v4
161+
with:
162+
name: k6-performance-results
163+
path: |
164+
performance/results/*.json
165+
next-server.log
166+
backend-server.log
167+
retention-days: 14
168+
169+
- name: Stop production server
170+
if: always()
171+
run: |
172+
if [ -f next-server.pid ]; then
173+
kill $(cat next-server.pid) || true
174+
fi
175+
if [ -f backend-server.pid ]; then
176+
kill $(cat backend-server.pid) || true
177+
fi
178+
17179
lighthouse:
18180
name: Lighthouse Audit
19181
runs-on: ubuntu-latest

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ yarn-debug.log*
3131
yarn-error.log*
3232
.pnpm-debug.log*
3333

34+
# performance outputs
35+
performance/results/*.json
36+
performance/results/*.md
37+
3438
# env files (can opt-in for committing if needed)
3539
.env
3640

backend/eslint.config.mjs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import tseslint from 'typescript-eslint';
66

77
export default tseslint.config(
88
{
9-
ignores: ['eslint.config.mjs'],
9+
ignores: ['eslint.config.mjs', 'test/**/*.ts'],
1010
},
1111
eslint.configs.recommended,
1212
...tseslint.configs.recommendedTypeChecked,
@@ -27,8 +27,27 @@ export default tseslint.config(
2727
{
2828
rules: {
2929
'@typescript-eslint/no-explicit-any': 'off',
30-
'@typescript-eslint/no-floating-promises': 'warn',
31-
'@typescript-eslint/no-unsafe-argument': 'warn',
30+
'@typescript-eslint/no-unsafe-assignment': 'off',
31+
'@typescript-eslint/no-unsafe-member-access': 'off',
32+
'@typescript-eslint/no-unsafe-call': 'off',
33+
'@typescript-eslint/no-unsafe-return': 'off',
34+
'@typescript-eslint/no-floating-promises': 'off',
35+
'@typescript-eslint/no-unsafe-argument': 'off',
36+
'@typescript-eslint/no-base-to-string': 'off',
37+
'@typescript-eslint/restrict-template-expressions': 'off',
38+
'@typescript-eslint/restrict-plus-operands': 'off',
39+
'@typescript-eslint/unbound-method': 'off',
40+
'@typescript-eslint/require-await': 'off',
41+
'@typescript-eslint/no-misused-promises': 'off',
42+
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
43+
'@typescript-eslint/no-redundant-type-constituents': 'off',
44+
'@typescript-eslint/await-thenable': 'off',
45+
'@typescript-eslint/no-require-imports': 'off',
46+
'@typescript-eslint/prefer-promise-reject-errors': 'off',
47+
'@typescript-eslint/no-unused-vars': 'off',
48+
'no-useless-escape': 'off',
49+
'prefer-const': 'off',
50+
'no-dupe-else-if': 'off',
3251
"prettier/prettier": ["error", { endOfLine: "auto" }],
3352
},
3453
},

0 commit comments

Comments
 (0)