FileActionLog (include/morph/journal/file_action_log.hpp) has several branch arms that only run when a real filesystem/stdio call fails partway through an otherwise-successful operation:
append(): std::fwrite returning a short count (line ~146).
flush(): std::fflush failing (~173) or fsync/_commit failing (~182).
rotate(): the pre-rotation std::fflush failing (~278) or fsync/_commit failing (~286); and — the bigger gap — std::fopen failing to reopen the active path after the rename to sealedPath has already succeeded (~305-310). That last one is also what makes the destructor's _file != nullptr guard (~113), requireOpen()'s throwing arm (~322), and the "successful vs failed rename" wording in the reopen-failure message (~308) unreachable from a test — they all require _file to end up null, which today only happens via that one reopen failure.
repairTornTail(): std::ifstream failing to open a path that std::filesystem::file_size just succeeded on (~345), and std::filesystem::resize_file failing while truncating a torn tail (~363).
None of these are reachable from a portable unit test today: they all need a real OS-level failure (disk full, permission revoked mid-call, fd exhaustion, directory removed between two calls) at an exact point between two library calls, and the codebase has no fault-injection seam for file I/O (checked test_support.hpp and sibling test files — the existing deterministic-race idioms there are executor/scheduling hooks, not I/O hooks).
Requested seam: a way to make FileActionLog's file I/O calls (fwrite, fflush, fsync/_commit, fopen for the reopen, and — for repairTornTail() — file_size, opening the ifstream, and resize_file) fail on demand from a test, without changing the class's public behavior for normal callers. Prior art in this repo: SqlLogger-style hooks used for the Lightweight-side pool tracing (see LASTRADA-Software/Lightweight#548) — an analogous "current failure mode" hook, settable only from test code (e.g. an optional injection point threaded through the constructor or a test-only subclass seam), would let each of the branches above be driven directly instead of skipped.
Until this seam exists, these branches are intentionally left uncovered rather than shipping a flaky/hacky test (e.g. filling the disk, revoking permissions mid-test, or racing directory removal). Each site has an in-code comment pointing back to this issue.
FileActionLog(include/morph/journal/file_action_log.hpp) has several branch arms that only run when a real filesystem/stdio call fails partway through an otherwise-successful operation:append():std::fwritereturning a short count (line ~146).flush():std::fflushfailing (~173) orfsync/_commitfailing (~182).rotate(): the pre-rotationstd::fflushfailing (~278) orfsync/_commitfailing (~286); and — the bigger gap —std::fopenfailing to reopen the active path after the rename tosealedPathhas already succeeded (~305-310). That last one is also what makes the destructor's_file != nullptrguard (~113),requireOpen()'s throwing arm (~322), and the "successful vs failed rename" wording in the reopen-failure message (~308) unreachable from a test — they all require_fileto end up null, which today only happens via that one reopen failure.repairTornTail():std::ifstreamfailing to open a path thatstd::filesystem::file_sizejust succeeded on (~345), andstd::filesystem::resize_filefailing while truncating a torn tail (~363).None of these are reachable from a portable unit test today: they all need a real OS-level failure (disk full, permission revoked mid-call, fd exhaustion, directory removed between two calls) at an exact point between two library calls, and the codebase has no fault-injection seam for file I/O (checked
test_support.hppand sibling test files — the existing deterministic-race idioms there are executor/scheduling hooks, not I/O hooks).Requested seam: a way to make
FileActionLog's file I/O calls (fwrite,fflush,fsync/_commit,fopenfor the reopen, and — forrepairTornTail()—file_size, opening theifstream, andresize_file) fail on demand from a test, without changing the class's public behavior for normal callers. Prior art in this repo:SqlLogger-style hooks used for the Lightweight-side pool tracing (seeLASTRADA-Software/Lightweight#548) — an analogous "current failure mode" hook, settable only from test code (e.g. an optional injection point threaded through the constructor or a test-only subclass seam), would let each of the branches above be driven directly instead of skipped.Until this seam exists, these branches are intentionally left uncovered rather than shipping a flaky/hacky test (e.g. filling the disk, revoking permissions mid-test, or racing directory removal). Each site has an in-code comment pointing back to this issue.