k6-CI fuer Raspberry Pi: weniger Last, quiet-Modus, nach pytest.
All checks were successful
Deploy Development / deploy (push) Successful in 33s
Test Suite / pytest-backend (push) Successful in 4s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Successful in 11s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Lars 2026-07-04 19:47:45 +02:00
parent 1765daed2d
commit 1d8e22be82
2 changed files with 33 additions and 6 deletions

View File

@ -115,6 +115,7 @@ jobs:
k6-health-baseline: k6-health-baseline:
name: k6 /api/health Baseline name: k6 /api/health Baseline
needs: [pytest-backend]
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -160,11 +161,19 @@ jobs:
sudo mv "/tmp/k6-${K6_VER}-linux-${K6_ARCH}/k6" /usr/local/bin/k6 sudo mv "/tmp/k6-${K6_VER}-linux-${K6_ARCH}/k6" /usr/local/bin/k6
- name: k6 Health-Baseline - name: k6 Health-Baseline
env: run: |
BASE_URL: ${{ steps.k6.outputs.base_url }} set -e
run: k6 run scripts/load/k6-health-baseline.js BASE_URL="${{ steps.k6.outputs.base_url }}"
if [ -z "$BASE_URL" ]; then
echo "BASE_URL leer — steps.k6.outputs.base_url prüfen"
exit 1
fi
echo "k6 gegen BASE_URL=$BASE_URL (K6_CI=1, quiet)"
BASE_URL="$BASE_URL" K6_CI=1 k6 run --quiet scripts/load/k6-health-baseline.js
echo "✓ k6 Health-Baseline OK"
playwright-smoke: playwright-smoke:
needs: [pytest-backend]
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -1,16 +1,23 @@
/** /**
* Phase-0-Baseline: parallele GET /api/health (kein Auth). * Phase-0-Baseline: parallele GET /api/health (kein Auth).
* BASE_URL optional, z. B. https://dev.kairo.jinkendo.de * BASE_URL optional, z. B. https://dev.kairo.jinkendo.de
*
* K6_CI=1: leichtere Last für Self-hosted Runner (Raspberry Pi).
*/ */
import http from 'k6/http' import http from 'k6/http'
import { check } from 'k6' import { check } from 'k6'
const isCi = __ENV.K6_CI === '1' || __ENV.K6_CI === 'true'
const vus = parseInt(__ENV.K6_VUS || (isCi ? '5' : '10'), 10)
const duration = __ENV.K6_DURATION || (isCi ? '15s' : '30s')
const p95Ms = parseInt(__ENV.K6_P95_MS || (isCi ? '5000' : '3000'), 10)
export const options = { export const options = {
scenarios: { scenarios: {
health: { health: {
executor: 'constant-vus', executor: 'constant-vus',
vus: 10, vus,
duration: '30s', duration,
gracefulStop: '5s', gracefulStop: '5s',
tags: { scenario: 'health' }, tags: { scenario: 'health' },
exec: 'health', exec: 'health',
@ -18,8 +25,9 @@ export const options = {
}, },
thresholds: { thresholds: {
http_req_failed: ['rate<0.05'], http_req_failed: ['rate<0.05'],
'http_req_duration{scenario:health}': ['p(95)<3000'], 'http_req_duration{scenario:health}': [`p(95)<${p95Ms}`],
}, },
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)', 'p(95)'],
} }
const BASE = (__ENV.BASE_URL || 'https://dev.kairo.jinkendo.de').replace(/\/$/, '') const BASE = (__ENV.BASE_URL || 'https://dev.kairo.jinkendo.de').replace(/\/$/, '')
@ -30,3 +38,13 @@ export function health() {
'health 2xx': (r) => r.status >= 200 && r.status < 300, 'health 2xx': (r) => r.status >= 200 && r.status < 300,
}) })
} }
export function handleSummary(data) {
const failed = data.metrics.http_req_failed?.values?.rate ?? 0
const p95 = data.metrics.http_req_duration?.values?.['p(95)'] ?? 0
const lines = [
`k6 summary: BASE=${BASE} vus=${vus} duration=${duration}`,
` http_req_failed=${(failed * 100).toFixed(2)}% p(95)=${p95.toFixed(1)}ms (limit ${p95Ms}ms)`,
]
return { stdout: lines.join('\n') + '\n' }
}