Files
ddidderr 4a1b08db98 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
2026-08-10 14:00:03 +02:00

80 lines
3.1 KiB
Markdown

# lanspread-peer-cli
Scriptable peer harness for automated LAN-spread tests. The binary starts the
core peer runtime without the Tauri GUI, reads one JSON command per stdin line,
and writes JSONL events, results, and errors to stdout.
## Running
```bash
just peer-cli-build
just peer-cli-image
just peer-cli-tests
just peer-cli-run alpha
```
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. The selected profile must already authorize that exact fixture.
## Fixture Game Directories
`fixtures/fixture-alpha`, `fixtures/fixture-bravo`, and
`fixtures/fixture-charlie` are ready-to-use game directories for local CLI smoke
tests. Point `--games-dir` at one of them to start a peer with several
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
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","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"}
{"id":"u1","cmd":"uninstall","game_id":"fixture-one"}
{"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.