forked from digitalandrew/wairz
-
Notifications
You must be signed in to change notification settings - Fork 0
188 lines (164 loc) · 6.87 KB
/
Copy pathbackend-tests.yml
File metadata and controls
188 lines (164 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
name: Backend Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
paths:
- 'backend/**'
- 'docker-compose.yml'
- '.github/workflows/backend-tests.yml'
workflow_dispatch:
# CLAUDE.md Rule #41 mitigation — nightly must-complete run. See the
# `pytest-must-complete` job below for the cost-profile rationale (per-
# commit must-complete would cost ~$15/day commercial vs ~$0.07/day for
# nightly; tests latency tolerance is hours, not commits).
schedule:
- cron: '0 6 * * *' # 06:00 UTC daily
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
pytest:
name: Pytest (Backend)
# CLAUDE.md Rule #41: this job runs under workflow-level
# cancel-in-progress: true. A fast-following push may cancel an
# in-flight run; the cancellation pattern is acceptable for fast
# feedback on push/PR but does NOT provide latent-defect-detection
# guarantees — that role is served by `pytest-must-complete` below
# on the nightly + dispatch path. Restricting the trigger surface
# here keeps push/PR runs lean.
if: github.event_name == 'push' || github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
# docker-compose.yml has :?required on POSTGRES_PASSWORD and FIRMAE_DB_PASSWORD
# (infra-secrets closure, commit 83e31c8) — seed CI-only values so
# `docker compose up` does not bail out at config resolution.
- name: Write CI .env
run: |
cat > .env <<'EOF'
POSTGRES_PASSWORD=ci-only-pg-password
FIRMAE_DB_PASSWORD=ci-only-firmae-password
API_KEY=ci-only-api-key
EOF
- name: Build backend image
run: docker compose build backend
timeout-minutes: 15
# docker-compose.yml declares wairz_emulation_net as `external: true` —
# in dev environments this is created by the operator (or by a prior
# `docker network create`); in CI we create it explicitly so the
# `docker compose up` doesn't bail with "network ... not found".
- name: Create external emulation network
run: docker network create wairz_emulation_net || true
- name: Start backend + datastores
run: docker compose up -d postgres redis backend --wait
timeout-minutes: 10
# tests/ is excluded from the production image via backend/.dockerignore (Q9).
# Copy the test tree into the running container for this CI job only.
- name: Copy tests into container
run: docker cp backend/tests wairz-backend-1:/app/tests
# pytest + pytest-asyncio live in [dependency-groups].dev, not in the
# production deps. Install them just for this job.
- name: Install test runner
run: |
docker compose exec -T backend /app/.venv/bin/pip install --quiet \
pytest pytest-asyncio
- name: Run pytest
run: |
docker compose exec -T -w /app \
-e PYTHONPATH=/app \
backend /app/.venv/bin/python -m pytest tests/ \
-v --tb=short --maxfail=5
timeout-minutes: 20
- name: Upload backend logs on failure
if: failure()
run: |
docker compose logs backend --tail 500 > backend.log || true
docker compose logs worker --tail 500 > worker.log || true
docker compose logs postgres --tail 200 > postgres.log || true
- name: Archive logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: backend-test-logs
path: |
backend.log
worker.log
postgres.log
retention-days: 7
pytest-must-complete:
# CLAUDE.md Rule #41 mitigation — nightly cron + dispatch path.
# Runs the full pytest suite to completion under a per-run-id
# concurrency group (`cancel-in-progress: false`) so latent
# regressions surface within 24 hours regardless of push cadence on
# `main`.
#
# Why nightly (mechanism b) and not per-commit (mechanism a):
# The `pytest` job above costs ~8-10 minutes per run (docker
# compose build + DB up + full pytest). Empirically the push-side
# cancellation rate runs ~68% during sustained per-piece cadence
# (Pattern P5, trusted contributor). Per-commit must-complete at
# ~25 commits/day = ~$15-20/day commercial runner time; nightly
# must-complete = ~$0.07/day. Test-defect latency is bounded by
# <24h, which is acceptable for backend regressions (vs ~1
# commit for the lint surface, which costs ~$0.001/run and has
# a tighter latency budget per the F823 Rule #40 incident).
#
# `pytest-must-complete` is INTENTIONALLY exempt from the
# `pull_request.paths` filter — schedule + dispatch always run it
# in full, regardless of which subpath changed since last run.
name: Pytest must-complete (Rule #41, nightly)
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 45
concurrency:
group: pytest-must-complete-${{ github.run_id }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- name: Write CI .env
run: |
cat > .env <<'EOF'
POSTGRES_PASSWORD=ci-only-pg-password
FIRMAE_DB_PASSWORD=ci-only-firmae-password
API_KEY=ci-only-api-key
EOF
- name: Build backend image
run: docker compose build backend
timeout-minutes: 15
- name: Create external emulation network
run: docker network create wairz_emulation_net || true
- name: Start backend + datastores
run: docker compose up -d postgres redis backend --wait
timeout-minutes: 10
- name: Copy tests into container
run: docker cp backend/tests wairz-backend-1:/app/tests
- name: Install test runner
run: |
docker compose exec -T backend /app/.venv/bin/pip install --quiet \
pytest pytest-asyncio
- name: Run pytest (nightly must-complete; no maxfail to surface every regression)
run: |
docker compose exec -T -w /app \
-e PYTHONPATH=/app \
backend /app/.venv/bin/python -m pytest tests/ \
-v --tb=short
timeout-minutes: 30
- name: Upload backend logs on failure
if: failure()
run: |
docker compose logs backend --tail 500 > backend.log || true
docker compose logs worker --tail 500 > worker.log || true
docker compose logs postgres --tail 200 > postgres.log || true
- name: Archive logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: backend-test-logs-must-complete
path: |
backend.log
worker.log
postgres.log
retention-days: 14