forked from lei.chen/myxce
test(ha-entity-snapshots): RED test for the rotation guard (task 4.2)
A checkpoint file whose position matches an in-flight peer transfer (task 4.1's snapshot_inflight_lsn[]) must survive rotate_snapshots even when snap_keep_n would otherwise delete it. Genuinely fails today (file removed, access() returns -1) since rotate_snapshots has no awareness of in-flight transfers yet. Executed directly (no subagent dispatch) per the hybrid execution-mode decision -- small, single-file, isolated test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JDYFbrgyDHbvNYcxApKhrX
This commit is contained in:
parent
164c9a9d2e
commit
221d86788d
2 changed files with 57 additions and 1 deletions
|
|
@ -57,7 +57,7 @@
|
|||
goes out and cleared after completion
|
||||
- _Requirements: 3.1, 3.2, 3.3_
|
||||
- _Boundary: HA Replication Layer_
|
||||
- [ ] 4.2 RED: rotation-guard test
|
||||
- [x] 4.2 RED: rotation-guard test
|
||||
- Assert a checkpoint file whose position matches an in-flight transfer survives file rotation
|
||||
even when it would otherwise be rotated out
|
||||
- Observable: new test compiles and fails (RED) against the current rotation logic
|
||||
|
|
|
|||
|
|
@ -941,6 +941,61 @@ static void test_snapent_checkpoint_queue_status_roundtrip(void)
|
|||
printf("test_snapent_checkpoint_queue_status_roundtrip: PASS\n");
|
||||
}
|
||||
|
||||
/* ───────────────────────────────────────────────────────────────────────
|
||||
* ha-entity-snapshots Task 4.2 (Req 3.1-3.3): rotation-guard RED test.
|
||||
*
|
||||
* A checkpoint file whose position matches an in-flight peer transfer
|
||||
* (task 4.1's snapshot_inflight_lsn[]) must survive rotate_snapshots even
|
||||
* when it would otherwise fall outside snap_keep_n. RED against today's
|
||||
* rotate_snapshots, which has no awareness of in-flight transfers at all.
|
||||
* ─────────────────────────────────────────────────────────────────────── */
|
||||
static void test_snapent_rotation_preserves_in_flight_checkpoint(void)
|
||||
{
|
||||
snapent_fixture_t* f = snapent_make(0, 0);
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
|
||||
/* Force aggressive rotation so the protected file would otherwise be
|
||||
* deleted after just one more checkpoint cycle. */
|
||||
f->c->persist.config.snap_keep_n = 1;
|
||||
|
||||
/* Round 1: produce the checkpoint file we'll mark as in-flight. */
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
persist_wal_async(&f->c->persist, WAL_JOB_UPDATE, "a", 1));
|
||||
TEST_ASSERT_EQUAL_INT(0, persist_checkpoint(&f->c->persist));
|
||||
uint64_t protected_lsn = f->c->persist.checkpoint_lsn;
|
||||
|
||||
char protected_path[4096];
|
||||
snprintf(protected_path, sizeof(protected_path),
|
||||
"%s/snap-%016" PRIx64 ".capnp",
|
||||
f->c->persist.snap_path, protected_lsn);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, access(protected_path, F_OK),
|
||||
"the checkpoint file must exist right after it is written");
|
||||
|
||||
/* Mark this checkpoint's position as referenced by an in-flight peer
|
||||
* transfer -- the same field/lifecycle task 4.1 wired in ha.c. */
|
||||
atomic_store_explicit(&f->c->ha.snapshot_inflight_lsn[0], protected_lsn,
|
||||
memory_order_release);
|
||||
|
||||
/* Rounds 2-3: with snap_keep_n=1, each further checkpoint would normally
|
||||
* rotate out every older file, including the one marked in-flight. */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
persist_wal_async(&f->c->persist, WAL_JOB_UPDATE, "b", 1));
|
||||
TEST_ASSERT_EQUAL_INT(0, persist_checkpoint(&f->c->persist));
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, access(protected_path, F_OK),
|
||||
"Req 3.1-3.3: a checkpoint file referenced by an in-flight peer "
|
||||
"transfer must survive rotate_snapshots even when snap_keep_n "
|
||||
"would otherwise have deleted it -- rotate_snapshots does not yet "
|
||||
"consult snapshot_inflight_lsn[] (task 4.3 not yet implemented)");
|
||||
|
||||
atomic_store_explicit(&f->c->ha.snapshot_inflight_lsn[0], 0,
|
||||
memory_order_release);
|
||||
snapent_teardown(f);
|
||||
printf("test_snapent_rotation_preserves_in_flight_checkpoint: PASS\n");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Suite entry point */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -966,4 +1021,5 @@ void test_persist_snapshot_entities(void)
|
|||
RUN_TEST(test_snapent_checkpoint_write_failure_leaves_no_final_file);
|
||||
RUN_TEST(test_snapent_checkpoint_mid_encode_failure_discards_whole_file);
|
||||
RUN_TEST(test_snapent_checkpoint_queue_status_roundtrip);
|
||||
RUN_TEST(test_snapent_rotation_preserves_in_flight_checkpoint);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue