test(peer-cli): document full manual scenario pass
Record the May 18 manual Docker pass over PEER_CLI_SCENARIOS.md so the scenario matrix has current evidence for every row. The run log now covers the clean direct-connect and aggregation rerun, exact diff checks for downloaded files, custom renamed-RAR fixtures for conflict and version-skew cases, and the latest-only transfer behavior for S15-S17. S12 remains verified by unit tests instead of a CLI race because the raw serving gates are below the peer-cli command surface. The run log names the exact tests that cover the non-catalog, missing-sentinel, active-operation, and local-path serving gates. Test Plan: - just peer-cli-image - RUSTC_WRAPPER= just peer-cli-build - manual Docker peer-cli runs for S1-S17 using JSONL stdin commands - diff -r transferred game directories against source fixture directories - just fmt - RUSTC_WRAPPER= just test - RUSTC_WRAPPER= just clippy - git diff --check Refs: PEER_CLI_SCENARIOS.md
This commit is contained in:
@@ -22,9 +22,124 @@ for deterministic local runs; mDNS/macvlan remains an environment smoke path.
|
|||||||
| S12 | Transfer serving gates | A peer has a non-catalog, missing-sentinel, active-operation, or `local/` path request. | The serving peer declines metadata/data; covered by unit tests where timing is too small for a stable CLI race test. |
|
| S12 | Transfer serving gates | A peer has a non-catalog, missing-sentinel, active-operation, or `local/` path request. | The serving peer declines metadata/data; covered by unit tests where timing is too small for a stable CLI race test. |
|
||||||
| S13 | Exact transferred-file equality | Repeat small and large downloads, then compare every transferred regular file against its source with SHA-256 manifests. | Source and receiver manifests match exactly for each transferred file; no extra or missing files appear in the downloaded game root. |
|
| S13 | Exact transferred-file equality | Repeat small and large downloads, then compare every transferred regular file against its source with SHA-256 manifests. | Source and receiver manifests match exactly for each transferred file; no extra or missing files appear in the downloaded game root. |
|
||||||
| S14 | Large multi-peer chunked download | `fixture-alpha/alienswarm` contains a renamed RAR `.eti` larger than 100 MB. A second peer downloads it, then a third peer downloads `alienswarm` from both peers. | The third peer's downloaded files match the source by SHA-256; `download-chunk-finished` events show the large `.eti` chunks coming from both peers with byte counts balanced within one chunk. |
|
| S14 | Large multi-peer chunked download | `fixture-alpha/alienswarm` contains a renamed RAR `.eti` larger than 100 MB. A second peer downloads it, then a third peer downloads `alienswarm` from both peers. | The third peer's downloaded files match the source by SHA-256; `download-chunk-finished` events show the large `.eti` chunks coming from both peers with byte counts balanced within one chunk. |
|
||||||
|
| S15 | Three-way version skew | Three peers advertise the same catalog game ID. Peer A has `version.ini=20250101`, peer B has `version.ini=20250201`, and peer C has `version.ini=20250301`; each version has distinguishable file contents. An empty client connects to all three and downloads the game with `install=false`. | `list-games` shows one row for the game with `peer_count=3` and `eti_game_version=20250301`. The `got-game-files` descriptor set and transfer source are peer C's newest version only; no chunks come from A or B. The receiver's `version.ini` and SHA-256 manifest match C exactly. |
|
||||||
|
| S16 | Latest-version fanout with stale peers present | Peer A has an older version of a game. Peers B and C both advertise the same newest version with matching file manifests; use a large file when proving chunk split. | The aggregated row still counts all ready peers, but eligible transfer peers are only B and C. Large-file chunks may split between B and C; peer A contributes no manifest majority vote and no file chunks. |
|
||||||
|
| S17 | Latest-version conflict rejection | Peer A has an older version. Peers B and C both advertise the newest version, but their latest-version file sizes conflict. | Validation considers only the latest-version peers, so A cannot rescue the majority. The download fails with `download-failed`, and no committed target `version.ini` remains. |
|
||||||
|
|
||||||
|
## Version-Skew Contract
|
||||||
|
|
||||||
|
Use S15-S17 to pin down what "newer" means when several peers have the same
|
||||||
|
game ID:
|
||||||
|
|
||||||
|
- Version comparison uses the eight-digit `version.ini` string, so use sortable
|
||||||
|
`YYYYMMDD` values in manual fixtures.
|
||||||
|
- `list-games` aggregates by game ID. The game appears once; `peer_count`
|
||||||
|
counts all ready peers with that ID, including peers that only have older
|
||||||
|
versions.
|
||||||
|
- The aggregated `eti_game_version` must be the newest ready version.
|
||||||
|
- The descriptor set emitted to the download path, file-size validation, and
|
||||||
|
transfer planning are latest-only. Older-version peers may be queried by a
|
||||||
|
generic detail request, but their descriptors must not supply download
|
||||||
|
descriptors, majority votes, or chunks once a newer version exists.
|
||||||
|
- If exactly one peer has the latest version, that peer is the only transfer
|
||||||
|
source. If several peers tie on the latest version, validation and chunk
|
||||||
|
fanout happen among that latest-version set only.
|
||||||
|
- Capture proof with the `list-games` row, `got-game-files` descriptors,
|
||||||
|
`download-chunk-finished` source addresses, and source/receiver SHA-256
|
||||||
|
manifests.
|
||||||
|
|
||||||
|
For a manual run, prefer a catalog game ID already served by the fixture lab,
|
||||||
|
such as `cnc4`, then create temporary `just peer-cli-run` game roots with
|
||||||
|
different `version.ini` contents. The existing alpha/bravo/charlie fixtures
|
||||||
|
cover duplicate-source and shared-game cases, but not the three-version skew
|
||||||
|
until a dedicated fixture or temporary games root is prepared.
|
||||||
|
|
||||||
## Run Log
|
## Run Log
|
||||||
|
|
||||||
|
### 2026-05-18 - Full Matrix Manual Docker Pass
|
||||||
|
|
||||||
|
- Build/setup: `just peer-cli-image` passed. Local `just peer-cli-build`
|
||||||
|
needed `RUSTC_WRAPPER=` because the host `kache` wrapper failed with a
|
||||||
|
read-only filesystem error; `RUSTC_WRAPPER= just peer-cli-build` passed.
|
||||||
|
- Temporary skew/conflict fixtures were created under the ignored
|
||||||
|
`.lanspread-peer-cli/full-fixtures/` tree using `rar a -idq -m0` against
|
||||||
|
`/dev/urandom` payloads and then renaming the archives to `.eti`.
|
||||||
|
`find .lanspread-peer-cli/full-fixtures -name '*.eti' -exec unrar t -idq {} \;`
|
||||||
|
passed.
|
||||||
|
- S1 startup scan: `just peer-cli-alpha` emitted `cli-started`,
|
||||||
|
`local-library-changed`, and `local-peer-ready`; `alienswarm`, `bf1942`, and
|
||||||
|
`ggoo` were `downloaded=true`, `installed=false`, `availability=Ready`.
|
||||||
|
- S2 clean direct connect: with only alpha and bravo running, alpha connected to
|
||||||
|
bravo at `10.66.0.3:42776`; `wait-peers` returned `peer_count=1`, and
|
||||||
|
`list-peers` showed exactly one bravo peer with four games.
|
||||||
|
- S3 clean remote aggregation: an empty `clean-s3-client` saw exactly alpha and
|
||||||
|
bravo. `list-games` showed `ggoo peer_count=2`; `alienswarm`, `bf1942`,
|
||||||
|
`bfbc2`, `cnc4`, and `cnctw` each had `peer_count=1`.
|
||||||
|
- S4 single-source no-install: `full-empty-client` downloaded `bfbc2` from
|
||||||
|
bravo with `install=false`. Events included `got-game-files`,
|
||||||
|
`download-begin`, `download-finished`, and local `installed=false`. Host
|
||||||
|
verification: `diff -r crates/lanspread-peer-cli/fixtures/fixture-bravo/bfbc2
|
||||||
|
.lanspread-peer-cli/full-empty-client/games/bfbc2` passed and `local/` was
|
||||||
|
absent.
|
||||||
|
- S5 auto-install: `full-empty-client` downloaded `cnctw` with default install.
|
||||||
|
Events included download finish, `install-begin`, and `install-finished`;
|
||||||
|
`local/fixture-payload.txt` existed. Host verification diffed the downloaded
|
||||||
|
files against `fixture-bravo/cnctw` excluding `local/` and `.lanspread.json`.
|
||||||
|
- S6 manual install/uninstall: after S4, `install bfbc2` created `local/` and
|
||||||
|
marked `installed=true`; `uninstall bfbc2` removed `local/` and preserved the
|
||||||
|
downloaded root files. Host verification diffed the preserved files against
|
||||||
|
`fixture-bravo/bfbc2` excluding `.lanspread.json`.
|
||||||
|
- S7 duplicate-source download: `full-empty-client` downloaded shared `ggoo`
|
||||||
|
from alpha/bravo with `install=false`. Chunk events used alpha for
|
||||||
|
`version.ini` and bravo for `ggoo.eti`; host `diff -r` matched both
|
||||||
|
`fixture-alpha/ggoo` and `fixture-bravo/ggoo`.
|
||||||
|
- S8 ambiguous metadata rejection: `full-s8-a` and `full-s8-b` both advertised
|
||||||
|
`ggoo` version `20260101` but with different `.eti` sizes (`1,048,746` and
|
||||||
|
`2,097,323` bytes). The client saw `peer_count=2`, then `download ggoo`
|
||||||
|
emitted `download-failed`; no target `ggoo/version.ini` was committed.
|
||||||
|
- S9 missing game: `download does-not-exist` emitted `no-peers-have-game` and
|
||||||
|
returned a command error; `.lanspread-peer-cli/full-empty-client/games` had no
|
||||||
|
`does-not-exist` directory.
|
||||||
|
- S10 shutdown cleanup: alpha saw bravo before shutdown with one remote peer and
|
||||||
|
bravo-only remote games. After bravo `shutdown`, alpha emitted `peer-lost`;
|
||||||
|
`list-peers` returned `[]` and `list-games` returned an empty remote list.
|
||||||
|
- S11 same identity reconnect: restarting bravo reused peer ID
|
||||||
|
`019e347d901e70c19adf5b9fd313fce4` at new address `10.66.0.3:41764`.
|
||||||
|
Alpha `list-peers` showed exactly one bravo entry at the new address.
|
||||||
|
- S12 transfer serving gates: this remains covered by unit tests because the
|
||||||
|
CLI cannot stably race raw transfer requests against non-catalog, missing
|
||||||
|
sentinel, active-operation, and `local/` path states. `RUSTC_WRAPPER= just
|
||||||
|
test` passed, including `local_download_available_gates_on_catalog_operation_and_sentinel`,
|
||||||
|
`get_game_response_respects_serve_gates`,
|
||||||
|
`file_transfer_dispatch_respects_serve_gates`, and
|
||||||
|
`local_relative_paths_are_never_transferable`.
|
||||||
|
- S13 exact transferred-file equality: the S4 small transfer and S14 large
|
||||||
|
transfer both passed host `diff -r` against the original source game
|
||||||
|
directories, proving exact file equality beyond event flow.
|
||||||
|
- S14 large multi-peer chunked download: `full-empty-client` first downloaded
|
||||||
|
`alienswarm` from alpha and diffed cleanly against `fixture-alpha/alienswarm`.
|
||||||
|
A fresh `full-s14-client` then saw `alienswarm peer_count=2` and downloaded
|
||||||
|
from both alpha and `full-empty-client`. Large `.eti` chunk totals were
|
||||||
|
`67,108,864` bytes from alpha and `58,721,049` bytes from the staged peer,
|
||||||
|
balanced within one `32 MiB` chunk. Final host `diff -r` against
|
||||||
|
`fixture-alpha/alienswarm` passed.
|
||||||
|
- S15 three-way version skew: peers A/B/C advertised `cnc4` versions
|
||||||
|
`20250101`, `20250201`, and `20250301`. The client saw one row with
|
||||||
|
`peer_count=3` and `eti_game_version=20250301`; all chunks came only from C
|
||||||
|
at `10.66.0.4:60290`. Host `diff -r` against C passed.
|
||||||
|
- S16 latest-version fanout with stale peer present: A advertised stale
|
||||||
|
`20250101`; B/C both advertised latest `20250301` with a `134,217,906` byte
|
||||||
|
`.eti`. The client saw `peer_count=3`; chunks came only from B/C
|
||||||
|
(`67,108,873` and `67,109,042` bytes respectively), with stale A contributing
|
||||||
|
zero. Host `diff -r` matched both B and C.
|
||||||
|
- S17 latest-version conflict rejection: A advertised stale `20250101`; B/C
|
||||||
|
both advertised latest `20250301` but with conflicting `.eti` sizes
|
||||||
|
(`1,048,748` and `2,097,325` bytes). The client saw `peer_count=3` and latest
|
||||||
|
`20250301`, then `download cnc4` emitted `download-failed`; no target
|
||||||
|
`cnc4/version.ini` was committed.
|
||||||
|
- Gates after manual runs: `just fmt`, `RUSTC_WRAPPER= just test`, and
|
||||||
|
`RUSTC_WRAPPER= just clippy` passed.
|
||||||
|
|
||||||
### 2026-05-17 - Exact Transfer And Large Multi-Peer Chunking
|
### 2026-05-17 - Exact Transfer And Large Multi-Peer Chunking
|
||||||
|
|
||||||
- Fixture update: `fixture-alpha/alienswarm/alienswarm.eti` was rebuilt with
|
- Fixture update: `fixture-alpha/alienswarm/alienswarm.eti` was rebuilt with
|
||||||
|
|||||||
Reference in New Issue
Block a user