Skip to content

Test replay persistence failure paths - #1858

Open
Jolah1 wants to merge 1 commit into
payjoin:masterfrom
Jolah1:rust-replay-persistence-failures
Open

Test replay persistence failure paths#1858
Jolah1 wants to merge 1 commit into
payjoin:masterfrom
Jolah1:rust-replay-persistence-failures

Conversation

@Jolah1

@Jolah1 Jolah1 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Closes #1857.

What

Add a fault-injecting session persister, then assert that replay_event_log and replay_event_log_async surface PersistenceFailure when load() or when close() fails, in both the receive and send sessions.

Also covers the in-memory persisters' happy paths directly: a fresh persister loads nothing, load() replays events in save order without consuming the log, and close() marks the session closed while leaving the log readable.

Why

The eight PersistenceFailure construction sites were unreachable from any test. The only persisters in the tree declare type InternalStorageError = std::convert::Infallible;, so their load() and close() cannot fail, and the variant appeared in no assertion.

Notes

Split out of #1835, which was retargeted to the FFI binding coverage #1325 asks for. This carries the review feedback from that PR:

  • test-only items grouped in a single #[cfg(test)] pub(crate) mod test_support
  • assertions match on the error variant and downcast to the injected storage error, rather than comparing Display strings
  • replay_surfaces_close_failure documents the error-replacement chain: replay closes the session on an invalid log, so a close failure replaces the replay error

Tests

  • cargo test -p payjoin --all-features
  • cargo clippy -p payjoin --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check

Disclosure: co-authored by Claude Code. The tests, the commit message and this PR body were generated by Claude Code, reviewed and verified by me.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VLcgR2FZhENW7ZfxHS2Rse

The in-memory persisters used by the existing tests are infallible, so
the error paths where replay maps a storage failure into ReplayError
were never exercised, and neither load() nor close() had direct
coverage of their successful behavior.

Add fault-injecting sync and async persisters under a single test-only
module, and assert that sender and receiver replay surface a failure
from load() and from the close() that replay performs when the event
log is invalid. Assertions match on the error variant and downcast to
the injected storage error rather than comparing Display strings, so
rewording a message does not break them.

Also cover the happy paths directly: a fresh persister loads nothing,
load() replays events in save order without consuming the log, and
close() marks the session closed while leaving the log readable.
@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 33745316388

Coverage increased (+0.07%) to 86.712%

Details

  • Coverage increased (+0.07%) from the base build.
  • Patch coverage: 17 uncovered changes across 2 files (133 of 150 lines covered, 88.67%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
payjoin/src/core/persist.rs 102 86 84.31%
payjoin/src/core/error.rs 5 4 80.0%
Total (4 files) 150 133 88.67%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 16624
Covered Lines: 14415
Line Coverage: 86.71%
Coverage Strength: 340.25 hits per line

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replay persistence failure paths are unreachable in tests

2 participants