1use super::*;
2use futures::{
3 FutureExt,
4 channel::{mpsc, oneshot},
5 executor::block_on,
6 future,
7 sink::SinkExt,
8 stream::{FuturesUnordered, StreamExt},
9};
10use std::{
11 cell::RefCell,
12 collections::{BTreeSet, HashSet},
13 pin::Pin,
14 rc::Rc,
15 sync::Arc,
16 task::{Context, Poll},
17};
18
19#[test]
20fn test_foreground_executor_spawn() {
21 let result = TestScheduler::once(async |scheduler| {
22 let task = scheduler.foreground().spawn(async move { 42 });
23 task.await
24 });
25 assert_eq!(result, 42);
26}
27
28#[test]
29fn test_background_executor_spawn() {
30 TestScheduler::once(async |scheduler| {
31 let task = scheduler.background().spawn(async move { 42 });
32 let result = task.await;
33 assert_eq!(result, 42);
34 });
35}
36
37#[test]
38fn test_foreground_ordering() {
39 let mut traces = HashSet::new();
40
41 TestScheduler::many(100, async |scheduler| {
42 #[derive(Hash, PartialEq, Eq)]
43 struct TraceEntry {
44 session: usize,
45 task: usize,
46 }
47
48 let trace = Rc::new(RefCell::new(Vec::new()));
49
50 let foreground_1 = scheduler.foreground();
51 for task in 0..10 {
52 foreground_1
53 .spawn({
54 let trace = trace.clone();
55 async move {
56 trace.borrow_mut().push(TraceEntry { session: 0, task });
57 }
58 })
59 .detach();
60 }
61
62 let foreground_2 = scheduler.foreground();
63 for task in 0..10 {
64 foreground_2
65 .spawn({
66 let trace = trace.clone();
67 async move {
68 trace.borrow_mut().push(TraceEntry { session: 1, task });
69 }
70 })
71 .detach();
72 }
73
74 scheduler.run();
75
76 assert_eq!(
77 trace
78 .borrow()
79 .iter()
80 .filter(|entry| entry.session == 0)
81 .map(|entry| entry.task)
82 .collect::<Vec<_>>(),
83 (0..10).collect::<Vec<_>>()
84 );
85 assert_eq!(
86 trace
87 .borrow()
88 .iter()
89 .filter(|entry| entry.session == 1)
90 .map(|entry| entry.task)
91 .collect::<Vec<_>>(),
92 (0..10).collect::<Vec<_>>()
93 );
94
95 traces.insert(trace.take());
96 });
97
98 assert!(traces.len() > 1, "Expected at least two traces");
99}
100
101#[test]
102fn test_timer_ordering() {
103 TestScheduler::many(1, async |scheduler| {
104 let background = scheduler.background();
105 let futures = FuturesUnordered::new();
106 futures.push(
107 async {
108 background.timer(Duration::from_millis(100)).await;
109 2
110 }
111 .boxed(),
112 );
113 futures.push(
114 async {
115 background.timer(Duration::from_millis(50)).await;
116 1
117 }
118 .boxed(),
119 );
120 futures.push(
121 async {
122 background.timer(Duration::from_millis(150)).await;
123 3
124 }
125 .boxed(),
126 );
127 assert_eq!(futures.collect::<Vec<_>>().await, vec![1, 2, 3]);
128 });
129}
130
131#[test]
132fn test_send_from_bg_to_fg() {
133 TestScheduler::once(async |scheduler| {
134 let foreground = scheduler.foreground();
135 let background = scheduler.background();
136
137 let (sender, receiver) = oneshot::channel::<i32>();
138
139 background
140 .spawn(async move {
141 sender.send(42).unwrap();
142 })
143 .detach();
144
145 let task = foreground.spawn(async move { receiver.await.unwrap() });
146 let result = task.await;
147 assert_eq!(result, 42);
148 });
149}
150
151#[test]
152fn test_randomize_order() {
153 // Test deterministic mode: different seeds should produce same execution order
154 let mut deterministic_results = HashSet::new();
155 for seed in 0..10 {
156 let config = SchedulerConfig {
157 seed,
158 randomize_order: false,
159 ..Default::default()
160 };
161 let order = block_on(capture_execution_order(config));
162 assert_eq!(order.len(), 6);
163 deterministic_results.insert(order);
164 }
165
166 // All deterministic runs should produce the same result
167 assert_eq!(
168 deterministic_results.len(),
169 1,
170 "Deterministic mode should always produce same execution order"
171 );
172
173 // Test randomized mode: different seeds can produce different execution orders
174 let mut randomized_results = HashSet::new();
175 for seed in 0..20 {
176 let config = SchedulerConfig::with_seed(seed);
177 let order = block_on(capture_execution_order(config));
178 assert_eq!(order.len(), 6);
179 randomized_results.insert(order);
180 }
181
182 // Randomized mode should produce multiple different execution orders
183 assert!(
184 randomized_results.len() > 1,
185 "Randomized mode should produce multiple different orders"
186 );
187}
188
189async fn capture_execution_order(config: SchedulerConfig) -> Vec<String> {
190 let scheduler = Arc::new(TestScheduler::new(config));
191 let foreground = scheduler.foreground();
192 let background = scheduler.background();
193
194 let (sender, receiver) = mpsc::unbounded::<String>();
195
196 // Spawn foreground tasks
197 for i in 0..3 {
198 let mut sender = sender.clone();
199 foreground
200 .spawn(async move {
201 sender.send(format!("fg-{}", i)).await.ok();
202 })
203 .detach();
204 }
205
206 // Spawn background tasks
207 for i in 0..3 {
208 let mut sender = sender.clone();
209 background
210 .spawn(async move {
211 sender.send(format!("bg-{}", i)).await.ok();
212 })
213 .detach();
214 }
215
216 drop(sender); // Close sender to signal no more messages
217 scheduler.run();
218
219 receiver.collect().await
220}
221
222#[test]
223fn test_block() {
224 let scheduler = Arc::new(TestScheduler::new(SchedulerConfig::default()));
225 let executor = BackgroundExecutor::new(scheduler);
226 let (tx, rx) = oneshot::channel();
227
228 // Spawn background task to send value
229 let _ = executor
230 .spawn(async move {
231 tx.send(42).unwrap();
232 })
233 .detach();
234
235 // Block on receiving the value
236 let result = executor.block_on(async { rx.await.unwrap() });
237 assert_eq!(result, 42);
238}
239
240#[test]
241#[should_panic(expected = "Parking forbidden")]
242fn test_parking_panics() {
243 let scheduler = Arc::new(TestScheduler::new(SchedulerConfig::default()));
244 let executor = BackgroundExecutor::new(scheduler);
245 executor.block_on(future::pending::<()>());
246}
247
248#[test]
249fn test_block_with_parking() {
250 let config = SchedulerConfig {
251 allow_parking: true,
252 ..Default::default()
253 };
254 let scheduler = Arc::new(TestScheduler::new(config));
255 let executor = BackgroundExecutor::new(scheduler);
256 let (tx, rx) = oneshot::channel();
257
258 // Spawn background task to send value
259 let _ = executor
260 .spawn(async move {
261 tx.send(42).unwrap();
262 })
263 .detach();
264
265 // Block on receiving the value (will park if needed)
266 let result = executor.block_on(async { rx.await.unwrap() });
267 assert_eq!(result, 42);
268}
269
270#[test]
271fn test_helper_methods() {
272 // Test the once method
273 let result = TestScheduler::once(async |scheduler: Arc<TestScheduler>| {
274 let background = scheduler.background();
275 background.spawn(async { 42 }).await
276 });
277 assert_eq!(result, 42);
278
279 // Test the many method
280 let results = TestScheduler::many(3, async |scheduler: Arc<TestScheduler>| {
281 let background = scheduler.background();
282 background.spawn(async { 10 }).await
283 });
284 assert_eq!(results, vec![10, 10, 10]);
285
286 // Test the with_seed method
287 let result = TestScheduler::with_seed(123, async |scheduler: Arc<TestScheduler>| {
288 let background = scheduler.background();
289
290 // Spawn a background task and wait for its result
291 let task = background.spawn(async { 99 });
292 task.await
293 });
294 assert_eq!(result, 99);
295}
296
297#[test]
298fn test_block_with_timeout() {
299 // Test case: future completes within timeout
300 TestScheduler::once(async |scheduler| {
301 let background = scheduler.background();
302 let mut future = future::ready(42);
303 let output = background.block_with_timeout(&mut future, Duration::from_millis(100));
304 assert_eq!(output, Some(42));
305 });
306
307 // Test case: future times out
308 TestScheduler::once(async |scheduler| {
309 let background = scheduler.background();
310 let mut future = future::pending::<()>();
311 let output = background.block_with_timeout(&mut future, Duration::from_millis(50));
312 assert_eq!(output, None);
313 });
314
315 // Test case: future makes progress via timer but still times out
316 let mut results = BTreeSet::new();
317 TestScheduler::many(100, async |scheduler| {
318 let background = scheduler.background();
319 let mut task = background.spawn(async move {
320 Yield { polls: 10 }.await;
321 42
322 });
323 let output = background.block_with_timeout(&mut task, Duration::from_millis(50));
324 results.insert(output);
325 });
326 assert_eq!(
327 results.into_iter().collect::<Vec<_>>(),
328 vec![None, Some(42)]
329 );
330}
331
332struct Yield {
333 polls: usize,
334}
335
336impl Future for Yield {
337 type Output = ();
338
339 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
340 self.polls -= 1;
341 if self.polls == 0 {
342 Poll::Ready(())
343 } else {
344 cx.waker().wake_by_ref();
345 Poll::Pending
346 }
347 }
348}