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
80 lines
3.1 KiB
Markdown
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.
|