Files
restic-manager/docs/e2e.md
T
steve 82931684eb
CI / Test (server-http) (pull_request) Successful in 21s
CI / Test (rest) (pull_request) Successful in 23s
CI / Test (store) (pull_request) Successful in 36s
CI / Lint (pull_request) Successful in 27s
CI / Build (windows/amd64) (pull_request) Successful in 26s
CI / Build (linux/arm64) (pull_request) Successful in 23s
CI / Build (linux/amd64) (pull_request) Successful in 1m24s
e2e / Playwright vs docker-compose (pull_request) Failing after 2m52s
P5: OSS readiness — docs site, contributor onboarding, e2e harness
P5-01 — Documentation site under docs/book/ rendered with mdBook
(downloaded via Makefile, same static-binary pattern as Tailwind).
Structured chapters: getting started, concepts, operations,
security, reference. `make docs` / `make docs-watch`. Generated
output gitignored.

P5-02 — CONTRIBUTING.md rewritten from placeholder to a full
guide. CODE_OF_CONDUCT.md adapted from Contributor Covenant for a
single-maintainer project. .gitea/issue_template/{bug,feature}.md
and PULL_REQUEST_TEMPLATE.md.

P5-04 — Six README screenshots captured live from a fresh server
bootstrap (login, empty dashboard, add-host, alerts, settings,
audit log). README rewritten to centre the screenshot grid and
link out to the docs site.

P5-05 — SECURITY.md with disclosure policy (3-day ack, 30-day
default window), scope in/out, threat-model summary, operator
hardening checklist. Mirrored as a docs-site chapter.

P5-06 — End-to-end test harness. e2e/compose.e2e.yml brings up
server + sibling Linux agent (alpine + restic) + restic/rest-server.
Agent uses announce-and-approve so Playwright can drive the full
operator flow: bootstrap → login → accept pending → backup →
verify terminal status. Second spec scrapes /metrics to assert
the P6-04 endpoint surface. .gitea/workflows/e2e.yml runs on every
PR; local how-to in docs/e2e.md.
2026-05-07 23:56:02 +01:00

121 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# End-to-end test harness
The e2e harness stands up the full production-shaped stack
(server + agent + rest-server) in Docker Compose and drives it
through Playwright. CI runs it on every PR; operators can run it
locally too.
## Files
```
e2e/
├── compose.e2e.yml compose stack: server + rest-server + agent
├── Dockerfile.agent Linux container for the agent (alpine + restic)
├── agent-entrypoint.sh decides between announce / token-enrol / run
└── playwright/
├── package.json
├── playwright.config.ts
└── tests/
├── lib/server.ts bootstrap, login, accept, poll helpers
└── smoke.spec.ts happy-path: enrol → backup → succeeded
```
## Local run
Prerequisites: Docker + Docker Compose, and `npx` for Playwright.
```sh
# 1. Build + bring up the stack (server, rest-server, source data).
docker compose -f e2e/compose.e2e.yml up --build -d server rest-server source-fixture
# 2. Wait for the server, then scrape the bootstrap token from the log.
until curl -fsS http://127.0.0.1:8080/api/version >/dev/null; do sleep 1; done
RM_BOOTSTRAP_TOKEN=$(docker compose -f e2e/compose.e2e.yml logs server \
| grep -Eo '[a-zA-Z0-9_-]{40,}' | head -1)
export RM_BOOTSTRAP_TOKEN
# 3. Start the agent (it announces against the running server).
docker compose -f e2e/compose.e2e.yml up -d agent
# 4. Install + run Playwright.
cd e2e/playwright
npm install
npx playwright install --with-deps chromium
npx playwright test
```
When the test passes you'll see:
```
Running 2 tests using 1 worker
✓ smoke: enrol-via-announce → backup happy path completes in under a minute (47s)
✓ smoke: scrape /metrics metrics endpoint exposes the host gauge (180ms)
2 passed (47.5s)
```
Tear-down:
```sh
docker compose -f e2e/compose.e2e.yml down -v
```
`-v` removes the named volumes too — important between runs because
the rest-server volume holds an initialised repo and the
agent-config volume holds a stale bearer.
## What the test exercises
1. **Bootstrap.** Posts the admin-creation request to
`/api/bootstrap` with the token scraped from the server log.
2. **Login (UI).** Drives the login form via Playwright; verifies
the dashboard loads with a session cookie set.
3. **Pending host appears.** Polls the dashboard for the inline
accept form generated by the announcing agent; reads the
pending-id out of its action URL.
4. **Accept.** POSTs `/api/pending-hosts/{id}/accept` with the
rest-server URL + repo password. The server mints a Host row
+ bearer + AEAD-encrypted creds and pushes the bearer down
the still-open pending WebSocket.
5. **Online + auto-init.** Polls `/api/hosts` until the new host
is `status=online`. Auto-init runs as part of this — the
first dispatched job after creds save is `restic init`.
6. **Run backup.** Submits the host detail page's `Run now`
form; expects `HX-Redirect` to the live job page.
7. **Verify.** Polls `/api/hosts` until the host's
`last_backup_status` flips to `succeeded`.
8. **Metrics.** Scrapes `/metrics` and asserts the
server-gauge + build-info lines are present (the compose
stack opens the endpoint via `RM_METRICS_TRUSTED_CIDR=0.0.0.0/0`).
## CI workflow
[`.gitea/workflows/e2e.yml`](../.gitea/workflows/e2e.yml) runs the
suite on every PR into `main`. On failure it dumps the last 200
lines of each container log as a workflow annotation and uploads
the Playwright HTML report as an artefact.
## When tests fail
- **Pending host never appears.** Agent container probably
couldn't reach the server. Check `docker compose logs agent`
for connection errors and `docker compose logs server` for
any 4xx on `/api/agents/announce`.
- **Backup hangs in `running`.** The agent shells out to
`restic`; check the live job log at
`http://127.0.0.1:8080/jobs/<id>` (still up after a
failed test as long as you didn't `down -v`).
- **`RM_BOOTSTRAP_TOKEN not set`.** The server log scrape
matched the wrong line or the token regex is too tight. The
server prints the token on a line starting with ` ` (four
spaces) inside a banner; widen the regex if your server log
format changes.
## Adding new tests
The harness is intentionally flat — one `*.spec.ts` per
scenario. Reuse the helpers in `lib/server.ts` and avoid
duplicating bootstrap / login boilerplate. Heavy fixtures
(custom users, OIDC IdP) belong in their own compose override
file rather than complicating `compose.e2e.yml`.