turbo_tasks_testing/
run.rs

1use 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}