Skip to content

Commit cc3a364

Browse files
authored
Merge pull request #65 from Freax13/fix-test-code
Consider all other exit codes besides 'test-success-exit-code' as failures
2 parents 1f48d1c + 7c686f1 commit cc3a364

File tree

10 files changed

+124
-0
lines changed

10 files changed

+124
-0
lines changed

.github/workflows/build.yml

+4
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ jobs:
116116
working-directory: example-kernels/runner-doctest
117117
name: 'Run `cargo test -Z doctest-xcompile` for "runner-doctest" kernel'
118118

119+
- run: cargo test
120+
working-directory: example-kernels/runner-fail-reboot
121+
name: 'Run `cargo test` for "runner-fail-reboot" kernel'
122+
119123
check_formatting:
120124
name: "Check Formatting"
121125
runs-on: ubuntu-latest

Readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ test-success-exit-code = {integer}
8282

8383
# The timeout for running a test through `bootimage test` or `bootimage runner` (in seconds)
8484
test-timeout = 300
85+
86+
# Whether the `-no-reboot` flag should be passed to test executables
87+
test-no-reboot = true
8588
```
8689

8790
## License

example-kernels/Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example-kernels/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ members = [
33
"basic",
44
"runner",
55
"runner-doctest",
6+
"runner-fail-reboot",
67
"runner-test",
78
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[build]
2+
target = "../x86_64-bootimage-example-kernels.json"
3+
4+
[target.'cfg(target_os = "none")']
5+
runner = "bootimage runner"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target/
2+
**/*.rs.bk
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "runner-fail-reboot"
3+
version = "0.1.0"
4+
authors = ["Philipp Oppermann <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
bootloader = "0.9.7"
9+
x86_64 = "0.11.0"
10+
rlibc = "1.0.0"
11+
12+
[package.metadata.bootimage]
13+
test-success-exit-code = 0 # this will test for the reboot
14+
test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-display", "none"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#![no_std]
2+
#![cfg_attr(test, no_main)]
3+
#![feature(custom_test_frameworks)]
4+
#![test_runner(crate::test_runner)]
5+
#![reexport_test_harness_main = "test_main"]
6+
7+
extern crate rlibc;
8+
9+
pub fn test_runner(tests: &[&dyn Fn()]) {
10+
for test in tests.iter() {
11+
test();
12+
}
13+
14+
unsafe {
15+
exit_qemu(ExitCode::Success);
16+
}
17+
}
18+
19+
#[test_case]
20+
fn should_reboot() {
21+
// this overflows the stack which leads to a triple fault
22+
// the as-if rule might allow this to get optimized away on release builds
23+
#[allow(unconditional_recursion)]
24+
fn stack_overflow() {
25+
stack_overflow()
26+
}
27+
stack_overflow()
28+
}
29+
30+
pub enum ExitCode {
31+
Success,
32+
Failed,
33+
}
34+
35+
impl ExitCode {
36+
fn code(&self) -> u32 {
37+
match self {
38+
ExitCode::Success => 0x10,
39+
ExitCode::Failed => 0x11,
40+
}
41+
}
42+
}
43+
44+
/// exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu)
45+
pub unsafe fn exit_qemu(exit_code: ExitCode) {
46+
use x86_64::instructions::port::Port;
47+
48+
let mut port = Port::<u32>::new(0xf4);
49+
port.write(exit_code.code());
50+
}
51+
52+
#[cfg(test)]
53+
#[no_mangle]
54+
pub extern "C" fn _start() -> ! {
55+
test_main();
56+
57+
unsafe {
58+
exit_qemu(ExitCode::Failed);
59+
}
60+
61+
loop {}
62+
}
63+
64+
#[cfg(test)]
65+
#[panic_handler]
66+
fn panic(_info: &core::panic::PanicInfo) -> ! {
67+
unsafe {
68+
exit_qemu(ExitCode::Failed);
69+
}
70+
loop {}
71+
}

src/config.rs

+9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ pub struct Config {
3333
/// An exit code that should be considered as success for test executables (applies to
3434
/// `bootimage runner`)
3535
pub test_success_exit_code: Option<i32>,
36+
/// Whether the `-no-reboot` flag should be passed to test executables
37+
///
38+
/// Defaults to `true`
39+
pub test_no_reboot: bool,
3640
}
3741

3842
/// Reads the configuration from a `package.metadata.bootimage` in the given Cargo.toml.
@@ -91,6 +95,9 @@ fn read_config_inner(manifest_path: &Path) -> Result<Config> {
9195
("test-args", Value::Array(array)) => {
9296
config.test_args = Some(parse_string_array(array, "test-args")?);
9397
}
98+
("test-no-reboot", Value::Boolean(no_reboot)) => {
99+
config.test_no_reboot = Some(no_reboot);
100+
}
94101
(key, value) => {
95102
return Err(anyhow!(
96103
"unexpected `package.metadata.bootimage` \
@@ -123,6 +130,7 @@ struct ConfigBuilder {
123130
test_args: Option<Vec<String>>,
124131
test_timeout: Option<u32>,
125132
test_success_exit_code: Option<i32>,
133+
test_no_reboot: Option<bool>,
126134
}
127135

128136
impl Into<Config> for ConfigBuilder {
@@ -140,6 +148,7 @@ impl Into<Config> for ConfigBuilder {
140148
test_args: self.test_args,
141149
test_timeout: self.test_timeout.unwrap_or(60 * 5),
142150
test_success_exit_code: self.test_success_exit_code,
151+
test_no_reboot: self.test_no_reboot.unwrap_or(true),
143152
}
144153
}
145154
}

src/run.rs

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ pub fn run(
2323
.map(|arg| arg.replace("{}", &format!("{}", image_path.display())))
2424
.collect();
2525
if is_test {
26+
if config.test_no_reboot {
27+
run_command.push("-no-reboot".to_owned());
28+
}
2629
if let Some(args) = config.test_args {
2730
run_command.extend(args);
2831
}
@@ -69,6 +72,7 @@ pub fn run(
6972
let qemu_exit_code = exit_status.code().ok_or(RunError::NoQemuExitCode)?;
7073
match config.test_success_exit_code {
7174
Some(code) if qemu_exit_code == code => 0,
75+
Some(_) if qemu_exit_code == 0 => 1,
7276
_ => qemu_exit_code,
7377
}
7478
}

0 commit comments

Comments
 (0)