diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-15 12:01:27 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-15 12:01:27 +0000 |
commit | da04eb3770eb14dadb6a2904269fe1ea0aef987f (patch) | |
tree | 18bc8021e9bed334a92503c1a51ce4ce15fe5f32 /crates | |
parent | 17370463e2bc23f7a654f95f589cf6de767f9fb8 (diff) | |
parent | f7e711b77fc4d7163c736d102783d1b407d9f705 (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]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_vfs/tests/vfs.rs | 76 |
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; | |||
5 | use ra_vfs::{Vfs, VfsChange}; | 5 | use ra_vfs::{Vfs, VfsChange}; |
6 | use tempfile::tempdir; | 6 | use 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. | ||
8 | fn process_tasks(vfs: &mut Vfs, num_tasks: u32) { | 11 | fn 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. | ||
19 | fn 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 | ||
16 | macro_rules! assert_match { | 31 | macro_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); |