Merge #167
167: Makefile: Support dumping stack size usage r=alistair23 a=alistair23
I have lots of issues of running out of stack, let's add a Makefile
option to print stack usage.
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Co-authored-by: Alistair Francis <alistair.francis@wdc.com>
diff --git a/.travis.yml b/.travis.yml
index 7b6bf87..8efe4b7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,10 +16,10 @@
# Once Travis supports a version of Ubuntu Disco or newer we can apt install QEMU for RISC-V
# Until then we need to build it ourselves
before_install:
-# - sudo apt-get -y install qemu-system-misc
-# addons:
-# apt:
-# update: true
+ # - sudo apt-get -y install qemu-system-misc
+ # addons:
+ # apt:
+ # update: true
- wget https://download.qemu.org/qemu-4.2.0.tar.xz
- tar xJf qemu-4.2.0.tar.xz
- pushd qemu-4.2.0
@@ -42,6 +42,7 @@
script:
- make test
# Run a QEMU instance of the HiFive1 app
- - make flash-hifive1 EXAMPLE=hello_world
- - timeout --foreground 10s qemu-system-riscv32 -M sifive_e -kernel ../tock/boards/hifive1/target/riscv32imac-unknown-none-elf/release/hifive1 -device loader,file=./target/riscv32imac-unknown-none-elf/tab/hifive1/hello_world/rv32imac.tbf,addr=0x20430000 -nographic | tee serial
- - grep "Hello Tock World" serial
+ - PLATFORM=hifive1 cargo rrv32imac --example libtock_test --features=alloc --features=__internal_disable_gpio_in_integration_test
+ - pushd test-runner
+ - cargo run
+ - popd
diff --git a/Cargo.toml b/Cargo.toml
index 5641d3c..eb56daa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@
alloc = ["libtock-core/alloc"]
custom_panic_handler = ["libtock-core/custom_panic_handler"]
custom_alloc_error_handler = ["libtock-core/custom_alloc_error_handler"]
+__internal_disable_gpio_in_integration_test = []
[dependencies]
core = { package = "async-support", path = "async-support" }
@@ -59,5 +60,6 @@
members = [
"async-support",
"codegen",
- "core"
+ "core",
+ "test-runner"
]
diff --git a/examples-features/libtock_test.rs b/examples-features/libtock_test.rs
index 26cccb4..5fe9e59 100644
--- a/examples-features/libtock_test.rs
+++ b/examples-features/libtock_test.rs
@@ -2,7 +2,6 @@
// Requires P0.03 and P0.04 to be connected (on a nRF52 DK).
#![no_std]
-
extern crate alloc;
use alloc::string::String;
@@ -36,6 +35,10 @@
}
}
+#[cfg_attr(
+ feature = "__internal_disable_gpio_in_integration_test",
+ allow(unused_variables)
+)]
async fn libtock_test(
test: &mut LibtockTest,
timer: &mut DriverContext,
@@ -48,6 +51,7 @@
test.heap()?;
test.drivers_only_instantiable_once()?;
test.callbacks(timer).await?;
+ #[cfg(not(feature = "__internal_disable_gpio_in_integration_test"))]
test.gpio(gpio)?;
Ok(())
}
@@ -113,7 +117,7 @@
let mut with_callback = timer_context.with_callback(|_, _| callback_hit = true);
let mut timer = with_callback.init()?;
- timer.set_alarm(Duration::from_ms(50))?;
+ timer.set_alarm(Duration::from_ms(1000))?;
AlternatingFuture { yielded: false }.await;
@@ -122,6 +126,10 @@
self.check_if_true(callback_hit, "Callbacks")
}
+ #[cfg_attr(
+ feature = "__internal_disable_gpio_in_integration_test",
+ allow(dead_code)
+ )]
fn gpio(&mut self, gpio: &mut GpioDriverFactory) -> TockResult<()> {
let mut gpio_driver = gpio.init_driver().ok().unwrap();
diff --git a/test-runner/Cargo.toml b/test-runner/Cargo.toml
new file mode 100644
index 0000000..b9769b9
--- /dev/null
+++ b/test-runner/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "test-runner"
+version = "0.1.0"
+authors = ["torfmaster <briefe@kebes.de>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+structopt = { version = "0.3", default-features = false }
+futures = "0.3.4"
+
+[dependencies.async-std]
+version = "1.5.0"
+features = ["attributes"]
+
+[dependencies.tokio]
+version = "0.2.12"
+features = ["process", "rt-threaded", "macros", "io-util", "time"]
diff --git a/test-runner/src/main.rs b/test-runner/src/main.rs
new file mode 100644
index 0000000..0ee3455
--- /dev/null
+++ b/test-runner/src/main.rs
@@ -0,0 +1,129 @@
+use std::fmt;
+use std::process::Stdio;
+use std::time::Duration;
+use tokio::io::AsyncBufReadExt;
+use tokio::io::BufReader;
+use tokio::process::Command;
+use tokio::time::timeout;
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ timeout(Duration::from_secs(10), perform_tests()).await?
+}
+
+async fn perform_tests() -> Result<(), Box<dyn std::error::Error>> {
+ let mut failed_tests = Vec::new();
+
+ let tests = Command::new("qemu-system-riscv32")
+ .arg("-M")
+ .arg("sifive_e")
+ .arg("-kernel")
+ .arg("../../tock/boards/hifive1/target/riscv32imac-unknown-none-elf/release/hifive1")
+ .arg("-device")
+ .arg("loader,file=./../target/riscv32imac-unknown-none-elf/tab/hifive1/libtock_test/rv32imac.tbf,addr=0x20430000")
+ .arg("-nographic")
+ .stdout(Stdio::piped())
+ .kill_on_drop(true)
+ .spawn()?;
+
+ let stdout = tests.stdout.unwrap();
+
+ let stdout_reader = BufReader::new(stdout);
+ let mut stdout_lines = stdout_reader.lines();
+
+ while let Some(line) = stdout_lines.next_line().await? {
+ println!("UART: {}", line);
+ let test_result = test_succeeded(line, &mut failed_tests);
+ if let Some(true) = test_result {
+ return Ok(());
+ }
+ if let Some(false) = test_result {
+ return Err(Box::new(TestError::TestFailure(failed_tests)));
+ }
+ }
+ Err(Box::new(TestError::QemuExit))
+}
+
+fn test_succeeded(input: String, failed_tests: &mut Vec<String>) -> Option<bool> {
+ let success = input.find("[ OK ]").is_some();
+ let failure = input.find("[ FAILURE ]").is_some();
+ let input = input.replace("[ OK ]", "");
+ let input = input.replace("[ FAILURE ]", "");
+ let input = input.trim();
+ if input == "Test suite finished with state SUCCESS" && success {
+ return Some(true);
+ } else if input == "Test suite finished with state FAILURE" && !success {
+ return Some(false);
+ } else if failure {
+ failed_tests.push(input.to_string());
+ }
+ None
+}
+
+#[derive(Debug)]
+enum TestError {
+ TestFailure(Vec<String>),
+ QemuExit,
+}
+
+impl fmt::Display for TestError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ TestError::TestFailure(failures) => {
+ writeln!(f, "A test failure occured. Failed Tests")?;
+ for test in failures {
+ writeln!(f, "Test failed\"{}\"", test)?;
+ }
+ Ok(())
+ }
+ TestError::QemuExit => write!(f, "Qemu exited unexpectedly."),
+ }
+ }
+}
+
+impl std::error::Error for TestError {}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ pub fn detects_success_of_test_suite() {
+ let mut test_results = Vec::new();
+ assert_eq!(
+ test_succeeded(
+ "[ OK ] Test suite finished with state SUCCESS".into(),
+ &mut test_results
+ ),
+ Some(true)
+ );
+ }
+
+ #[test]
+ pub fn detects_failure_of_test_suite() {
+ let mut test_results = Vec::new();
+ assert_eq!(
+ test_succeeded(
+ "[ FAILURE ] Test suite finished with state FAILURE".into(),
+ &mut test_results
+ ),
+ Some(false)
+ );
+ }
+
+ #[test]
+ pub fn detects_test_failures() {
+ let mut test_results = Vec::new();
+ test_succeeded("[ FAILURE ] Another test".into(), &mut test_results);
+ assert_eq!(test_results, vec!["Another test"]);
+ }
+
+ #[test]
+ pub fn ignores_other_tests() {
+ let mut test_results = Vec::new();
+ assert_eq!(
+ test_succeeded("[ SUCCESS ] Another test".into(), &mut test_results),
+ None
+ );
+ }
+}