unittest/
main.rs

1use std::{io::BufRead, sync::OnceLock, time::Instant};
2
3use unittest_report::{Report, ReportInfo, TestResult};
4
5static RESULT: OnceLock<Report> = OnceLock::new();
6
7fn try_bench(path: &str) {
8    let Ok(file) = std::fs::File::open(path) else {
9        return;
10    };
11    println!("starting benchmarking ({})", path);
12    let start = Instant::now();
13    for line in std::io::BufReader::new(file).lines() {
14        if let Ok(line) = &line {
15            if line.contains("\u{0000}") {
16                continue;
17            }
18            if !line.is_ascii() {
19                continue;
20            }
21            println!("STARTING {}", line);
22            let mut possibles = Vec::new();
23            for exe in std::fs::read_dir("/initrd").unwrap() {
24                if exe
25                    .as_ref()
26                    .unwrap()
27                    .file_name()
28                    .to_string_lossy()
29                    .starts_with(line)
30                {
31                    possibles.push(format!(
32                        "/initrd/{}",
33                        exe.as_ref().unwrap().file_name().to_string_lossy()
34                    ));
35                }
36                if exe
37                    .as_ref()
38                    .unwrap()
39                    .file_name()
40                    .to_string_lossy()
41                    .starts_with(&line.replace("-", "_"))
42                {
43                    possibles.push(format!(
44                        "/initrd/{}",
45                        exe.as_ref().unwrap().file_name().to_string_lossy()
46                    ));
47                }
48            }
49            for (i, exe) in possibles.iter().enumerate() {
50                let mut cmd = std::process::Command::new(exe);
51                cmd.args(["--bench"]);
52                if let Ok(mut test_comp) = cmd.spawn() {
53                    test_comp.wait().unwrap();
54                } else {
55                    if i == possibles.len() - 1 {
56                        eprintln!("failed to start {}", exe);
57                    }
58                }
59            }
60        }
61    }
62    let dur = Instant::now() - start;
63    println!("unittest: benches finished in {:?}", dur);
64}
65
66fn main() {
67    try_bench("/initrd/bench_bins");
68    try_bench("/initrd/bench_bin");
69    let Ok(file) = std::fs::File::open("/initrd/test_bins")
70        .inspect_err(|e| eprintln!("failed to open test bins: {}", e))
71    else {
72        return;
73    };
74
75    let heartbeat_thread = std::thread::spawn(|| io_heartbeat());
76
77    let mut reports = vec![];
78    let start = Instant::now();
79    for line in std::io::BufReader::new(file).lines() {
80        if let Ok(line) = &line {
81            if line.contains("\u{0000}") {
82                continue;
83            }
84            if !line.is_ascii() {
85                continue;
86            }
87            let line = &format!("/initrd/{}", line);
88            println!("STARTING {}", line);
89            let mut cmd = std::process::Command::new(line);
90            cmd.args(["--test"]);
91            if let Ok(mut test_comp) = cmd.spawn() {
92                test_comp.wait().unwrap();
93                reports.push(TestResult {
94                    name: line.clone(),
95                    passed: true,
96                });
97            } else {
98                reports.push(TestResult {
99                    name: line.clone(),
100                    passed: false,
101                });
102            }
103        }
104    }
105    let dur = Instant::now() - start;
106    println!("unittest: tests finished, waiting for status request");
107    RESULT
108        .set(Report::ready(ReportInfo {
109            time: dur,
110            tests: reports,
111        }))
112        .unwrap();
113    heartbeat_thread.join().unwrap();
114}
115
116fn io_heartbeat() {
117    let mut buf = String::new();
118    while let Ok(_) = std::io::stdin().read_line(&mut buf) {
119        match buf.as_str().trim() {
120            "status" => {
121                if let Some(report) = RESULT.get() {
122                    println!("unittest: creating report");
123                    println!("REPORT {}", serde_json::to_string(report).unwrap());
124                    return;
125                } else {
126                    println!(
127                        "REPORT {}",
128                        serde_json::to_string(&Report::pending()).unwrap()
129                    );
130                }
131            }
132            _ => {
133                println!("!! unknown command: {}", buf);
134            }
135        }
136        buf.clear();
137    }
138}