huskies: merge 1007
This commit is contained in:
@@ -507,3 +507,76 @@ fn list_refactor_files_returns_ok() {
|
||||
let result = list_refactor_files(tmp.path());
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
/// Regression for bug 1001: 8 rapid sequential `create_refactor` calls with
|
||||
/// `depends_on` chains must all land cleanly in BOTH the content store AND
|
||||
/// the CRDT. Before the fix, the allocator could return a tombstoned ID on
|
||||
/// a tight loop, producing a half-written item invisible to `list_refactors`
|
||||
/// and `update_story`.
|
||||
#[test]
|
||||
fn rapid_sequential_creates_all_land_in_crdt() {
|
||||
crate::crdt_state::init_for_test();
|
||||
crate::db::ensure_content_store();
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
let mut ids: Vec<String> = Vec::new();
|
||||
|
||||
for i in 0..8u32 {
|
||||
// Build a depends_on chain: item i depends on item i-1.
|
||||
let depends_on: Option<Vec<u32>> = if ids.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let last_num: u32 = ids.last().unwrap().parse().unwrap_or(0);
|
||||
Some(vec![last_num])
|
||||
};
|
||||
|
||||
let id = create_refactor_file(
|
||||
tmp.path(),
|
||||
&format!("Rapid Refactor {i}"),
|
||||
None,
|
||||
&[format!("AC for rapid refactor {i}")],
|
||||
depends_on.as_deref(),
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("create_refactor_file {i} failed: {e}"));
|
||||
|
||||
// Immediately verify it landed in CRDT (the core transactional guarantee).
|
||||
assert!(
|
||||
crate::crdt_state::read_item(&id).is_some(),
|
||||
"refactor {i} (id={id}) must be in CRDT immediately after create"
|
||||
);
|
||||
|
||||
ids.push(id);
|
||||
}
|
||||
|
||||
assert_eq!(ids.len(), 8, "all 8 creates must succeed");
|
||||
assert_eq!(
|
||||
ids.iter().collect::<std::collections::HashSet<_>>().len(),
|
||||
8,
|
||||
"all 8 IDs must be distinct"
|
||||
);
|
||||
|
||||
// list_refactor_files must return all 8 (reads from CRDT).
|
||||
let listed = list_refactor_files(tmp.path()).expect("list_refactor_files must succeed");
|
||||
let listed_ids: std::collections::HashSet<&str> =
|
||||
listed.iter().map(|(id, _)| id.as_str()).collect();
|
||||
for id in &ids {
|
||||
assert!(
|
||||
listed_ids.contains(id.as_str()),
|
||||
"refactor '{id}' must appear in list_refactor_files: {listed_ids:?}"
|
||||
);
|
||||
}
|
||||
|
||||
// set_name (the update_story --name path) must succeed for all 8.
|
||||
for (i, id) in ids.iter().enumerate() {
|
||||
let new_name = format!("Renamed Rapid Refactor {i}");
|
||||
let success = crate::crdt_state::set_name(id, Some(&new_name));
|
||||
assert!(success, "set_name for refactor {i} (id={id}) must succeed");
|
||||
let view = crate::crdt_state::read_item(id)
|
||||
.unwrap_or_else(|| panic!("item {i} (id={id}) must still be in CRDT after rename"));
|
||||
assert_eq!(
|
||||
view.name(),
|
||||
new_name,
|
||||
"CRDT must reflect the new name for refactor {i}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user