harn_test_runner/
session.rs1use std::collections::BTreeSet;
2use std::path::PathBuf;
3use std::sync::Mutex;
4
5use serde::Serialize;
6
7use crate::reporting::SuiteModulePreparation;
8
9pub struct TestRunSession {
16 prepared_module_cache: harn_vm::PreparedModuleCache,
17 workers: Mutex<usize>,
18 clock: std::sync::Arc<dyn harn_vm::clock::Clock>,
19 stdio_available: bool,
20 callable_preparations: Mutex<(usize, usize)>,
21}
22
23impl Default for TestRunSession {
24 fn default() -> Self {
25 Self {
26 prepared_module_cache: harn_vm::PreparedModuleCache::default(),
27 workers: Mutex::new(0),
28 clock: harn_vm::clock::RealClock::arc(),
29 stdio_available: true,
30 callable_preparations: Mutex::new((0, 0)),
31 }
32 }
33}
34
35#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize)]
41pub struct TestRunSessionStats {
42 pub workers: usize,
43 pub hits: u64,
44 pub misses: u64,
45 pub insertions: u64,
46 pub evictions: u64,
47 pub entries: usize,
48 pub test_files_compiled: usize,
49 pub test_entries_compiled: usize,
50}
51
52impl TestRunSession {
53 pub fn without_stdio() -> Self {
55 Self {
56 stdio_available: false,
57 ..Self::default()
58 }
59 }
60
61 pub fn stats(&self) -> TestRunSessionStats {
62 let stats = self.prepared_module_cache.stats();
63 let callable = *self.callable_preparations.lock().unwrap();
64 TestRunSessionStats {
65 workers: *self.workers.lock().unwrap(),
66 hits: stats.hits,
67 misses: stats.misses,
68 insertions: stats.insertions,
69 evictions: stats.evictions,
70 entries: stats.entries,
71 test_files_compiled: callable.0,
72 test_entries_compiled: callable.1,
73 }
74 }
75
76 #[doc(hidden)]
77 pub fn prepared_module_cache(&self, worker_index: usize) -> harn_vm::PreparedModuleCache {
78 let mut workers = self.workers.lock().unwrap();
79 *workers = (*workers).max(worker_index.saturating_add(1));
80 self.prepared_module_cache.clone()
81 }
82
83 #[doc(hidden)]
84 pub fn prepare_import_graphs(
85 &self,
86 roots: impl IntoIterator<Item = (PathBuf, bool)>,
87 ) -> SuiteModulePreparation {
88 let mut user_files = BTreeSet::new();
89 let mut trusted_files = BTreeSet::new();
90 for (path, trusted_host_dispatch) in roots {
91 if trusted_host_dispatch {
92 trusted_files.insert(path);
93 } else {
94 user_files.insert(path);
95 }
96 }
97 let user = self.prepare_import_graph(&user_files.into_iter().collect::<Vec<_>>(), false);
98 let trusted =
99 self.prepare_import_graph(&trusted_files.into_iter().collect::<Vec<_>>(), true);
100 SuiteModulePreparation {
101 duration_ms: user.duration_ms.saturating_add(trusted.duration_ms),
102 modules: user.modules.saturating_add(trusted.modules),
103 }
104 }
105
106 fn prepare_import_graph(
107 &self,
108 roots: &[std::path::PathBuf],
109 trusted_host_dispatch: bool,
110 ) -> SuiteModulePreparation {
111 let started_ms = self.clock.monotonic_ms();
112 let modules = if trusted_host_dispatch {
113 self.prepared_module_cache
114 .prepare_trusted_host_dispatch_import_graph(roots)
115 } else {
116 self.prepared_module_cache.prepare_import_graph(roots)
117 };
118 let duration_ms = self.clock.monotonic_ms().saturating_sub(started_ms).max(0) as u64;
119 SuiteModulePreparation {
120 duration_ms,
121 modules,
122 }
123 }
124
125 #[doc(hidden)]
126 pub fn record_callable_preparation(&self, files: usize, entries: usize) {
127 let mut totals = self.callable_preparations.lock().unwrap();
128 totals.0 = totals.0.saturating_add(files);
129 totals.1 = totals.1.saturating_add(entries);
130 }
131
132 #[doc(hidden)]
133 pub fn stdio_available(&self) -> bool {
134 self.stdio_available
135 }
136}