cargo_image_runner/runner/
mod.rs1use crate::core::context::Context;
4use crate::core::error::Result;
5use std::path::Path;
6
7pub mod io;
8
9#[cfg(feature = "qemu")]
11pub mod qemu;
12
13pub trait Runner: Send + Sync {
15 fn run(&self, ctx: &Context, image_path: &Path) -> Result<RunResult>;
19
20 fn run_with_io(
25 &self,
26 ctx: &Context,
27 image_path: &Path,
28 handler: &mut dyn io::IoHandler,
29 ) -> Result<RunResult> {
30 let _ = handler;
31 self.run(ctx, image_path)
32 }
33
34 fn is_available(&self) -> bool;
36
37 fn validate(&self, ctx: &Context) -> Result<()> {
39 if !self.is_available() {
40 return Err(crate::core::error::Error::runner(format!(
41 "{} is not available on this system",
42 self.name()
43 )));
44 }
45
46 let _ = ctx;
47 Ok(())
48 }
49
50 fn name(&self) -> &str;
52}
53
54#[derive(Debug)]
56pub struct RunResult {
57 pub exit_code: i32,
59
60 pub success: bool,
62
63 pub captured_output: Option<CapturedOutput>,
65
66 pub timed_out: bool,
68}
69
70#[non_exhaustive]
72#[derive(Debug, Clone)]
73pub struct CapturedOutput {
74 pub stdout: String,
75 pub stderr: String,
76 pub serial: Option<String>,
78}
79
80impl RunResult {
81 pub fn new(exit_code: i32, success: bool) -> Self {
83 Self {
84 exit_code,
85 success,
86 captured_output: None,
87 timed_out: false,
88 }
89 }
90
91 pub fn success() -> Self {
93 Self {
94 exit_code: 0,
95 success: true,
96 captured_output: None,
97 timed_out: false,
98 }
99 }
100
101 pub fn failed(exit_code: i32) -> Self {
103 Self {
104 exit_code,
105 success: false,
106 captured_output: None,
107 timed_out: false,
108 }
109 }
110
111 pub fn with_output(mut self, stdout: String, stderr: String) -> Self {
113 self.captured_output = Some(CapturedOutput {
114 stdout,
115 stderr,
116 serial: None,
117 });
118 self
119 }
120
121 pub fn with_serial(mut self, serial: String) -> Self {
123 if let Some(ref mut output) = self.captured_output {
124 output.serial = Some(serial);
125 } else {
126 self.captured_output = Some(CapturedOutput {
127 stdout: String::new(),
128 stderr: String::new(),
129 serial: Some(serial),
130 });
131 }
132 self
133 }
134
135 pub fn with_timeout(mut self) -> Self {
137 self.timed_out = true;
138 self
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_run_result_success() {
148 let result = RunResult::success();
149 assert_eq!(result.exit_code, 0);
150 assert!(result.success);
151 }
152
153 #[test]
154 fn test_run_result_failed() {
155 let result = RunResult::failed(1);
156 assert_eq!(result.exit_code, 1);
157 assert!(!result.success);
158 }
159
160 #[test]
161 fn test_run_result_custom() {
162 let result = RunResult::new(33, true);
163 assert_eq!(result.exit_code, 33);
164 assert!(result.success);
165 }
166}