Skip to main content

harn_cli/test_runner/
session.rs

1use std::sync::Mutex;
2
3use serde::Serialize;
4
5/// Reusable runtime state for repeated user-test runs.
6///
7/// Each logical worker retains its own bounded prepared-module cache while
8/// every test case still receives a fresh VM and fresh runtime state. Keeping
9/// the cache per worker avoids introducing cross-worker contention while
10/// allowing watch mode and long-lived embedders to amortize module hydration.
11pub struct TestRunSession {
12    prepared_module_caches: Mutex<Vec<harn_vm::PreparedModuleCache>>,
13    stdio_available: bool,
14}
15
16impl Default for TestRunSession {
17    fn default() -> Self {
18        Self {
19            prepared_module_caches: Mutex::new(Vec::new()),
20            stdio_available: true,
21        }
22    }
23}
24
25/// Aggregate prepared-module cache counters for a [`TestRunSession`].
26#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize)]
27#[non_exhaustive]
28pub struct TestRunSessionStats {
29    pub workers: usize,
30    pub hits: u64,
31    pub misses: u64,
32    pub insertions: u64,
33    pub evictions: u64,
34    pub entries: usize,
35}
36
37impl TestRunSession {
38    /// Build a session for an embedder whose control protocol owns stdio.
39    pub fn without_stdio() -> Self {
40        Self {
41            stdio_available: false,
42            ..Self::default()
43        }
44    }
45
46    pub fn stats(&self) -> TestRunSessionStats {
47        self.prepared_module_caches
48            .lock()
49            .unwrap()
50            .iter()
51            .map(harn_vm::PreparedModuleCache::stats)
52            .fold(TestRunSessionStats::default(), |mut total, stats| {
53                total.workers += 1;
54                total.hits = total.hits.saturating_add(stats.hits);
55                total.misses = total.misses.saturating_add(stats.misses);
56                total.insertions = total.insertions.saturating_add(stats.insertions);
57                total.evictions = total.evictions.saturating_add(stats.evictions);
58                total.entries = total.entries.saturating_add(stats.entries);
59                total
60            })
61    }
62
63    pub(super) fn prepared_module_cache(
64        &self,
65        worker_index: usize,
66    ) -> harn_vm::PreparedModuleCache {
67        let mut caches = self.prepared_module_caches.lock().unwrap();
68        caches.resize_with(worker_index.saturating_add(1), Default::default);
69        caches[worker_index].clone()
70    }
71
72    pub(super) fn stdio_available(&self) -> bool {
73        self.stdio_available
74    }
75}