From 6f853d3768ceb2f6b81803b78484e6fd9b00acf7 Mon Sep 17 00:00:00 2001 From: Aman Kumar Date: Fri, 6 Feb 2026 16:26:43 +0530 Subject: [PATCH] fix(test): enforce durability invariant after fsync Use crash_info.label to differentiate expected states: - Before fsync: any prefix is acceptable - After fsync: both records MUST be present Addresses review feedback on #23 --- tests/canonical_append_log.rs | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/canonical_append_log.rs b/tests/canonical_append_log.rs index 6c1ab94..a1cc25c 100644 --- a/tests/canonical_append_log.rs +++ b/tests/canonical_append_log.rs @@ -36,18 +36,29 @@ fn append_log_atomicity() { let records: Vec<_> = contents.lines().collect(); - // INVARIANT: Records are prefix-consistent - // Either: [], ["RECORD1"], or ["RECORD1", "RECORD2"] - // Never: ["RECORD2"] alone (would violate append-only semantics) - - match records.as_slice() { - [] => { /* Nothing persisted - fine */ } - ["RECORD1"] => { /* Partial - fine */ } - ["RECORD1", "RECORD2"] => { /* Complete - fine */ } - other => { + // INVARIANT: Records are prefix-consistent, with durability enforcement + // + // Before fsync: any prefix is acceptable ([], ["RECORD1"], or both) + // After fsync: both records MUST be present (fsync guarantees durability) + + match (crash_info.label.as_str(), records.as_slice()) { + // After write_1: nothing or RECORD1 is fine + ("after_write_1", []) => {} + ("after_write_1", ["RECORD1"]) => {} + + // After write_2: nothing, RECORD1, or both is fine (not yet synced) + ("after_write_2", []) => {} + ("after_write_2", ["RECORD1"]) => {} + ("after_write_2", ["RECORD1", "RECORD2"]) => {} + + // After fsync: MUST have both records (durability guarantee) + ("after_fsync", ["RECORD1", "RECORD2"]) => {} + + // Any other state is a violation + (label, state) => { panic!( "Invariant violation at '{}': unexpected log state {:?}", - crash_info.label, other + label, state ); } }