turbo_tasks_testing/
run.rs1use std::{env, fmt::Debug, future::Future, sync::Arc};
2
3use anyhow::Result;
4use turbo_tasks::{TurboTasksApi, trace::TraceRawVcs};
5
6pub struct Registration {
7 create_turbo_tasks: fn(&str, bool) -> Arc<dyn TurboTasksApi>,
8}
9
10impl Registration {
11 #[doc(hidden)]
12 pub const fn new(create_turbo_tasks: fn(&str, bool) -> Arc<dyn TurboTasksApi>) -> Self {
13 Registration { create_turbo_tasks }
14 }
15
16 pub fn create_turbo_tasks(&self, name: &str, initial: bool) -> Arc<dyn TurboTasksApi> {
17 (self.create_turbo_tasks)(name, initial)
18 }
19}
20
21#[macro_export]
22macro_rules! register {
23 ($($other_register_fns:expr),* $(,)?) => {{
24 use std::sync::Arc;
25
26 use turbo_tasks::TurboTasksApi;
27 fn create_turbo_tasks(name: &str, initial: bool) -> Arc<dyn TurboTasksApi> {
28 let inner = include!(concat!(
29 env!("CARGO_MANIFEST_DIR"),
30 "/tests/test_config.trs"
31 ));
32 (inner)(name, initial)
33 }
34 turbo_tasks_testing::Registration::new(create_turbo_tasks)
35 }};
36}
37
38pub async fn run_once_without_cache_check<T>(
39 registration: &Registration,
40 fut: impl Future<Output = T> + Send + 'static,
41) -> T
42where
43 T: TraceRawVcs + Send + 'static,
44{
45 let name = closure_to_name(&fut);
46 let tt = registration.create_turbo_tasks(&name, true);
47 turbo_tasks::run_once(tt, async move { Ok(fut.await) })
48 .await
49 .unwrap()
50}
51
52pub async fn run_without_cache_check<T>(
53 registration: &Registration,
54 fut: impl Future<Output = T> + Send + 'static,
55) -> T
56where
57 T: TraceRawVcs + Send + 'static,
58{
59 let name = closure_to_name(&fut);
60 let tt = registration.create_turbo_tasks(&name, true);
61 turbo_tasks::run(tt, async move { Ok(fut.await) })
62 .await
63 .unwrap()
64}
65
66fn closure_to_name<T>(value: &T) -> String {
67 let name = std::any::type_name_of_val(value);
68 name.replace("::{{closure}}", "").replace("::", "_")
69}
70
71pub async fn run_once<T, F>(
72 registration: &Registration,
73 fut: impl Fn() -> F + Send + 'static,
74) -> Result<()>
75where
76 F: Future<Output = Result<T>> + Send + 'static,
77 T: Debug + PartialEq + Eq + TraceRawVcs + Send + 'static,
78{
79 run_with_tt(registration, move |tt| turbo_tasks::run_once(tt, fut())).await
80}
81
82pub async fn run<T, F>(
83 registration: &Registration,
84 fut: impl Fn() -> F + Send + 'static,
85) -> Result<()>
86where
87 F: Future<Output = Result<T>> + Send + 'static,
88 T: Debug + PartialEq + Eq + TraceRawVcs + Send + 'static,
89{
90 run_with_tt(registration, move |tt| turbo_tasks::run(tt, fut())).await
91}
92
93pub async fn run_with_tt<T, F>(
94 registration: &Registration,
95 fut: impl Fn(Arc<dyn TurboTasksApi>) -> F + Send + 'static,
96) -> Result<()>
97where
98 F: Future<Output = Result<T>> + Send + 'static,
99 T: Debug + PartialEq + Eq + TraceRawVcs + Send + 'static,
100{
101 let infinite_initial_runs = env::var("INFINITE_INITIAL_RUNS").is_ok();
102 let infinite_memory_runs = !infinite_initial_runs && env::var("INFINITE_MEMORY_RUNS").is_ok();
103 let single_run = infinite_initial_runs || env::var("SINGLE_RUN").is_ok();
104 let name = closure_to_name(&fut);
105 let mut i = 1;
106 loop {
107 let tt = registration.create_turbo_tasks(&name, true);
108 println!("Run #{i} (without cache)");
109 let start = std::time::Instant::now();
110 let first = fut(tt.clone()).await?;
111 println!("Run #{i} took {:?}", start.elapsed());
112 i += 1;
113 if !single_run {
114 let max_run = if infinite_memory_runs { usize::MAX } else { 10 };
115 for _ in 0..max_run {
116 println!("Run #{i} (with memory cache, same TurboTasks instance)");
117 let start = std::time::Instant::now();
118 let second = fut(tt.clone()).await?;
119 println!("Run #{i} took {:?}", start.elapsed());
120 i += 1;
121 assert_eq!(first, second);
122 }
123 }
124 let start = std::time::Instant::now();
125 tt.stop_and_wait().await;
126 println!("Stopping TurboTasks took {:?}", start.elapsed());
127 if !single_run {
128 for _ in 10..20 {
129 let tt = registration.create_turbo_tasks(&name, false);
130 println!("Run #{i} (with filesystem cache if available, new TurboTasks instance)");
131 let start = std::time::Instant::now();
132 let third = fut(tt.clone()).await?;
133 println!("Run #{i} took {:?}", start.elapsed());
134 i += 1;
135 let start = std::time::Instant::now();
136 tt.stop_and_wait().await;
137 println!("Stopping TurboTasks took {:?}", start.elapsed());
138 assert_eq!(first, third);
139 }
140 }
141 if !infinite_initial_runs {
142 break;
143 }
144 }
145 Ok(())
146}