Goal (M9 — finish the ocpi-cli test coverage started in #230/#231)
#231 gives the ocpi validate subcommand end-to-end coverage, but the CLI's other command — ocpi versions <url> --token <TOKEN> — is still untested because it needs a live /versions peer. This issue closes that last gap by driving ocpi versions against an in-process axum loopback server, exactly as the ocpi-client M2–M8 tests do.
Scope
- Add a dev-dependency on
axum + tokio test plumbing to crates/ocpi-cli (the same loopback harness the client tests already use), or — to keep ocpi-cli dependency-free — assert the command's output against a recorded-fixture server if a lighter approach is viable. Prefer reusing the existing ocpi-server versions_router / VersionsConfig so the test exercises the real advertise path.
crates/ocpi-cli/tests/versions.rs: bind versions_router on 127.0.0.1:0, run ocpi versions http://127.0.0.1:<port>/ --token <TOKEN> via CARGO_BIN_EXE_ocpi, and assert stdout lists each advertised {version}\t{url} line (e.g. 2.2.1), and that a wrong token / unreachable host exits non-zero without a panic.
- Keep it reviewable (≤ ~150 LOC). Justify the new dev-dependency in the PR body per the charter's "no new deps without justification" rule (dev-only, mirrors the existing client test harness).
Real use case — why this matters
ocpi-rs is consumed by evlinked/charge-hub (a hosted OCPI roaming Hub) and evlinked/stationlink. ocpi versions is the first command an operator runs when onboarding a new roaming partner — "what OCPI versions does this party actually advertise?" — so its output (and its clean failure on a bad token / unreachable host) is load-bearing during partner setup. A loopback smoke test pins that the CLI's negotiation front door prints the advertised catalogue faithfully and fails cleanly, completing the definition-of-done coverage for the SDK's user-facing binary.
Acceptance criteria
Spec / references
Filed by the nightly routine as M9 grooming — the open-PR queue is at the 5-PR cap (#223, #226, #227, #229, #231), so per the "queue full → groom the next slice instead of a 6th PR" rule no new implementation PR was opened. This is the natural, non-overlapping next slice: it completes the ocpi-cli coverage #231 begins. Claude session: https://claude.ai/code/session_01MA613RoGnMMjQh2RePd4oL
Goal (M9 — finish the
ocpi-clitest coverage started in #230/#231)#231 gives the
ocpi validatesubcommand end-to-end coverage, but the CLI's other command —ocpi versions <url> --token <TOKEN>— is still untested because it needs a live/versionspeer. This issue closes that last gap by drivingocpi versionsagainst an in-processaxumloopback server, exactly as theocpi-clientM2–M8 tests do.Scope
axum+tokiotest plumbing tocrates/ocpi-cli(the same loopback harness the client tests already use), or — to keepocpi-clidependency-free — assert the command's output against a recorded-fixture server if a lighter approach is viable. Prefer reusing the existingocpi-serverversions_router/VersionsConfigso the test exercises the real advertise path.crates/ocpi-cli/tests/versions.rs: bindversions_routeron127.0.0.1:0, runocpi versions http://127.0.0.1:<port>/ --token <TOKEN>viaCARGO_BIN_EXE_ocpi, and assert stdout lists each advertised{version}\t{url}line (e.g.2.2.1), and that a wrong token / unreachable host exits non-zero without a panic.Real use case — why this matters
ocpi-rsis consumed by evlinked/charge-hub (a hosted OCPI roaming Hub) and evlinked/stationlink.ocpi versionsis the first command an operator runs when onboarding a new roaming partner — "what OCPI versions does this party actually advertise?" — so its output (and its clean failure on a bad token / unreachable host) is load-bearing during partner setup. A loopback smoke test pins that the CLI's negotiation front door prints the advertised catalogue faithfully and fails cleanly, completing the definition-of-done coverage for the SDK's user-facing binary.Acceptance criteria
crates/ocpi-cli/tests/versions.rsdrivesocpi versionsagainst an in-process loopback server and asserts the advertised versions are listed; a failure path (bad token / unreachable host) exits non-zero, no panic.cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings,cargo test --workspace --all-featuresgreen.unsafe; no public type changes.Spec / references
specs/ocpi/2.2.1/version_information_endpoint.asciidoc— theGET /versionscontract the command exercises.crates/ocpi-client/tests/m2_registration.rs(and siblings) — the in-processaxumloopback harness this mirrors.ocpi-clihas zero tests — add end-to-end integration coverage forocpi validate#230 / test(M9): end-to-end integration coverage for theocpi validateCLI #231 — theocpi validatecoverage this completes.Filed by the nightly routine as M9 grooming — the open-PR queue is at the 5-PR cap (#223, #226, #227, #229, #231), so per the "queue full → groom the next slice instead of a 6th PR" rule no new implementation PR was opened. This is the natural, non-overlapping next slice: it completes the
ocpi-clicoverage #231 begins. Claude session: https://claude.ai/code/session_01MA613RoGnMMjQh2RePd4oL