diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03e202eae..5bf8e925a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -279,6 +279,56 @@ jobs: # Docker Tests (matches test_docker.sh) # ============================================================================ + # Run the FULL backend test suite inside the test image, sharded 4-way + # so wall-clock matches the host-side backend-tests job. Catches the + # rare-but-real cases where a test passes on the GHA host but fails in + # the python:3.13-slim test image (system-binary version differences, + # locale/timezone, container vs host user, cwd assumptions). Without + # sharding this was a 5-10 min single-runner job; with sharding it's + # ~120-150s per shard running in parallel, gated by max(shard). + docker-backend-tests: + name: Docker Backend Tests (shard ${{ matrix.shard }}/4) + runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event.pull_request.user.login != github.repository_owner + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Build the backend-test image with GHA BuildKit cache backend so + # the pip-install layer is shared across the 4 matrix shards AND + # across CI runs. First run on a given requirements.txt is cold + # (~60-90s); subsequent runs are ~5-10s. + - name: Build backend test image (cached) + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.test + target: backend-test + load: true + tags: bambuddy-backend-test:latest + cache-from: type=gha,scope=backend-test + cache-to: type=gha,scope=backend-test,mode=max + + - name: Run backend tests in Docker (shard ${{ matrix.shard }}/4) + run: | + docker run --rm \ + -e TESTING=1 \ + -e PYTHONUNBUFFERED=1 \ + bambuddy-backend-test:latest \ + pytest backend/tests/ \ + --tb=short \ + --timeout=60 --timeout-method=thread \ + -p no:cacheprovider \ + -n auto \ + --splits 4 --group ${{ matrix.shard }} + docker-test: name: Docker Build runs-on: ubuntu-latest @@ -298,19 +348,6 @@ jobs: - name: Verify static files exist run: docker run --rm bambuddy:test test -d /app/static - # NOTE: Tests 2 and 3 from test_docker.sh (backend / frontend unit - # tests inside the test image) used to run here. They've been removed - # from the CI pipeline because the host-side `backend-tests` and - # `frontend-tests` jobs already exercise the exact same test code - # against the exact same Python version + requirements.txt the test - # image installs — on 2-vCPU GHA runners a re-run inside Docker - # added 5-10 min of wall-clock for zero new coverage. The - # image-validation purpose of this job (does it build, do imports - # resolve, does the integration container come up and answer HTTP) - # lives in the surrounding steps. test_docker.sh keeps the unit-test - # runs because devs running it locally don't have a separate host- - # side pytest job to compare against. - # Test 4: Integration Tests - name: Build integration container run: docker compose -f docker-compose.test.yml build integration