diff --git a/Cargo.lock b/Cargo.lock index 721b08e8..1bab0118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3732,6 +3732,7 @@ dependencies = [ "clap", "flate2", "log", + "rand 0.4.6", "reqwest", "slight-common", "slight-core", @@ -3745,6 +3746,7 @@ dependencies = [ "slight-sql", "tar", "tempdir", + "tempfile", "tokio", "toml", "tracing", @@ -3845,6 +3847,7 @@ dependencies = [ "anyhow", "hyper", "mosquitto-rs", + "rand 0.8.5", "signal-child", "tempdir", "tokio", @@ -4167,16 +4170,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix 0.36.4", + "windows-sys 0.42.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8b511702..e215f007 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,9 @@ flate2 = "1" tar = "0.4" [dev-dependencies] -tempdir = { workspace = true} +tempdir = { workspace = true } +tempfile = { workspace = true } +rand = { worspace = true } [features] default = ["keyvalue", "distributed-locking", "messaging", "runtime-configs", "sql", "http-server", "http-client"] @@ -83,6 +85,7 @@ tokio = { version = "1", features = ["full"] } tracing = { version = "0.1", features = ["log"] } toml = "0.5" tempdir = "0.3" +tempfile = "3.4" log = { version = "0.4", default-features = false } env_logger = "0.9" as-any = "0.3" diff --git a/src/commands/run.rs b/src/commands/run.rs index 39478d5a..dbd8c863 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -353,3 +353,53 @@ fn maybe_add_named_capability_to_store( Ok(()) } + +#[cfg(test)] +mod unittest { + use std::path::{Path, PathBuf}; + use std::fs::File; + use tempfile::tempdir; + use tokio::fs; + use rand::Rng; + use slight_runtime::IORedirects; + use crate::commands::run::{handle_run, RunArgs}; + + #[tokio::test] + async fn test_handle_run_with_io() -> anyhow::Result<()> { + let module = "./src/commands/test/io-test.wasm"; + assert!(Path::new(module).exists()); + let slightfile = "./src/commands/test/slightfile.toml"; + assert!(Path::new(slightfile).exists()); + + let tmp_dir = tempdir()?; + let stdin_path = tmp_dir.path().join("stdin"); + let stdout_path = tmp_dir.path().join("stdout"); + let stderr_path = tmp_dir.path().join("stderr"); + + let canary: String = rand::thread_rng() + .gen_ascii_chars() + .take(7) + .map(char::from) + .collect(); + fs::write(&stdin_path, &canary).await?; + let _ = File::create(&stdout_path)?; + let _ = File::create(&stderr_path)?; + + let args = RunArgs{ + module: PathBuf::from(module), + slightfile: PathBuf::from(slightfile), + io_redirects: Some(IORedirects{ + stdin_path: PathBuf::from(&stdin_path), + stdout_path: PathBuf::from(&stdout_path), + stderr_path: PathBuf::from(&stderr_path), + }) + }; + + let _ = handle_run(args).await?; + let stdout_output = fs::read_to_string(&stdout_path).await?; + assert_eq!(stdout_output, canary); + let stderr_output = fs::read_to_string(&stderr_path).await?; + assert_eq!(stderr_output, format!("error: {canary}")); + Ok(()) + } +} diff --git a/src/commands/test/io-test.wasm b/src/commands/test/io-test.wasm new file mode 100755 index 00000000..1cc602d6 Binary files /dev/null and b/src/commands/test/io-test.wasm differ diff --git a/src/commands/test/slightfile.toml b/src/commands/test/slightfile.toml new file mode 100644 index 00000000..5ee47d8d --- /dev/null +++ b/src/commands/test/slightfile.toml @@ -0,0 +1,5 @@ +specversion = "0.2" + +[[capability]] +resource = "configs.envvars" +name = "env-configs" diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 08b26462..11d38e40 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -17,6 +17,7 @@ tokio = { workspace = true } anyhow = { workspace = true } mosquitto-rs = { version = "0.4.0", features = ["vendored-openssl", "vendored-mosquitto"] } tempdir = { workspace = true } +rand = { workspace = true } [target.'cfg(unix)'.dev-dependencies] signal-child = "1" diff --git a/tests/build.rs b/tests/build.rs index 4830858f..867cfedf 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -7,6 +7,7 @@ const WIT_DIRECTORY: &str = "wit/*"; const KEYVALUE_TEST_PATH: &str = "./keyvalue-test"; const HTTP_TEST_PATH: &str = "./http-test"; const CONFIGS_TEST_PATH: &str = "./configs-test"; +const IO_TEST_PATH: &str = "./io-test"; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -28,6 +29,7 @@ fn main() { std::process::exit(1); } // Build test wasm modules + cargo_wasi_build(IO_TEST_PATH); cargo_wasi_build(KEYVALUE_TEST_PATH); cargo_wasi_build(HTTP_TEST_PATH); cargo_wasi_build(CONFIGS_TEST_PATH); diff --git a/tests/io-test/Cargo.lock b/tests/io-test/Cargo.lock new file mode 100644 index 00000000..6ce1b7a9 --- /dev/null +++ b/tests/io-test/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "508b352bb5c066aac251f6daf6b36eccd03e8a88e8081cd44959ea277a3af9a8" + +[[package]] +name = "io-test" +version = "0.1.0" +dependencies = [ + "anyhow", +] diff --git a/tests/io-test/Cargo.toml b/tests/io-test/Cargo.toml new file mode 100644 index 00000000..41d15ed3 --- /dev/null +++ b/tests/io-test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "io-test" +version = "0.1.0" +edition = "2021" +authors = [ "DeisLabs Engineering Team" ] + +[[bin]] +name = "io-test" +test = false + +[dependencies] +anyhow = "1" + +[workspace] diff --git a/tests/io-test/slightfile.toml b/tests/io-test/slightfile.toml new file mode 100644 index 00000000..353cc64b --- /dev/null +++ b/tests/io-test/slightfile.toml @@ -0,0 +1 @@ +specversion = "0.2" diff --git a/tests/io-test/src/main.rs b/tests/io-test/src/main.rs new file mode 100644 index 00000000..d3c15fd6 --- /dev/null +++ b/tests/io-test/src/main.rs @@ -0,0 +1,11 @@ +use std::io; +use std::io::Write; +use anyhow::Result; + +fn main() -> Result<()> { + let mut buffer = String::new(); + io::stdin().read_line(&mut buffer)?; + io::stdout().write_all(buffer.as_bytes())?; + io::stderr().write_all(format!("error: {buffer}").as_bytes())?; + Ok(()) +}