Aucun garde-fou de performance n'existait, et le dépôt ne chiffrait aucun temps de réponse. tests/load, quatre scénarios : - smoke : une minute sur chaque route de lecture, joué à chaque PR ; - charge : 50 utilisateurs, 40 sur le tableau de bord au rythme de son rafraîchissement, 10 qui explorent les sites ; - stress : débit croissant jusqu'à la rupture, arrêt au-delà de 10 % d'erreurs ; - limitation-debit : par le proxy, vérifie que nginx répond 429 et jamais 5xx. Seuils : p95 < 500 ms et p99 < 1 s sur les lectures, moins de 1 % d'échecs. k6 tourne en service Compose (profil load) sur le réseau du projet : il vise backend:8000 et mesure l'API plutôt que la limite de 20 req/s par adresse de nginx. Chaque tir écrit un rapport HTML, une synthèse Markdown et le JSON brut dans tests/load/results. make load-smoke, load-test, load-stress et load-limits ; le job E2E enchaîne le smoke et le test de limitation après Playwright. Closes #47
132 lines
4.4 KiB
YAML
132 lines
4.4 KiB
YAML
name: E2E
|
|
|
|
# Pourquoi : les parcours tournent contre la stack telle qu'elle est déployée, derrière le proxy
|
|
# TLS (cookie `__Secure-`, CSP, limitation de débit), pas contre `ng serve` - job parcours. Il
|
|
# construit aussi les images backend et frontend, que rien d'autre ne construit avant le
|
|
# déploiement (ADR 0015).
|
|
# Piège : pas d'Airflow ici. `up` nomme ses services : sans eux, la construction de l'image
|
|
# Airflow doublerait la durée du job sans rien tester de plus.
|
|
|
|
on:
|
|
workflow_call:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
parcours:
|
|
name: Parcours Playwright et tirs k6
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
env:
|
|
COMPOSE_FILE: docker-compose.yml:docker-compose.prod.yml
|
|
PUBLIC_HOST: localhost
|
|
E2E_BASE_URL: https://localhost
|
|
|
|
steps:
|
|
- name: Récupère le dépôt
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Prépare le .env de la stack
|
|
run: |
|
|
secret() { openssl rand -hex 32; }
|
|
sed -e "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(secret)|" \
|
|
-e "s|^APP_SECRET_KEY=.*|APP_SECRET_KEY=$(secret)|" \
|
|
-e "s|^PUBLIC_HOST=.*|PUBLIC_HOST=localhost|" \
|
|
.env.example > .env
|
|
|
|
- name: Génère le certificat de démonstration
|
|
run: ./scripts/tls-selfsigned.sh
|
|
|
|
- name: Construit et démarre la stack derrière le proxy
|
|
run: docker compose up --detach --build --wait --wait-timeout 300 db mailpit backend frontend proxy
|
|
|
|
- name: Applique les migrations
|
|
run: docker compose exec -T backend alembic upgrade head
|
|
|
|
- name: Sème le jeu de démonstration
|
|
run: docker compose exec -T db psql -U enervision -d enervision -v ON_ERROR_STOP=1 < db/seeds/demo.sql
|
|
|
|
- name: Crée les comptes de test
|
|
env:
|
|
BASE_URL: https://localhost
|
|
APP_CLI: docker compose exec -T backend python -m app.cli
|
|
COMPTES_FICHIER: ${{ runner.temp }}/comptes.json
|
|
run: ./scripts/comptes-test.sh
|
|
|
|
- name: Installe Node
|
|
uses: actions/setup-node@v7
|
|
with:
|
|
node-version: 26
|
|
cache: npm
|
|
cache-dependency-path: tests/e2e/package-lock.json
|
|
|
|
- name: Installe Playwright
|
|
working-directory: tests/e2e
|
|
run: npm ci
|
|
|
|
- name: Restaure les navigateurs de Playwright
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ runner.os }}-${{ hashFiles('tests/e2e/package-lock.json') }}
|
|
|
|
# `--with-deps` tourne même quand le cache a servi : il pose aussi les bibliothèques système.
|
|
- name: Installe Chromium
|
|
working-directory: tests/e2e
|
|
run: npx playwright install --with-deps chromium
|
|
|
|
- name: Joue les parcours
|
|
working-directory: tests/e2e
|
|
env:
|
|
E2E_COMPTES: ${{ runner.temp }}/comptes.json
|
|
run: npx playwright test
|
|
|
|
# Direct sur `backend:8000` : ce tir mesure l'API, pas la limitation de nginx.
|
|
- name: Tir k6 de fumée sur l'API
|
|
env:
|
|
K6_RESUME: /results/resume-smoke.md
|
|
run: |
|
|
K6_EMAIL="$(jq -r .lecteur.email "$RUNNER_TEMP/comptes.json")"
|
|
K6_PASSWORD="$(jq -r .lecteur.password "$RUNNER_TEMP/comptes.json")"
|
|
echo "::add-mask::$K6_PASSWORD"
|
|
export K6_EMAIL K6_PASSWORD
|
|
make load-smoke
|
|
|
|
- name: Vérifie par k6 que le proxy limite le débit
|
|
env:
|
|
K6_RESUME: /results/resume-limitation.md
|
|
run: make load-limits
|
|
|
|
- name: Publie la synthèse k6
|
|
if: ${{ !cancelled() }}
|
|
run: cat tests/load/results/resume-*.md >> "$GITHUB_STEP_SUMMARY" 2>/dev/null || true
|
|
|
|
- name: Publie les rapports k6
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: k6-rapports
|
|
path: tests/load/results/
|
|
if-no-files-found: ignore
|
|
retention-days: 14
|
|
|
|
- name: Publie le rapport Playwright
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: playwright-report
|
|
path: |
|
|
tests/e2e/playwright-report/
|
|
tests/e2e/test-results/
|
|
if-no-files-found: ignore
|
|
retention-days: 14
|
|
|
|
- name: Journaux de la stack en cas d'échec
|
|
if: failure()
|
|
run: docker compose logs --tail=200 backend proxy frontend
|
|
|
|
- name: Arrête la stack
|
|
if: always()
|
|
run: docker compose down --volumes
|