85 lines
4.3 KiB
Markdown
85 lines
4.3 KiB
Markdown
# Local 2×2 route E2E
|
||
|
||
This harness runs one bot-free control stack plus four isolated data-node
|
||
Compose projects. Every data node contains its own qBittorrent, Syncthing, and
|
||
archive-client containers and its own bind-mounted config, secrets, state,
|
||
backup, qB data, and sync roots. The stacks share only the explicitly named
|
||
`archive-control-e2e` network.
|
||
|
||
The initial scenario starts with no route folders. With the control policy set
|
||
to `eager_mesh`, two cache and two archive registrations must produce four
|
||
independent, bidirectionally verified Syncthing routes. The assertion talks to
|
||
the loopback-only test adapter through a curl sidecar sharing the control
|
||
container's network namespace; Telegram is not initialized.
|
||
|
||
Run from the archive-clients checkout:
|
||
|
||
```bash
|
||
./e2e/scripts/up.sh
|
||
./e2e/scripts/logs.sh
|
||
./e2e/scripts/down.sh
|
||
```
|
||
|
||
`up.sh` defaults `ARCHIVE_CONTROL_SOURCE` to the sibling playground
|
||
`mogic-bot/mogic-repo` checkout. Set that environment variable to test another
|
||
control worktree. `E2E_WAIT_SECONDS` overrides the 360-second assertion
|
||
deadline. `down.sh` removes only the five exact Compose projects and the
|
||
labelled E2E network; it intentionally retains all bind-mounted runtime state.
|
||
|
||
Set `E2E_RUN_TRANSFER=1` to follow route verification with a real
|
||
cache-1 → archive-1 transfer, covered cache-1 eviction, and
|
||
archive-1 → cache-2 unarchive. The scenario creates a deterministic one-file
|
||
torrent in the isolated cache qBittorrent, uses fresh preview revisions for all
|
||
jobs, waits for the durable five/three/five-step flows, and verifies target
|
||
qBittorrent selections, archive retention, safe cache removal, and target file
|
||
digests.
|
||
|
||
Set `E2E_RUN_COMPLEX=1` to run the Phase 8 selective and recovery matrix. It
|
||
uses a four-file torrent with complementary cache selections to verify
|
||
selective archive placement, multi-job archive/cache merging, union coverage
|
||
across two archive nodes, uncovered/no-op/stale-preview rejection, and
|
||
retention of shared and unknown files during eviction. It then pauses the
|
||
test scheduler at durable boundaries to verify record-only queued
|
||
cancellation, rollback after target materialization, control restart after
|
||
source staging, and command replay after a target client disconnect. The final
|
||
hostile cases change the source selection and make an absent target appear
|
||
after confirmation; each must fail before commit with its exact precondition
|
||
reason. qBittorrent is also checked for zero downloaded bytes at the replayed
|
||
target. Finally, a wrong-size pre-existing target and an unwritable target root
|
||
must fail without committing or losing the source; the permission fixture
|
||
restores the target root's original mode even on an aborted run.
|
||
|
||
The scheduler pause/resume endpoints exist only on the loopback test adapter;
|
||
normal control and Telegram orchestration always use the automatic scheduler.
|
||
|
||
Set `E2E_RUN_ADVERSARIAL=1` to run the Phase 8 v2/fault tranche in
|
||
one pass. The scenario performs archive → eviction → unarchive round trips for
|
||
a pure-v2 torrent and a hybrid torrent, checking that hybrid placements retain
|
||
both identities. It then:
|
||
|
||
- leaves a Syncthing command durable while archive-2 is offline, waits beyond
|
||
the five-second E2E stall threshold, verifies the job retains overall
|
||
progress while `STALLED`, and reconnects the client to finish it;
|
||
- recreates archive-2 with `client-exhausted.toml`, whose impossible free-space
|
||
reserve exercises the real capacity guard without consuming disk, and
|
||
verifies a precise precommit failure with the source intact; and
|
||
- runs a separate `protocol-probe` container in the control network namespace.
|
||
The probe sends job event 2 before event 1, requires a snapshot request and
|
||
stale-state error, sends event 1 twice, and replays event 2 to prove
|
||
reordered convergence and duplicate idempotency over the real WebSocket.
|
||
|
||
The adversarial script restores the normal archive-2 client configuration and
|
||
automatic scheduler through an exit trap. It passed from a clean five-project
|
||
topology on 2026-07-23. Run it with:
|
||
|
||
```bash
|
||
E2E_RUN_ADVERSARIAL=1 \
|
||
ARCHIVE_CONTROL_SOURCE=/path/to/mogic-bot \
|
||
./e2e/scripts/up.sh
|
||
```
|
||
|
||
The Syncthing 2.1.2 and LinuxServer qBittorrent multi-platform image indexes are
|
||
digest-pinned. Runtime secrets are generated with mode 0600 and ignored by
|
||
Git. The qBittorrent test config limits its authentication bypass to the
|
||
isolated E2E network and must never be reused for deployment.
|