Repository navigation
391 lines (351 loc) · 16.5 KB
/
Copy pathci-e2e.yml
File metadata and controls
391 lines (351 loc) · 16.5 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
name: E2E Test Suite
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
e2e:
name: Full E2E suite (Playwright · Apache · MySQL)
runs-on: ubuntu-latest
timeout-minutes: 60
services:
mysql:
image: mysql:8.0@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: pinakes_test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1"
--health-interval=10s
--health-timeout=5s
--health-retries=10
env:
E2E_BASE_URL: http://localhost:8081
E2E_ADMIN_EMAIL: admin@pinakes.test
E2E_ADMIN_PASS: Test1234!
E2E_DB_HOST: 127.0.0.1
E2E_DB_PORT: 3306
E2E_DB_USER: root
E2E_DB_PASS: root
E2E_DB_NAME: pinakes_test
E2E_INSTALL_ROOT: ${{ github.workspace }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
# ── Apache2 + mod_php ───────────────────────────────────────────────────
# Install Apache before setup-php adds external package sources; the app
# supports PHP >= 8.1, so the Ubuntu mod_php package is sufficient here.
- name: Install Apache2 + mod_php
run: |
# This job never installs Google Chrome. Remove its hosted-runner
# apt source before the first refresh so mirror syncs cannot break CI.
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
sudo apt-get update -q
# php-apcu: the app's page cache must run on its production backend
# (APCu shared memory) under Apache/mod_php, not the file fallback.
sudo apt-get install -y apache2 libapache2-mod-php php-apcu
sudo a2enmod rewrite headers env
php_module="$(find /etc/apache2/mods-available -maxdepth 1 -name 'php*.load' -printf '%f\n' | sed 's/\.load$//' | sort -V | tail -n1)"
if [ -n "${php_module}" ]; then
sudo a2enmod "${php_module}"
fi
sudo a2dissite 000-default || true
# Enable APCu for every distro-PHP SAPI (Apache mod_php + distro CLI).
while IFS= read -r conf_dir; do
sudo tee "${conf_dir}/99-pinakes-apcu.ini" >/dev/null <<'EOF'
apc.enable=1
apc.enable_cli=1
EOF
done < <(find /etc/php -type d -path '*/conf.d' | sort -u)
# ── PHP 8.2 CLI for Composer and tooling ────────────────────────────────
- name: Setup PHP 8.2
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: '8.2'
extensions: mysqli, mbstring, json, curl, openssl, zip, gd, intl, xml, apcu
ini-values: apc.enable=1, apc.enable_cli=1
coverage: none
- name: Configure virtual host on port 8081
env:
WORKSPACE: ${{ github.workspace }}
run: |
sudo tee /etc/apache2/sites-available/pinakes.conf > /dev/null <<EOF
Listen 8081
<VirtualHost *:8081>
ServerName localhost
DocumentRoot ${WORKSPACE}/public
SetEnv PINAKES_E2E_BYPASS_RATE_LIMIT 1
# E2E only — deterministic, network-free bulk-enrich scraper stub.
# Removes external-API latency/flakiness; never set in production.
SetEnv PINAKES_E2E_SCRAPER_STUB 1
# E2E only — arms GET /_e2e/flush-cache so specs that write to the
# DB directly can invalidate the page cache; 404s when unset.
SetEnv PINAKES_E2E_CACHE_FLUSH 1
<Directory "${WORKSPACE}/public">
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog \${APACHE_LOG_DIR}/pinakes-error.log
CustomLog \${APACHE_LOG_DIR}/pinakes-access.log combined
</VirtualHost>
EOF
sudo a2ensite pinakes
sudo apachectl configtest
# ── PHP dependencies ────────────────────────────────────────────────────
- name: Cache Composer packages
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
restore-keys: composer-
- name: Install Composer dependencies
run: composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader
# ── Node / Playwright ────────────────────────────────────────────────────
- name: Setup Node 22
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: '22'
cache: npm
- name: Install Node dependencies
run: npm ci --silent
- name: Verify CI covers every Playwright spec
run: npm run test:ci-policy
- name: Install Playwright Chromium
run: npx playwright install chromium --with-deps
# ── Permissions: Apache (www-data) must write .env, .installed, storage ─
- name: Grant write permissions to workspace
env:
WORKSPACE: ${{ github.workspace }}
run: |
path="${WORKSPACE}"
while [ "${path}" != "/" ]; do
sudo chmod o+x "${path}" || true
path="$(dirname "${path}")"
done
sudo chmod 777 "${WORKSPACE}"
sudo chmod -R 777 "${WORKSPACE}/storage"
sudo mkdir -p "${WORKSPACE}/public/uploads"
sudo chmod -R 777 "${WORKSPACE}/public/uploads"
# ── Start Apache ─────────────────────────────────────────────────────────
- name: Start Apache and wait for installer
run: |
sudo systemctl start apache2
echo "Waiting for Apache on :8081..."
for i in $(seq 1 30); do
if curl -sf -o /dev/null "http://localhost:8081/installer/"; then
echo "ok — Apache up (attempt $i)"
exit 0
fi
sleep 1
done
echo "Apache did not respond in 30s"
sudo journalctl -u apache2 --no-pager -n 30 >&2
sudo cat /var/log/apache2/pinakes-error.log >&2 || true
exit 1
# ── Test suite ───────────────────────────────────────────────────────────
- name: "[1/13] full-test.spec.js — complete application lifecycle"
run: |
npx playwright test tests/full-test.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[2/13] schema-integrity.spec.js — post-install table verification"
run: |
npx playwright test tests/schema-integrity.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[3/13] plugin-integrity.spec.js — plugin registration regression"
run: |
npx playwright test tests/plugin-integrity.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[required] mobile-api.spec.js — discovery/auth + private-mode regression (#29)"
run: |
npx playwright test tests/mobile-api.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[4/13] mag-validation.spec.js — OAI-PMH MAG 2.0.1 metadata"
run: |
npx playwright test tests/mag-validation.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[5/13] archives-search.spec.js — ricerca archivi admin + pubblica"
run: |
npx playwright test tests/archives-search.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[6/13] ncip-server.spec.js — NCIP 2.0 endpoints v0.7.4"
run: |
npx playwright test tests/ncip-server.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[7/13] archives-phase5-admin-ui.spec.js — RiC-CM Phase 5 admin UI v0.7.12"
run: |
npx playwright test tests/archives-phase5-admin-ui.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[8/13] archives-phase6-oai-ric-o.spec.js — OAI-PMH metadataPrefix=ric-o v0.7.12"
run: |
npx playwright test tests/archives-phase6-oai-ric-o.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[9/13] archives-ric-jsonld.spec.js — RiC-O JSON-LD endpoints (Phase 1-4)"
run: |
npx playwright test tests/archives-ric-jsonld.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[10/13] archives-crud.spec.js — archival_units CRUD (#103)"
run: |
npx playwright test tests/archives-crud.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[11/13] archives-authorities.spec.js — authority_records CRUD"
run: |
npx playwright test tests/archives-authorities.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[12/13] archives-upload-assets.spec.js — cover/document upload pipeline"
# The upload-assets spec picks 3 archival_units from the
# `E2E_SEED_*` batch — it doesn't seed them itself. The seed
# lives in archives-seed-50.spec.js (50 rows, all 4 levels,
# full option matrix). On a fresh CI install no E2E_SEED_* row
# exists yet, so the upload spec's beforeAll fails with
# "no seeded row available for PDF test". Seed-then-upload
# in the same step keeps the dependency local — no test-order
# coupling with other steps, no separate seed step to renumber.
run: |
npx playwright test tests/archives-seed-50.spec.js \
--config=tests/playwright.config.js \
--workers=1
npx playwright test tests/archives-upload-assets.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[13/13] archives-pr-extended.spec.js — extended CRUD + CSRF regression"
# The pr-extended spec creates stub files directly via
# fs.writeFileSync under public/uploads/archives/documents/ to
# drive the IIIF rendering[] assertions. The previous step
# ([12/13] upload-assets) ran real uploads through Apache,
# which created subdirectories owned by www-data — the runner
# process can no longer write into them, so the test EACCES'es
# before the first assertion. Re-chmod the uploads tree right
# before this step (idempotent, no-op when already 777).
run: |
sudo chmod -R 777 "${GITHUB_WORKSPACE}/public/uploads" || true
npx playwright test tests/archives-pr-extended.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[required] issue-237-contributors.spec.js — pseudonym + contributor save contract"
run: |
npx playwright test tests/issue-237-contributors.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[required] issue-255-registration.spec.js — configurable registration fields"
run: |
npx playwright test tests/issue-255-registration.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[required] release-0.7.37-integration.spec.js — merged settings contract"
run: |
npx playwright test tests/release-0.7.37-integration.spec.js \
--config=tests/playwright.config.js \
--workers=1
# The legacy facet scenarios assume a populated development catalog and
# are not isolated from the state left by the preceding E2E steps. Run
# the data-independent regression added by #317 as the required gate.
- name: "[required] catalog-facets.spec.js — request ordering regression"
run: |
npx playwright test tests/catalog-facets.spec.js \
--config=tests/playwright.config.js \
--grep "A newer catalog request aborts and supersedes" \
--workers=1
- name: "[required] data-integrity-audit.spec.js — PR #323 roundtrip and consistency matrix"
run: |
npx playwright test tests/data-integrity-audit.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[required] mobile-api-behaviors.spec.js — availability state contract"
run: |
npx playwright test tests/mobile-api-behaviors.spec.js \
--config=tests/playwright.config.js \
--workers=1
# Activate linked-data plugins before suites whose routes are registered
# only for active plugins. A missing route is now a hard failure.
- name: "Interop plugin preflight"
run: |
npx playwright test tests/interop-00-activate-plugins.spec.js \
--config=tests/playwright.config.js \
--workers=1
# Formerly non-blocking backfill. These are release gates now: no test
# failure is allowed to leave the workflow green.
- name: "[regression/1] book-form-comprehensive.spec.js"
run: |
npx playwright test tests/book-form-comprehensive.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/2] code-quality.spec.js"
run: |
npx playwright test tests/code-quality.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/3] genre-merge-rearrange.spec.js"
run: |
npx playwright test tests/genre-merge-rearrange.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/4] loan-reservation.spec.js"
run: |
npx playwright test tests/loan-reservation.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/5] multisource-scraping.spec.js"
run: |
npx playwright test tests/multisource-scraping.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/6] security-hardening.spec.js"
run: |
npx playwright test tests/security-hardening.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/7] viaf-authority.spec.js"
run: |
npx playwright test tests/viaf-authority.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "[regression/8] interop-specific.spec.js"
run: |
npx playwright test tests/interop-specific.spec.js \
--config=tests/playwright.config.js \
--workers=1
- name: "book-club-uwe.spec.js — meeting/member edit + external book proposals (#138)"
run: |
npx playwright test tests/book-club-uwe.spec.js \
--config=tests/playwright.config.js \
--workers=1
# ── Artifacts on failure ─────────────────────────────────────────────────
- name: Upload Playwright report
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
if: failure()
with:
name: playwright-report-${{ github.run_id }}
path: |
playwright-report/
test-results/
retention-days: 14
- name: Upload Apache error log
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
if: failure()
with:
name: apache-error-log-${{ github.run_id }}
path: /var/log/apache2/pinakes-error.log
retention-days: 7