|
1 | 1 | #![allow(clippy::disallowed_macros)] |
2 | 2 |
|
3 | 3 | use spacetimedb_data_structures::map::{HashMap, HashSet}; |
4 | | -use std::{ |
5 | | - sync::{Arc, Condvar, Mutex}, |
6 | | - time::Duration, |
7 | | -}; |
| 4 | +use std::sync::{Arc, Condvar, Mutex}; |
| 5 | +#[cfg(not(target_arch = "wasm32"))] |
| 6 | +use std::time::Duration; |
8 | 7 |
|
9 | 8 | const TEST_TIMEOUT_SECS: u64 = 5 * 60; |
10 | 9 |
|
@@ -55,7 +54,31 @@ impl TestCounter { |
55 | 54 | }) |
56 | 55 | } |
57 | 56 |
|
| 57 | + // Keep this legacy sync API for existing native-first callers. |
| 58 | + // wasm callers should prefer `wait_for_all_async` so we do not |
| 59 | + // block the JS event loop while waiting for callbacks. |
58 | 60 | pub fn wait_for_all(&self) { |
| 61 | + #[cfg(target_arch = "wasm32")] |
| 62 | + futures::executor::block_on(self.wait_for_all_wasm_async()); |
| 63 | + |
| 64 | + #[cfg(not(target_arch = "wasm32"))] |
| 65 | + self.wait_for_all_native(); |
| 66 | + } |
| 67 | + |
| 68 | + pub async fn wait_for_all_async(&self) { |
| 69 | + #[cfg(target_arch = "wasm32")] |
| 70 | + { |
| 71 | + // wasm/web test clients run callbacks on a single-threaded event loop, |
| 72 | + // so waiting must be async to allow callback tasks to make progress. |
| 73 | + self.wait_for_all_wasm_async().await; |
| 74 | + } |
| 75 | + |
| 76 | + #[cfg(not(target_arch = "wasm32"))] |
| 77 | + self.wait_for_all_native(); |
| 78 | + } |
| 79 | + |
| 80 | + #[cfg(not(target_arch = "wasm32"))] |
| 81 | + fn wait_for_all_native(&self) { |
59 | 82 | let lock = self.inner.lock().expect("TestCounterInner Mutex is poisoned"); |
60 | 83 | let (lock, timeout_result) = self |
61 | 84 | .wait_until_done |
@@ -100,4 +123,65 @@ impl TestCounter { |
100 | 123 | } |
101 | 124 | } |
102 | 125 | } |
| 126 | + |
| 127 | + #[cfg(target_arch = "wasm32")] |
| 128 | + async fn wait_for_all_wasm_async(&self) { |
| 129 | + use gloo_timers::future::TimeoutFuture; |
| 130 | + |
| 131 | + const WAIT_INTERVAL_MS: u32 = 10; |
| 132 | + const MAX_WAIT_ITERATIONS: u32 = (TEST_TIMEOUT_SECS as u32 * 1000) / WAIT_INTERVAL_MS; |
| 133 | + |
| 134 | + // On wasm/web the SDK message loop runs on the same single-threaded event loop |
| 135 | + // as test code. Blocking on a Condvar here can deadlock callbacks forever. |
| 136 | + // We poll with timer yields so websocket/callback tasks can continue to run. |
| 137 | + let all_tests_finished = || { |
| 138 | + let inner = self.inner.lock().expect("TestCounterInner Mutex is poisoned"); |
| 139 | + inner.outcomes.len() == inner.registered.len() |
| 140 | + }; |
| 141 | + |
| 142 | + for _ in 0..MAX_WAIT_ITERATIONS { |
| 143 | + if all_tests_finished() { |
| 144 | + return; |
| 145 | + } |
| 146 | + TimeoutFuture::new(WAIT_INTERVAL_MS).await; |
| 147 | + } |
| 148 | + |
| 149 | + let lock = self.inner.lock().expect("TestCounterInner Mutex is poisoned"); |
| 150 | + if lock.outcomes.len() != lock.registered.len() { |
| 151 | + let mut timeout_count = 0; |
| 152 | + let mut failed_count = 0; |
| 153 | + for test in lock.registered.iter() { |
| 154 | + match lock.outcomes.get(test) { |
| 155 | + None => { |
| 156 | + timeout_count += 1; |
| 157 | + println!("TIMEOUT: {test}"); |
| 158 | + } |
| 159 | + Some(Err(e)) => { |
| 160 | + failed_count += 1; |
| 161 | + println!("FAILED: {test}:\n\t{e:?}\n"); |
| 162 | + } |
| 163 | + Some(Ok(())) => { |
| 164 | + println!("PASSED: {test}"); |
| 165 | + } |
| 166 | + } |
| 167 | + } |
| 168 | + panic!("{timeout_count} tests timed out and {failed_count} tests failed"); |
| 169 | + } else { |
| 170 | + let mut failed_count = 0; |
| 171 | + for (test, outcome) in lock.outcomes.iter() { |
| 172 | + match outcome { |
| 173 | + Ok(()) => println!("PASSED: {test}"), |
| 174 | + Err(e) => { |
| 175 | + failed_count += 1; |
| 176 | + println!("FAILED: {test}:\n\t{e:?}\n"); |
| 177 | + } |
| 178 | + } |
| 179 | + } |
| 180 | + if failed_count != 0 { |
| 181 | + panic!("{failed_count} tests failed"); |
| 182 | + } else { |
| 183 | + println!("All tests passed"); |
| 184 | + } |
| 185 | + } |
| 186 | + } |
103 | 187 | } |
0 commit comments