aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-15 12:01:27 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-15 12:01:27 +0000
commitda04eb3770eb14dadb6a2904269fe1ea0aef987f (patch)
tree18bc8021e9bed334a92503c1a51ce4ce15fe5f32
parent17370463e2bc23f7a654f95f589cf6de767f9fb8 (diff)
parentf7e711b77fc4d7163c736d102783d1b407d9f705 (diff)
Merge #837
837: Generalize vfs.rs test to address fsevents timing-dependent behavior. r=matklad a=pnkfelix Generalize `tests/vfs.rs` processing to address wildly-varying timing-dependent behavior from fsevents (i.e. on Mac OS X). Fix #734 Co-authored-by: Felix S. Klock II <[email protected]>
-rw-r--r--crates/ra_vfs/tests/vfs.rs76
1 files changed, 67 insertions, 9 deletions
diff --git a/crates/ra_vfs/tests/vfs.rs b/crates/ra_vfs/tests/vfs.rs
index b31e0f288..2ae7bb40b 100644
--- a/crates/ra_vfs/tests/vfs.rs
+++ b/crates/ra_vfs/tests/vfs.rs
@@ -5,12 +5,27 @@ use crossbeam_channel::RecvTimeoutError;
5use ra_vfs::{Vfs, VfsChange}; 5use ra_vfs::{Vfs, VfsChange};
6use tempfile::tempdir; 6use tempfile::tempdir;
7 7
8/// Processes exactly `num_tasks` events waiting in the `vfs` message queue.
9///
10/// Panics if there are not exactly that many tasks enqueued for processing.
8fn process_tasks(vfs: &mut Vfs, num_tasks: u32) { 11fn process_tasks(vfs: &mut Vfs, num_tasks: u32) {
9 for _ in 0..num_tasks { 12 process_tasks_in_range(vfs, num_tasks, num_tasks);
10 let task = vfs.task_receiver().recv_timeout(Duration::from_secs(3)).unwrap(); 13}
14
15/// Processes up to `max_count` events waiting in the `vfs` message queue.
16///
17/// Panics if it cannot process at least `min_count` events.
18/// Panics if more than `max_count` events are enqueued for processing.
19fn process_tasks_in_range(vfs: &mut Vfs, min_count: u32, max_count: u32) {
20 for i in 0..max_count {
21 let task = match vfs.task_receiver().recv_timeout(Duration::from_secs(3)) {
22 Err(RecvTimeoutError::Timeout) if i >= min_count => return,
23 otherwise => otherwise.unwrap(),
24 };
11 log::debug!("{:?}", task); 25 log::debug!("{:?}", task);
12 vfs.handle_task(task); 26 vfs.handle_task(task);
13 } 27 }
28 assert!(vfs.task_receiver().is_empty());
14} 29}
15 30
16macro_rules! assert_match { 31macro_rules! assert_match {
@@ -67,6 +82,28 @@ fn test_vfs_works() -> std::io::Result<()> {
67 assert_eq!(files, expected_files); 82 assert_eq!(files, expected_files);
68 } 83 }
69 84
85 // rust-analyzer#734: fsevents has a bunch of events still sitting around.
86 process_tasks_in_range(&mut vfs, 0, 7);
87 match vfs.commit_changes().as_slice() {
88 [] => {}
89
90 // This arises on fsevents (unless we wait 30 seconds before
91 // calling `Vfs::new` above). We need to churn through these
92 // events so that we can focus on the event that arises from
93 // the `fs::write` below.
94 [VfsChange::ChangeFile { .. }, // hello
95 VfsChange::ChangeFile { .. }, // world
96 VfsChange::AddFile { .. }, // b/baz.rs, nested hello
97 VfsChange::ChangeFile { .. }, // hello
98 VfsChange::ChangeFile { .. }, // world
99 VfsChange::ChangeFile { .. }, // nested hello
100 VfsChange::ChangeFile { .. }, // nested hello
101 ] => {}
102
103 changes => panic!("Expected events for setting up initial files, got: {GOT:?}",
104 GOT=changes),
105 }
106
70 fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap(); 107 fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap();
71 process_tasks(&mut vfs, 1); 108 process_tasks(&mut vfs, 1);
72 assert_match!( 109 assert_match!(
@@ -118,18 +155,39 @@ fn test_vfs_works() -> std::io::Result<()> {
118 155
119 fs::rename(&dir.path().join("a/sub1/sub2/new.rs"), &dir.path().join("a/sub1/sub2/new1.rs")) 156 fs::rename(&dir.path().join("a/sub1/sub2/new.rs"), &dir.path().join("a/sub1/sub2/new1.rs"))
120 .unwrap(); 157 .unwrap();
121 // NOTE: Windows generates extra `Write` events when renaming? 158
122 // meaning we have extra tasks to process 159 // rust-analyzer#734: For testing purposes, work-around
123 process_tasks(&mut vfs, if cfg!(windows) { 4 } else { 2 }); 160 // passcod/notify#181 by processing either 1 or 2 events. (In
124 assert_match!( 161 // particular, Mac can hand back either 1 or 2 events in a
125 vfs.commit_changes().as_slice(), 162 // timing-dependent fashion.)
126 [VfsChange::RemoveFile { path: removed_path, .. }, VfsChange::AddFile { text, path: added_path, .. }], 163 //
164 // rust-analyzer#827: Windows generates extra `Write` events when
165 // renaming? meaning we have extra tasks to process.
166 process_tasks_in_range(&mut vfs, 1, if cfg!(windows) { 4 } else { 2 });
167 match vfs.commit_changes().as_slice() {
168 [VfsChange::RemoveFile { path: removed_path, .. }, VfsChange::AddFile { text, path: added_path, .. }] =>
127 { 169 {
128 assert_eq!(removed_path, "sub1/sub2/new.rs"); 170 assert_eq!(removed_path, "sub1/sub2/new.rs");
129 assert_eq!(added_path, "sub1/sub2/new1.rs"); 171 assert_eq!(added_path, "sub1/sub2/new1.rs");
130 assert_eq!(text.as_str(), "new hello"); 172 assert_eq!(text.as_str(), "new hello");
131 } 173 }
132 ); 174
175 // Hopefully passcod/notify#181 will be addressed in some
176 // manner that will reliably emit an event mentioning
177 // `sub1/sub2/new.rs`. But until then, must accept that
178 // debouncing loses information unrecoverably.
179 [VfsChange::AddFile { text, path: added_path, .. }] => {
180 assert_eq!(added_path, "sub1/sub2/new1.rs");
181 assert_eq!(text.as_str(), "new hello");
182 }
183
184 changes => panic!(
185 "Expected events for rename of {OLD} to {NEW}, got: {GOT:?}",
186 OLD = "sub1/sub2/new.rs",
187 NEW = "sub1/sub2/new1.rs",
188 GOT = changes
189 ),
190 }
133 191
134 fs::remove_file(&dir.path().join("a/sub1/sub2/new1.rs")).unwrap(); 192 fs::remove_file(&dir.path().join("a/sub1/sub2/new1.rs")).unwrap();
135 process_tasks(&mut vfs, 1); 193 process_tasks(&mut vfs, 1);