From 08dbdad9e4fb203c874a7035cc77f5e4db5bc7b8 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Thu, 15 Oct 2026 09:37:12 -0700 Subject: [PATCH] test(mobile): count each page arrangement as one durable queued edit pages_drag_indent_and_undo_as_one_edit_each read the replica queue straight after an arrange. Since edits are written by the section thread, the page list can answer from memory before the burst that holds the edit is written, so under load the queue still read empty; a sync step publishing the edit could drain it as well. The test now works offline from the start and waits for written() before counting, and counts every arrangement and the no-op rather than only the first. notebook_open takes the offline flag so the section never opens online, which also closes the same window in unpublished_edit, which went offline only after its session had started a sync step. Under load the old test failed 7 times in 1200 runs; the new one passed 2400 of 2400. Assisted-by: claude-opus-5.5 --- crates/mobile/src/tests.rs | 55 +++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/crates/mobile/src/tests.rs b/crates/mobile/src/tests.rs index 8f72cb28cc207356a327e0c8f97dff199de5adf2..282826da36a458ece5149638ab7ae7060b9f1378 100644 --- a/crates/mobile/src/tests.rs +++ b/crates/mobile/src/tests.rs @@ -1173,10 +1173,14 @@ fn a_share_notebook_names_its_files_from_the_share_s_top() { ); } -/// A notebook copy with its library, and a section of it open for editing. -fn notebook_open(path: &str) -> (tempfile::TempDir, PathBuf, Arc, Section) { +/// A notebook copy with its library, and a section of it open for editing. Working +/// `offline` from the start, no sync step can publish the section's edits. +fn notebook_open(path: &str, offline: bool) -> (tempfile::TempDir, PathBuf, Arc, Section) { let (directory, root) = copy("m6/native-features-01/notebook"); let library = Arc::new(Library::open(&root, &directory.path().join("cache"), true).unwrap()); + if offline { + sb_library_set_offline(&library, true); + } let section = open(&library, path); (directory, root, library, section) } @@ -1195,7 +1199,7 @@ fn eventually(mut ready: impl FnMut() -> bool) -> bool { #[test] fn sync_status_lists_every_section_and_work_offline_holds_edits_until_sync_now() { - let (_directory, root, library, section) = notebook_open("Features.one"); + let (_directory, root, library, section) = notebook_open("Features.one", false); // Every readable section, the open one's from its session. assert!(eventually(|| { let status = library.sync_status(); @@ -1499,8 +1503,7 @@ fn the_accent_pen_and_shapes_draw_as_the_desktop_and_a_cancelled_sweep_stores_no /// Queues an offline edit to Features.one and closes its session, leaving the edit to the /// background; the replicas in the cache, and the text edited in. fn unpublished_edit() -> (tempfile::TempDir, PathBuf, Arc, ExGuid) { - let (directory, root, library, section) = notebook_open("Features.one"); - sb_library_set_offline(&library, true); + let (directory, root, library, section) = notebook_open("Features.one", true); let mut canvas = canvas(§ion, "Paragraph controls"); focus(&mut canvas, "Collapsed parent"); canvas.insert("Unpublished ".into()).unwrap(); @@ -1699,34 +1702,38 @@ fn levels(section: &Section) -> Vec<(ExGuid, u32)> { #[test] fn pages_drag_indent_and_undo_as_one_edit_each() { - let (_directory, _root, _library, section) = notebook_open("Features.one"); + let (_directory, _root, _library, section) = notebook_open("Features.one", true); + let queued = || { + section.shared.section.written().unwrap(); + section.shared.section.pending().unwrap().len() + }; let before = levels(§ion); assert!(before.len() > 2); let last = before.last().unwrap().0; let mut dragged = before.clone(); let moved = dragged.pop().unwrap(); dragged.insert(0, moved); - let revisions = section.shared.section.pending().unwrap().len(); - assert!(section.arrange(&dragged, &[last]).unwrap()); - assert_eq!(levels(§ion), dragged); - assert_eq!( - section.shared.section.pending().unwrap().len(), - revisions + 1 - ); + let mut edits = queued(); + let mut arrange = |order: &[(ExGuid, u32)], moved: ExGuid| { + assert!(section.arrange(order, &[moved]).unwrap()); + assert_eq!(levels(§ion), order); + edits += 1; + assert_eq!(queued(), edits); + }; + arrange(&dragged, last); let second = dragged[1].0; let mut indented = dragged.clone(); indented[1].1 = 2; - assert!(section.arrange(&indented, &[second]).unwrap()); - assert_eq!(levels(§ion), indented); - assert!(section.arrange(&dragged, &[second]).unwrap()); - assert!(section.arrange(&before, &[last]).unwrap()); - assert_eq!(levels(§ion), before); + arrange(&indented, second); + arrange(&dragged, second); + arrange(&before, last); assert!(!section.arrange(&before, &[ExGuid::default()]).unwrap()); + assert_eq!(queued(), edits); } #[test] fn a_page_moves_to_another_section_and_back_where_it_was() { - let (_directory, root, library, features) = notebook_open("Features.one"); + let (_directory, root, library, features) = notebook_open("Features.one", false); let before = levels(&features); let (space, level) = before[1]; let title = features.shared.section.page(space).unwrap().title; @@ -1785,7 +1792,7 @@ fn a_page_moves_to_another_section_and_back_where_it_was() { fn a_page_edited_while_it_moves_stays_with_its_edit() { library::sb_set_coordinator(coordinator); for edited in [true, false] { - let (_directory, root, library, features) = notebook_open("Features.one"); + let (_directory, root, library, features) = notebook_open("Features.one", false); assert!(eventually(|| { let status = library.sync_status(); !status.is_empty() @@ -1861,7 +1868,7 @@ fn a_page_its_section_cannot_retire_stays_beside_its_copy() { let _exclusive = vfs::EXCLUSIVE .lock() .unwrap_or_else(std::sync::PoisonError::into_inner); - let (directory, root, library, empty) = notebook_open("Empty.one"); + let (directory, root, library, empty) = notebook_open("Empty.one", false); let features = open(&library, "Features.one"); let space = space(&features, "Task controls"); drop(features); @@ -1908,7 +1915,7 @@ fn a_page_its_section_cannot_retire_stays_beside_its_copy() { /// A page the section it moves to refuses stays where it was, and the move fails. #[test] fn a_page_the_other_section_refuses_stays() { - let (_directory, _root, library, features) = notebook_open("Features.one"); + let (_directory, _root, library, features) = notebook_open("Features.one", false); let before = levels(&features); let (space, _) = before[1]; let page = features.shared.section.page(space).unwrap(); @@ -1938,7 +1945,7 @@ fn a_page_the_other_section_refuses_stays() { #[test] fn a_sections_last_page_moving_leaves_a_page_that_undo_takes_out() { - let (_directory, _root, library, features) = notebook_open("Features.one"); + let (_directory, _root, library, features) = notebook_open("Features.one", false); let date = ["Thursday, October 1, 2026", "9:02 AM"]; let page = features.new_page(None, date[0], date[1]).unwrap(); let arrived: ExGuid = library @@ -1989,7 +1996,7 @@ fn a_sections_last_page_moving_leaves_a_page_that_undo_takes_out() { #[test] fn sections_reorder_and_move_between_groups_and_back() { - let (_directory, root, library, features) = notebook_open("Features.one"); + let (_directory, root, library, features) = notebook_open("Features.one", false); drop(features); let top = |library: &Library| -> Vec { let tabs = library.tabs().unwrap(); -- 2.54.0