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}