test(client): Plan 1 — foundation test helpers and client unit coverage#15
Conversation
Full coverage pass — per-module unit tests, route-level integration via in-process Rocket client, wiremock for client HTTP mocking, and a small end-to-end harness against a real spawned server.
Shared test helpers and unit coverage for connection, errors, context, file_watcher, lib JWT extraction, and chunker extensions. Plans 2-6 follow for registry/indexer, remote/syncer, server, and e2e.
Set r2d2 connection_timeout to 1s so pool creation fails quickly on invalid paths instead of waiting the default 30s retry window.
…ath" This reverts commit d459ac4.
The r2d2 pool retries failed establish() for its default 30s connection_timeout, which makes this test a CI time sink. Mark it ignored by default; it can be run explicitly with --ignored when the error path needs verification.
Code Review — Plan 1: Foundation Test Helpers + Client Unit CoverageOverall this is a well-structured, zero-production-change test PR. The test names are descriptive, precondition asserts are used consistently, and the real-filesystem/real-SQLite approach is the right call over mocking. A few things worth addressing before merge: Issues1. Weak error assertions in two chunker tests
let _ = format!("{err:?}");This doesn't assert anything — it only exercises the
Suggested fix: // hashify test
assert!(matches!(err, SyncError::IoError { .. } | SyncError::IoErrorGeneric(_)));
// save test
assert!(matches!(err, SyncError::GetFromCacheError));If pinning is intentionally avoided to allow future refactoring flexibility, at least add 2.
|
| Area | Status |
|---|---|
| Test structure and naming | ✅ Good |
| Real DB/FS (no mocks) | ✅ Correct approach |
#[should_panic] for panic-path JWT tests |
✅ Correct |
#[ignore] for slow r2d2 error path |
✅ Well-documented |
| Error variant assertions | |
| Cache eviction coverage | |
on_complete listener test |
|
| Plan docs in source tree | 💬 Policy question |
Happy to discuss any of these — issues 1 and 2 are the ones most worth fixing before merge.
…n_complete coverage
- hashify missing-file test now asserts SyncError::IoError { .. } instead
of just exercising Debug impl
- save unknown-chunk test asserts SyncError::GetFromCacheError
- Add hashify_then_read_chunk_round_trip_via_cache exercising save_chunk →
read_chunk → check_chunk path that the swapped-in delete test had dropped
- Add on_complete_forwards_success_and_failure_with_message so the
RecordingListener.completions infrastructure is no longer dead code
|
Thanks for the review. Addressed in Fixed:
Not fixing in this PR: PR #16 (stacked on this branch) picks up these fixes automatically after rebase. |
Code Review — Plan 1: Foundation Test Helpers and Client Unit CoverageOverall this is a well-structured PR that adds meaningful test coverage without touching production code. The test organization is clean, helpers are thoughtfully designed, and the PR description is detailed. Below are observations ranging from blocking concerns to minor suggestions. Security
// `extract_uid_from_jwt` does NOT verify the signature, so any placeholder works.
let signature = base64_url_nopad(b"test-signature-unverified");This is fine for the test helper, but the function being tested is used in production to identify users. An attacker who can craft a JWT payload with any Code Quality
Three tests in #[test]
#[should_panic]
fn extract_uid_panics_on_token_with_missing_segments() { … }Any panic — including a test infrastructure panic — will make these pass. Prefer Redundant test in
The plan spec says "delete removes chunk from disk and evicts from cache." The actual test only checks the on-disk file is gone — it doesn't assert that
fn child_tokens_are_independent_of_each_other() {
let ctx = SyncContext::new();
let a = ctx.token();
let b = ctx.token();
a.cancel();
assert!(!b.is_cancelled(), "sibling token should not be affected");
}Unless Potential Bugs / Platform Issues
assert!(
msg.to_lowercase().contains("connection"),
"expected ConnectionInitError message, got: {msg}"
);This relies on
The test is not marked
Minor / Style
The two new files (
It suppresses warnings for all dead code in the module. If What's working well
|
Summary
Implements Plan 1 of a multi-plan test-coverage effort for the
cooklang-sync-clientandcooklang-sync-servercrates. See the design spec indocs/superpowers/specs/2026-04-15-library-test-coverage-design.mdand Plan 1 itself indocs/superpowers/plans/2026-04-15-test-coverage-plan-1-foundation.md.Plan 1 scope: shared test helpers plus leaf-level client module coverage. Later plans (2–6) will cover registry/indexer, remote/syncer, the server, and end-to-end tests.
What's in this PR
client/tests/common/mod.rs— shared helpers:fresh_client_pool(),tempdir_with_files(),sample_jwt()client/tests/connection_tests.rs— pool creation, migrations, checkout (3 tests, 1#[ignore]for the slow r2d2-retry error path)client/tests/context_tests.rs—SyncContextlistener forwarding + parent/child cancellation (6 tests)client/tests/file_watcher_tests.rs—async_watcherfile-event smoke test (1 test)client/tests/lib_jwt_tests.rs— pinsextract_uid_from_jwtsuccess and panic paths (6 tests)client/src/errors.rs— appended#[cfg(test)]block, 4 tests forSyncErrorconversion andDisplayclient/src/chunker.rs— 4 new tests inside existing#[cfg(test)]block:hashifyerror,savemissing-chunk error,delete(path)round-trip, multi-chunk textZero production code changes. One attempted production tweak was reverted during review.
Numbers
cargo test -- --ignored)cargo build --workspaceTest plan
cargo test -p cooklang-sync-client— all greencargo test --workspace— all greencargo build --workspace— no new warningsFollow-up plans
Not in this PR — each will land separately:
registry+indexerintegration testsremote(wiremock) +syncertestschunk_id, metadata models/db/notification, request/response serde)create_serversmoke)