test(peer-cli): verify protocol 8 transfer lifecycle

Replace legacy metadata and relay expectations with current protocol-8 JSONL
assertions. Scenarios now bind every source to authenticated PeerId and exact
ContentId, prove typed attempt lifecycle order, and fence cancellation,
quarantine, rollback, republishing, and peer-departure outcomes against vacuous
success.

Isolated topologies distinguish direct author pulls from relay and ambient mDNS
substitution. The run log records focused diagnostics and the final fresh-image
S1-S49 acceptance result without presenting Docker-host throughput as a
representative external-LAN measurement.

Test Plan:
- `LANSPREAD_S37_MIN_MIB_PER_S=100 just peer-cli-tests` -- passed S1-S49
- S37 -- passed 2,147,483,656 bytes in 17 chunks at 551.10 MiB/s
- `python3 -m py_compile crates/lanspread-peer-cli/scripts/run_extended_scenarios.py` -- passed
- `ruff check --select F,E9 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-10 14:00:03 +02:00
parent 71dbf27d8b
commit 4a1b08db98
3 changed files with 2441 additions and 515 deletions
+31 -2
View File
@@ -17,8 +17,12 @@ Useful flags:
- `--games-dir PATH` stores local archives and installs.
- `--state-dir PATH` stores the generated peer identity.
- `--identity-file PATH` loads one existing peer identity strictly. Missing or
invalid files fail startup without repair, quarantine, or fallback.
- `--catalog-db PATH` and `--manifests-dir PATH` select one coherent catalog
authority profile.
- `--fixture GAME_ID` seeds a tiny archive that the fixture unpacker can
install.
install. The selected profile must already authorize that exact fixture.
## Fixture Game Directories
@@ -29,6 +33,27 @@ catalog-backed fake games. Each game includes `version.ini` and a real RAR
archive renamed to `.eti`; `fixture-alpha` and `fixture-bravo` share `ggoo`,
while `fixture-bravo` and `fixture-charlie` share `cnc4`.
The checked-in `catalogs/default` profile authorizes the normal alpha, bravo,
charlie, and persona packages. `catalogs/solid` and `catalogs/multi` are
separate authorities because their `cnctw` packages intentionally contain
different bytes and extracted layouts. `catalogs/unknown` is a source-only
`cod2` profile used to prove that another peer's honest catalog cannot extend
the client's local catalog.
Regenerate and verify the profiles with:
```bash
just fixture-catalogs
just fixture-catalogs-check
```
Both commands use the Rust catalog publisher. Dynamic sparse and many-file
acceptance packages use the same test-only generator through
`just fixture-download-only-catalog` or `just fixture-catalog`; the Python
scenario runner never derives hashes or catalog rows itself. Production
artifacts are a separate corpus and are checked by
`just catalog-check-production`.
## Commands
Every command is a JSON object with `cmd` or `command`; `id` is optional and is
@@ -37,7 +62,7 @@ echoed back on the result or error line.
```json
{"id":"s1","cmd":"status"}
{"id":"p1","cmd":"wait-peers","count":1,"timeout_ms":5000}
{"id":"c1","cmd":"connect","addr":"127.0.0.1:34567"}
{"id":"c1","cmd":"connect","peer_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","addr":"127.0.0.1:34567"}
{"id":"g1","cmd":"list-games"}
{"id":"d1","cmd":"download","game_id":"fixture-one","install":true}
{"id":"i1","cmd":"install","game_id":"fixture-one"}
@@ -45,6 +70,10 @@ echoed back on the result or error line.
{"id":"q1","cmd":"shutdown"}
```
`connect` requires the target's `peer_id` and `addr` from the same
`local-peer-ready` event. Address-only connects are rejected because the peer ID
is the TLS identity pin, not descriptive metadata.
The `status` result includes receiver-side `active_operations` and sender-side
`active_outbound_transfers` counts by game ID, which the scenario runner uses to
verify transfer lifecycle cleanup.