Some checks failed
Test Suite / playwright-tests (push) Waiting to run
Deploy Development / deploy (push) Failing after 43s
Test Suite / pytest-backend (push) Failing after 31s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Has been cancelled
- Enhanced the deployment workflow to include error handling for the DEV API, ensuring logs are captured if the API is unreachable. - Updated the migration scripts to safely rename existing tables by checking for their existence, preventing potential conflicts during migrations. - Added exception handling in migration 079 to ensure the prerequisites are met before proceeding with the creation of the capabilities table.
316 lines
12 KiB
YAML
316 lines
12 KiB
YAML
name: Test Suite
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
pull_request:
|
|
branches: [main, develop]
|
|
workflow_run:
|
|
workflows: ["Deploy Development", "Deploy Production"]
|
|
types: [completed]
|
|
|
|
jobs:
|
|
# Pytest im laufenden backend-Container; ACCESS_LAYER + TRAINING_PLANNING Integration gegen dieselbe PostgreSQL wie Deploy (Schema via Container-Start migriert).
|
|
pytest-backend:
|
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Backend pytest im deployten Container
|
|
run: |
|
|
set -e
|
|
EVENT_NAME="${{ github.event_name }}"
|
|
REF_NAME="${{ github.ref_name }}"
|
|
BASE_REF="${{ github.base_ref }}"
|
|
RUN_WORKFLOW="${{ github.event.workflow_run.name }}"
|
|
APP_DIR="/home/lars/docker/shinkan"
|
|
COMPOSE_FILE="docker-compose.yml"
|
|
|
|
if [ "$EVENT_NAME" = "workflow_run" ]; then
|
|
if [ "$RUN_WORKFLOW" = "Deploy Development" ]; then
|
|
APP_DIR="/home/lars/docker/shinkan-dev"
|
|
COMPOSE_FILE="docker-compose.dev-env.yml"
|
|
fi
|
|
elif [ "$REF_NAME" = "develop" ] || [ "$BASE_REF" = "develop" ]; then
|
|
APP_DIR="/home/lars/docker/shinkan-dev"
|
|
COMPOSE_FILE="docker-compose.dev-env.yml"
|
|
fi
|
|
|
|
cd "$APP_DIR"
|
|
echo "Warte auf stabilen backend-Container …"
|
|
for i in $(seq 1 60); do
|
|
if docker compose -f "$COMPOSE_FILE" exec -T backend true 2>/dev/null; then
|
|
echo "Backend bereit (Versuch $i)"
|
|
break
|
|
fi
|
|
if [ "$i" -eq 60 ]; then
|
|
echo "Timeout: backend-Container nicht bereit"
|
|
docker compose -f "$COMPOSE_FILE" ps || true
|
|
docker compose -f "$COMPOSE_FILE" logs backend --tail 80 || true
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
docker compose -f "$COMPOSE_FILE" exec -T backend sh -lc "
|
|
pip install -r /app/requirements-dev.txt &&
|
|
cd /app &&
|
|
ACCESS_LAYER_STRICT=1 python scripts/check_access_layer_hints.py &&
|
|
python scripts/security_release_checks.py &&
|
|
ACCESS_LAYER_INTEGRATION=1 TRAINING_PLANNING_INTEGRATION=1 SKIP_DB_MIGRATE=1 python -m pytest tests -m 'not slow' -ra -vv --tb=short
|
|
"
|
|
|
|
lint-backend:
|
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Check backend syntax
|
|
run: |
|
|
EVENT_NAME="${{ github.event_name }}"
|
|
REF_NAME="${{ github.ref_name }}"
|
|
RUN_WORKFLOW="${{ github.event.workflow_run.name }}"
|
|
APP_DIR="/home/lars/docker/shinkan"
|
|
|
|
if [ "$EVENT_NAME" = "workflow_run" ]; then
|
|
if [ "$RUN_WORKFLOW" = "Deploy Development" ]; then
|
|
APP_DIR="/home/lars/docker/shinkan-dev"
|
|
fi
|
|
elif [ "$REF_NAME" = "develop" ]; then
|
|
APP_DIR="/home/lars/docker/shinkan-dev"
|
|
fi
|
|
|
|
python3 -m py_compile "$APP_DIR/backend/main.py"
|
|
echo "✓ Backend syntax OK"
|
|
|
|
build-frontend:
|
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Build frontend
|
|
run: |
|
|
EVENT_NAME="${{ github.event_name }}"
|
|
REF_NAME="${{ github.ref_name }}"
|
|
RUN_WORKFLOW="${{ github.event.workflow_run.name }}"
|
|
APP_DIR="/home/lars/docker/shinkan"
|
|
|
|
if [ "$EVENT_NAME" = "workflow_run" ]; then
|
|
if [ "$RUN_WORKFLOW" = "Deploy Development" ]; then
|
|
APP_DIR="/home/lars/docker/shinkan-dev"
|
|
fi
|
|
elif [ "$REF_NAME" = "develop" ]; then
|
|
APP_DIR="/home/lars/docker/shinkan-dev"
|
|
fi
|
|
|
|
cd "$APP_DIR/frontend"
|
|
npm install
|
|
npm run build
|
|
echo "✓ Frontend build OK"
|
|
|
|
# Phase-0 Lastsmoke: nur k6 — eigener Job (kein Node/Playwright), klare CI-Zuordnung.
|
|
k6-health-baseline:
|
|
name: k6 /health Baseline
|
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
E2E_TARGET_URL: https://dev.shinkan.jinkendo.de
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: E2E-Ziel wählen (Dev über Proxy vs. Production)
|
|
id: e2e
|
|
run: |
|
|
EVENT="${{ github.event_name }}"
|
|
WF_NAME="${{ github.event.workflow_run.name }}"
|
|
DEV_BASE="${{ env.E2E_TARGET_URL }}"
|
|
if [ "$EVENT" = "workflow_run" ] && [ "$WF_NAME" = "Deploy Production" ]; then
|
|
echo "mode=prod" >> $GITHUB_OUTPUT
|
|
echo "base_url=https://shinkan.jinkendo.de" >> $GITHUB_OUTPUT
|
|
echo "→ k6 gegen Prod-Basis."
|
|
else
|
|
echo "mode=dev" >> $GITHUB_OUTPUT
|
|
echo "base_url=${DEV_BASE}" >> $GITHUB_OUTPUT
|
|
echo "→ k6 gegen Dev (${DEV_BASE})."
|
|
fi
|
|
|
|
- name: Dev /health abwarten
|
|
if: ${{ steps.e2e.outputs.mode == 'dev' }}
|
|
run: |
|
|
BASE="${{ steps.e2e.outputs.base_url }}"
|
|
echo "Warte auf $BASE/health …"
|
|
for i in $(seq 1 90); do
|
|
if curl -sf "$BASE/health" >/dev/null 2>&1; then
|
|
echo "Health OK (Versuch $i)"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
echo "Timeout: Dev /health nicht erreichbar — Deploy / DNS / Firewall prüfen."
|
|
curl -v "$BASE/health" || true
|
|
exit 1
|
|
|
|
- name: Prod /health abwarten
|
|
if: ${{ steps.e2e.outputs.mode == 'prod' }}
|
|
run: |
|
|
BASE="${{ steps.e2e.outputs.base_url }}"
|
|
echo "Warte auf $BASE/health …"
|
|
for i in $(seq 1 60); do
|
|
if curl -sf "$BASE/health" >/dev/null 2>&1; then
|
|
echo "Health OK (Versuch $i)"
|
|
exit 0
|
|
fi
|
|
sleep 5
|
|
done
|
|
echo "Timeout: Prod /health nicht erreichbar"
|
|
curl -v "$BASE/health" || true
|
|
exit 1
|
|
|
|
- name: Install k6
|
|
run: |
|
|
set -e
|
|
K6_VER="v0.55.0"
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64) K6_ARCH=amd64 ;;
|
|
aarch64|arm64) K6_ARCH=arm64 ;;
|
|
*) echo "k6: unbekannte Architektur: $ARCH"; exit 1 ;;
|
|
esac
|
|
echo "Installing k6 ${K6_VER} linux-${K6_ARCH}"
|
|
curl -sSL "https://github.com/grafana/k6/releases/download/${K6_VER}/k6-${K6_VER}-linux-${K6_ARCH}.tar.gz" -o /tmp/k6.tgz
|
|
tar -xzf /tmp/k6.tgz -C /tmp
|
|
sudo mv "/tmp/k6-${K6_VER}-linux-${K6_ARCH}/k6" /usr/local/bin/k6
|
|
k6 version
|
|
|
|
- name: k6 Health-Baseline (parallele /health)
|
|
env:
|
|
BASE_URL: ${{ steps.e2e.outputs.base_url }}
|
|
run: |
|
|
set -e
|
|
echo "k6 gegen BASE_URL=$BASE_URL"
|
|
k6 run scripts/load/k6-health-baseline.js
|
|
echo "✓ k6 Health-Baseline passed"
|
|
|
|
playwright-tests:
|
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
# Kein zusätzlicher docker-compose im Job: keine zweiten Container/Host-Ports.
|
|
# Dev: Tests gegen bereits deployte URL (HTTPS, Reverse-Proxy). Prod: gleicher Ablauf.
|
|
env:
|
|
# Öffentliche Dev-Basis — muss ALLOWED_ORIGINS / Nginx entsprechen; bei anderer Domain Workflow anpassen.
|
|
E2E_TARGET_URL: https://dev.shinkan.jinkendo.de
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: E2E-Ziel wählen (Dev über Proxy vs. Production)
|
|
id: e2e
|
|
run: |
|
|
EVENT="${{ github.event_name }}"
|
|
WF_NAME="${{ github.event.workflow_run.name }}"
|
|
DEV_BASE="${{ env.E2E_TARGET_URL }}"
|
|
if [ "$EVENT" = "workflow_run" ] && [ "$WF_NAME" = "Deploy Production" ]; then
|
|
echo "mode=prod" >> $GITHUB_OUTPUT
|
|
echo "base_url=https://shinkan.jinkendo.de" >> $GITHUB_OUTPUT
|
|
echo "→ Prod. Secrets: E2E_PROD_TEST_EMAIL / E2E_PROD_TEST_PASSWORD."
|
|
else
|
|
echo "mode=dev" >> $GITHUB_OUTPUT
|
|
echo "base_url=${DEV_BASE}" >> $GITHUB_OUTPUT
|
|
echo "→ Deployte Dev-Umgebung (${DEV_BASE}). Secrets: E2E_DEV_TEST_EMAIL / E2E_DEV_TEST_PASSWORD."
|
|
fi
|
|
|
|
- name: Dev /health abwarten
|
|
if: ${{ steps.e2e.outputs.mode == 'dev' }}
|
|
run: |
|
|
BASE="${{ steps.e2e.outputs.base_url }}"
|
|
echo "Warte auf $BASE/health …"
|
|
for i in $(seq 1 90); do
|
|
if curl -sf "$BASE/health" >/dev/null 2>&1; then
|
|
echo "Health OK (Versuch $i)"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
echo "Timeout: Dev /health nicht erreichbar — Deploy / DNS / Firewall prüfen."
|
|
curl -v "$BASE/health" || true
|
|
exit 1
|
|
|
|
- name: Prod /health abwarten
|
|
if: ${{ steps.e2e.outputs.mode == 'prod' }}
|
|
run: |
|
|
BASE="${{ steps.e2e.outputs.base_url }}"
|
|
echo "Warte auf $BASE/health …"
|
|
for i in $(seq 1 60); do
|
|
if curl -sf "$BASE/health" >/dev/null 2>&1; then
|
|
echo "Health OK (Versuch $i)"
|
|
exit 0
|
|
fi
|
|
sleep 5
|
|
done
|
|
echo "Timeout: Prod /health nicht erreichbar"
|
|
curl -v "$BASE/health" || true
|
|
exit 1
|
|
|
|
- name: Testnutzer registrieren (Dev, nur wenn möglich)
|
|
if: ${{ steps.e2e.outputs.mode == 'dev' }}
|
|
env:
|
|
E2E_DEV_TEST_EMAIL: ${{ secrets.E2E_DEV_TEST_EMAIL }}
|
|
E2E_DEV_TEST_PASSWORD: ${{ secrets.E2E_DEV_TEST_PASSWORD }}
|
|
run: |
|
|
BASE="${{ steps.e2e.outputs.base_url }}"
|
|
if [ -z "$E2E_DEV_TEST_EMAIL" ] || [ -z "$E2E_DEV_TEST_PASSWORD" ]; then
|
|
echo "(Registrierung übersprungen — Secrets E2E_DEV_* nicht gesetzt.)"
|
|
exit 0
|
|
fi
|
|
curl -sf -X POST "$BASE/api/auth/register" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"email\":\"${E2E_DEV_TEST_EMAIL}\",\"password\":\"${E2E_DEV_TEST_PASSWORD}\",\"name\":\"Playwright CI\"}" \
|
|
|| echo "(Register evtl. schon erfolgt oder Limits — Login-Test gilt trotzdem.)"
|
|
|
|
- name: Install Playwright
|
|
run: |
|
|
npm ci || npm install
|
|
npx playwright install --with-deps chromium
|
|
|
|
- name: Run Playwright tests
|
|
env:
|
|
E2E_DEV_TEST_EMAIL: ${{ secrets.E2E_DEV_TEST_EMAIL }}
|
|
E2E_DEV_TEST_PASSWORD: ${{ secrets.E2E_DEV_TEST_PASSWORD }}
|
|
run: |
|
|
set -e
|
|
MODE="${{ steps.e2e.outputs.mode }}"
|
|
BASE_URL="${{ steps.e2e.outputs.base_url }}"
|
|
export PLAYWRIGHT_BASE_URL="$BASE_URL"
|
|
|
|
if [ "$MODE" = "prod" ]; then
|
|
export TEST_EMAIL="${{ secrets.E2E_PROD_TEST_EMAIL }}"
|
|
export TEST_PASSWORD="${{ secrets.E2E_PROD_TEST_PASSWORD }}"
|
|
if [ -z "$TEST_EMAIL" ] || [ -z "$TEST_PASSWORD" ]; then
|
|
echo "Fehler: E2E_PROD_TEST_EMAIL und E2E_PROD_TEST_PASSWORD setzen."
|
|
exit 1
|
|
fi
|
|
else
|
|
export TEST_EMAIL="$E2E_DEV_TEST_EMAIL"
|
|
export TEST_PASSWORD="$E2E_DEV_TEST_PASSWORD"
|
|
if [ -z "$TEST_EMAIL" ] || [ -z "$TEST_PASSWORD" ]; then
|
|
echo "Fehler: E2E_DEV_TEST_EMAIL und E2E_DEV_TEST_PASSWORD setzen (Playwright soll gegen Dev einloggen)."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
mkdir -p screenshots
|
|
npx playwright test
|
|
echo "✓ Playwright tests passed"
|
|
|
|
- name: Upload test screenshots
|
|
if: failure()
|
|
# v4 ist auf Gitea (GHES-kompatibles Actions-Backend) oft nicht verfügbar
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: playwright-screenshots
|
|
path: screenshots/
|
|
retention-days: 7
|