Spaces:
Running
Running
| name: Tests | |
| on: | |
| push: | |
| branches: [master, main] | |
| paths: | |
| - 'backend/**' | |
| - 'exam-app/**' | |
| - 'requirements*.txt' | |
| - '.github/workflows/test.yml' | |
| pull_request: | |
| branches: [master, main] | |
| paths: | |
| - 'backend/**' | |
| - 'exam-app/**' | |
| - 'requirements*.txt' | |
| jobs: | |
| # ── Backend unit + integration tests ──────────────────────────────────────── | |
| backend-tests: | |
| name: Backend Tests (Python ${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.12"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| - name: Install dependencies | |
| run: | | |
| pip install -r requirements.txt | |
| pip install -r requirements-dev.txt | |
| - name: Run fast test suite (no live AI, no fault injection) | |
| env: | |
| ANTHROPIC_AUTH_TOKEN: test-token-ci | |
| JWT_SECRET: ${{ secrets.JWT_SECRET || 'ci-test-secret-at-least-32-chars-long' }} | |
| ADMIN_KEY: ci-admin-key | |
| ADMIN_MASTER_SECRET: "" | |
| SQLITE_PATH: ":memory:" | |
| run: | | |
| PYTHONPATH=backend python3 -m pytest backend/tests/ \ | |
| -m "not live_ai and not fault_injection" \ | |
| --tb=short \ | |
| -q \ | |
| --randomly-seed=0 \ | |
| -x | |
| - name: Run fault injection tests | |
| env: | |
| ANTHROPIC_AUTH_TOKEN: test-token-ci | |
| JWT_SECRET: ${{ secrets.JWT_SECRET || 'ci-test-secret-at-least-32-chars-long' }} | |
| ADMIN_KEY: ci-admin-key | |
| ADMIN_MASTER_SECRET: "" | |
| SQLITE_PATH: ":memory:" | |
| run: | | |
| PYTHONPATH=backend python3 -m pytest backend/tests/ \ | |
| -m "fault_injection" \ | |
| --tb=short \ | |
| -q | |
| continue-on-error: true # fault injection is informational until stabilised | |
| # ── Frontend unit tests ────────────────────────────────────────────────────── | |
| frontend-tests: | |
| name: Frontend Tests (Node ${{ matrix.node-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| node-version: ["20"] | |
| defaults: | |
| run: | |
| working-directory: exam-app | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Node ${{ matrix.node-version }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: npm | |
| cache-dependency-path: exam-app/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run Vitest unit tests | |
| run: npm test | |
| # ── Mutation score gate (weekly, manual, or on demand) ─────────────────────── | |
| mutation-score: | |
| name: Mutation Score Gate | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'workflow_dispatch' || github.event.schedule != '' | |
| # Run manually via: gh workflow run test.yml | |
| # Or add to a scheduled cron job by uncommenting below: | |
| # on: | |
| # schedule: | |
| # - cron: '0 3 * * 1' # Monday 03:00 UTC | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| - name: Install dependencies | |
| run: | | |
| pip install -r requirements.txt | |
| pip install -r requirements-dev.txt | |
| - name: Run mutation testing | |
| env: | |
| ANTHROPIC_AUTH_TOKEN: test-token-ci | |
| JWT_SECRET: ci-test-secret-at-least-32-chars-long | |
| ADMIN_KEY: ci-admin-key | |
| ADMIN_MASTER_SECRET: "" | |
| run: | | |
| PYTHONPATH=backend mutmut run \ | |
| --paths-to-mutate backend/app/agent/ \ | |
| --tests-dir backend/tests/ \ | |
| || true # mutmut exits non-zero when mutations survive — handled below | |
| - name: Check mutation score gate | |
| run: | | |
| PYTHONPATH=backend python3 tools/check_mutation_score.py --min 70 | |