huskies: merge 1111 bug Test isolation: init_for_test() and ensure_content_store() are once-per-thread, not once-per-test, polluting CRDT state across tests
This commit is contained in:
@@ -165,7 +165,9 @@ pub fn delete_content(key: ContentKey<'_>) {
|
||||
|
||||
/// Ensure the in-memory content store is initialised.
|
||||
///
|
||||
/// Safe to call multiple times — the `OnceLock` is set at most once.
|
||||
/// In non-test builds: init-once via `OnceLock` (safe to call multiple times).
|
||||
/// In test builds: always resets `CONTENT_STORE_TL` to an empty `HashMap` so
|
||||
/// each test on the same thread starts with a clean store.
|
||||
pub fn ensure_content_store() {
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
@@ -175,7 +177,11 @@ pub fn ensure_content_store() {
|
||||
#[cfg(test)]
|
||||
{
|
||||
CONTENT_STORE_TL.with(|lock| {
|
||||
if lock.get().is_none() {
|
||||
if let Some(mutex) = lock.get() {
|
||||
// Already initialised on this thread — reset to empty so the
|
||||
// next test does not see content written by a previous test.
|
||||
mutex.lock().unwrap().clear();
|
||||
} else {
|
||||
let _ = lock.set(Mutex::new(HashMap::new()));
|
||||
}
|
||||
});
|
||||
@@ -203,6 +209,41 @@ pub(super) fn init_content_store(map: HashMap<String, String>) {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Regression: two sequential `ensure_content_store()` + write + read cycles
|
||||
/// in the same test body must not see each other's content. Before the fix,
|
||||
/// `ensure_content_store()` was a no-op on the second call (OnceLock gating),
|
||||
/// so the second cycle could read items written in the first cycle.
|
||||
#[test]
|
||||
fn sequential_ensure_content_store_resets_state() {
|
||||
// ── Cycle 1 ──────────────────────────────────────────────────────────
|
||||
ensure_content_store();
|
||||
write_content(ContentKey::Story("1111_cycle1"), "cycle-one body");
|
||||
assert_eq!(
|
||||
read_content(ContentKey::Story("1111_cycle1")).as_deref(),
|
||||
Some("cycle-one body"),
|
||||
"cycle 1: item must be readable after write"
|
||||
);
|
||||
|
||||
// ── Cycle 2: reset, write a different item ────────────────────────────
|
||||
ensure_content_store();
|
||||
// Cycle-1 item must no longer be visible.
|
||||
assert!(
|
||||
read_content(ContentKey::Story("1111_cycle1")).is_none(),
|
||||
"cycle 2: store must be empty; cycle-1 content must not bleed through"
|
||||
);
|
||||
write_content(ContentKey::Story("1111_cycle2"), "cycle-two body");
|
||||
assert_eq!(
|
||||
read_content(ContentKey::Story("1111_cycle2")).as_deref(),
|
||||
Some("cycle-two body"),
|
||||
"cycle 2: own item must be readable"
|
||||
);
|
||||
// And cycle-1 key must still be absent.
|
||||
assert!(
|
||||
read_content(ContentKey::Story("1111_cycle1")).is_none(),
|
||||
"cycle 2: cycle-1 content must remain absent after cycle-2 write"
|
||||
);
|
||||
}
|
||||
|
||||
/// AC 2 regression: writing under `ContentKey::Story` is not visible under
|
||||
/// `ContentKey::GateOutput` (and vice versa). The typed key namespace, not
|
||||
/// runtime substring matching, enforces the separation.
|
||||
|
||||
Reference in New Issue
Block a user