From 8a1f0f874eb31427dd8dcf39e3fbfd2e54c8b29c Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Thu, 6 Jul 2023 00:14:58 +0900 Subject: [PATCH] feat: add p2 target to wasmcloud.toml Signed-off-by: Victor Adossi --- .github/workflows/rust_ci.yml | 17 ++++ crates/wash-lib/src/build.rs | 42 ++++++--- crates/wash-lib/src/parser/mod.rs | 90 +++++++++++++++---- crates/wash-lib/src/start/wasmcloud.rs | 86 ++++++++++++++---- .../files/minimal_rust_actor_core_module.toml | 8 ++ .../files/minimal_rust_actor_preview1.toml | 8 ++ .../files/minimal_rust_actor_preview2.toml | 8 ++ crates/wash-lib/tests/parser/main.rs | 72 ++++++++++++++- tests/common.rs | 44 ++++++--- tests/integration_dev.rs | 10 ++- tests/integration_get.rs | 10 ++- 11 files changed, 326 insertions(+), 69 deletions(-) create mode 100644 crates/wash-lib/tests/parser/files/minimal_rust_actor_core_module.toml create mode 100644 crates/wash-lib/tests/parser/files/minimal_rust_actor_preview1.toml create mode 100644 crates/wash-lib/tests/parser/files/minimal_rust_actor_preview2.toml diff --git a/.github/workflows/rust_ci.yml b/.github/workflows/rust_ci.yml index 08e8f02d..6017ec2e 100644 --- a/.github/workflows/rust_ci.yml +++ b/.github/workflows/rust_ci.yml @@ -35,6 +35,23 @@ jobs: shared-key: "${{ matrix.os }}-shared-cache" - name: Install nextest uses: taiki-e/install-action@nextest + + # Sometimes, unit tests will get stuck executing wash during the + # loading CA certificates from the :otp store step. All you see is: + # + # > stderr log: 14:38:03.656 [info] Loading 467 CA(s) from :otp store + # + # when this happens, tests like can_download_and_start_wasmcloud get stuck and fail. + # to avoid this, we can call wash up/down and at least cause this loading as early as possible, + # hoping it does not happen again (or completes near instantaneously) during a test. + - name: Build wash + run: make build + - name: Cycle wash + run: | + cargo run -- up --detached; + sleep 10; + cargo run -- down; + - name: Run all wash & wash-lib unit tests run: make test-wash-ci diff --git a/crates/wash-lib/src/build.rs b/crates/wash-lib/src/build.rs index 71b76b4e..1a15e910 100644 --- a/crates/wash-lib/src/build.rs +++ b/crates/wash-lib/src/build.rs @@ -4,13 +4,15 @@ use std::{fs, io::ErrorKind, path::PathBuf, process, str::FromStr}; use anyhow::{anyhow, bail, Result}; -use crate::cli::{ - claims::{sign_file, ActorMetadata, SignCommand}, - OutputKind, -}; -use crate::parser::{ - ActorConfig, CommonConfig, InterfaceConfig, LanguageConfig, ProjectConfig, ProviderConfig, - RustConfig, TinyGoConfig, TypeConfig, +use crate::{ + cli::{ + claims::{sign_file, ActorMetadata, SignCommand}, + OutputKind, + }, + parser::{ + ActorConfig, CommonConfig, InterfaceConfig, LanguageConfig, ProjectConfig, ProviderConfig, + RustConfig, TinyGoConfig, TypeConfig, WasmTarget, + }, }; /// Configuration for signing an artifact (actor or provider) including issuer and subject key, the path to where keys can be found, and an option to @@ -126,19 +128,31 @@ fn build_rust_actor( None => process::Command::new("cargo"), }; + if actor_config.wasm_target == WasmTarget::WasiPreview2 { + bail!("Building projects targeting WASI preview 2 is not yet supported"); + } + // Change directory into the project directory std::env::set_current_dir(&common_config.path)?; let metadata = cargo_metadata::MetadataCommand::new().exec()?; let target_path = metadata.target_directory.as_path(); - let result = command.args(["build", "--release"]).status().map_err(|e| { - if e.kind() == ErrorKind::NotFound { - anyhow!("{:?} command is not found", command.get_program()) - } else { - anyhow!(e) - } - })?; + let result = command + .args([ + "build", + "--release", + "--target", + rust_config.build_target(&actor_config.wasm_target), + ]) + .status() + .map_err(|e| { + if e.kind() == ErrorKind::NotFound { + anyhow!("{:?} command is not found", command.get_program()) + } else { + anyhow!(e) + } + })?; if !result.success() { bail!("Compiling actor failed: {}", result.to_string()) diff --git a/crates/wash-lib/src/parser/mod.rs b/crates/wash-lib/src/parser/mod.rs index c3b7df38..606590a1 100644 --- a/crates/wash-lib/src/parser/mod.rs +++ b/crates/wash-lib/src/parser/mod.rs @@ -5,16 +5,17 @@ use anyhow::{anyhow, bail, Result}; use cargo_toml::{Manifest, Product}; use config::Config; use semver::Version; -use std::{fs, path::PathBuf}; +use serde::Deserialize; +use std::{fmt::Display, fs, path::PathBuf}; -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(rename_all = "snake_case")] pub enum LanguageConfig { Rust(RustConfig), TinyGo(TinyGoConfig), } -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(rename_all = "snake_case")] pub enum TypeConfig { Actor(ActorConfig), @@ -22,7 +23,8 @@ pub enum TypeConfig { Interface(InterfaceConfig), } -#[derive(serde::Deserialize, Debug, Clone)] +/// Project configuration, normally specified in the root keys of a wasmcloud.toml file +#[derive(Deserialize, Debug, Clone)] pub struct ProjectConfig { /// The language of the project, e.g. rust, tinygo. Contains specific configuration for that language. pub language: LanguageConfig, @@ -34,7 +36,7 @@ pub struct ProjectConfig { pub common: CommonConfig, } -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct ActorConfig { /// The list of provider claims that this actor requires. eg. ["wasmcloud:httpserver", "wasmcloud:blobstore"] pub claims: Vec, @@ -47,11 +49,12 @@ pub struct ActorConfig { /// The filename of the signed wasm actor. pub filename: Option, /// The target wasm target to build for. Defaults to "wasm32-unknown-unknown". - pub wasm_target: String, + pub wasm_target: WasmTarget, /// The call alias of the actor. pub call_alias: Option, } -#[derive(serde::Deserialize, Debug, PartialEq)] + +#[derive(Deserialize, Debug, PartialEq)] struct RawActorConfig { /// The list of provider claims that this actor requires. eg. ["wasmcloud:httpserver", "wasmcloud:blobstore"] pub claims: Option>, @@ -83,19 +86,20 @@ impl TryFrom for ActorConfig { filename: raw_config.filename, wasm_target: raw_config .wasm_target - .unwrap_or_else(|| "wasm32-unknown-unknown".to_string()), + .map(WasmTarget::from) + .unwrap_or_default(), call_alias: raw_config.call_alias, }) } } -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct ProviderConfig { /// The capability ID of the provider. pub capability_id: String, /// The vendor name of the provider. pub vendor: String, } -#[derive(serde::Deserialize, Debug, PartialEq)] +#[derive(Deserialize, Debug, PartialEq)] struct RawProviderConfig { /// The capability ID of the provider. pub capability_id: String, @@ -114,14 +118,14 @@ impl TryFrom for ProviderConfig { } } -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct InterfaceConfig { /// Directory to output HTML. pub html_target: PathBuf, /// Path to codegen.toml file. pub codegen_config: PathBuf, } -#[derive(serde::Deserialize, Debug, PartialEq)] +#[derive(Deserialize, Debug, PartialEq)] struct RawInterfaceConfig { /// Directory to output HTML. Defaults to "./html". @@ -145,7 +149,7 @@ impl TryFrom for InterfaceConfig { } } -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct RustConfig { /// The path to the cargo binary. Optional, will default to search the user's `PATH` for `cargo` if not specified. pub cargo_path: Option, @@ -153,7 +157,19 @@ pub struct RustConfig { pub target_path: Option, } -#[derive(serde::Deserialize, Debug, PartialEq, Default, Clone)] +impl RustConfig { + pub fn build_target(&self, wasm_target: &WasmTarget) -> &'static str { + match wasm_target { + WasmTarget::CoreModule => "wasm32-unknown-unknown", + // NOTE: eventually "wasm32-wasi" will be renamed to "wasm32-wasi-preview1" + // https://github.com/rust-lang/compiler-team/issues/607 + WasmTarget::WasiPreview1 => "wasm32-wasi", + WasmTarget::WasiPreview2 => "wasm32-wasi-preview2", + } + } +} + +#[derive(Deserialize, Debug, PartialEq, Default, Clone)] struct RawRustConfig { /// The path to the cargo binary. Optional, will default to search the user's `PATH` for `cargo` if not specified. pub cargo_path: Option, @@ -173,7 +189,7 @@ impl TryFrom for RustConfig { } /// Configuration common amoung all project types & languages. -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] pub struct CommonConfig { /// Name of the project. pub name: String, @@ -186,7 +202,45 @@ pub struct CommonConfig { pub wasm_bin_name: Option, } -#[derive(serde::Deserialize, Debug)] +#[derive(Debug, Deserialize, Default, Clone, Eq, PartialEq)] +pub enum WasmTarget { + #[default] + #[serde(alias = "wasm32-unknown-unknown")] + CoreModule, + #[serde(alias = "wasm32-wasi", alias = "wasm32-wasi-preview1")] + WasiPreview1, + #[serde(alias = "wasm32-wasi-preview2")] + WasiPreview2, +} + +impl From<&str> for WasmTarget { + fn from(value: &str) -> Self { + match value { + "wasm32-wasi-preview1" => WasmTarget::WasiPreview1, + "wasm32-wasi" => WasmTarget::WasiPreview1, + "wasm32-wasi-preview2" => WasmTarget::WasiPreview2, + _ => WasmTarget::CoreModule, + } + } +} + +impl From for WasmTarget { + fn from(value: String) -> Self { + value.as_str().into() + } +} + +impl Display for WasmTarget { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match &self { + WasmTarget::CoreModule => "wasm32-unknown-unknown", + WasmTarget::WasiPreview1 => "wasm32-wasi", + WasmTarget::WasiPreview2 => "wasm32-wasi-preview2", + }) + } +} + +#[derive(Deserialize, Debug)] struct RawProjectConfig { /// The language of the project, e.g. rust, tinygo. This is used to determine which config to parse. pub language: String, @@ -205,13 +259,13 @@ struct RawProjectConfig { pub tinygo: Option, } -#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct TinyGoConfig { /// The path to the tinygo binary. Optional, will default to `tinygo` if not specified. pub tinygo_path: Option, } -#[derive(serde::Deserialize, Debug, PartialEq, Default)] +#[derive(Deserialize, Debug, PartialEq, Default)] struct RawTinyGoConfig { /// The path to the tinygo binary. Optional, will default to `tinygo` if not specified. pub tinygo_path: Option, diff --git a/crates/wash-lib/src/start/wasmcloud.rs b/crates/wash-lib/src/start/wasmcloud.rs index d09d06d5..b575ef44 100644 --- a/crates/wash-lib/src/start/wasmcloud.rs +++ b/crates/wash-lib/src/start/wasmcloud.rs @@ -242,6 +242,8 @@ where // wasmCloud host logs are sent to stderr as of https://github.com/wasmCloud/wasmcloud-otp/pull/418 .stderr(stderr) .stdout(stdout) + // NOTE: while normally we might want to kill_on_drop here, the tests that use this function + // manually manage the process that is spawned (see can_download_and_start_wasmcloud) .stdin(Stdio::null()) .envs(&env_vars); @@ -302,6 +304,7 @@ fn check_version(version: &str) -> Result<()> { } } } + #[cfg(test)] mod test { use super::{check_version, ensure_wasmcloud, wasmcloud_url}; @@ -309,10 +312,30 @@ mod test { ensure_nats_server, ensure_wasmcloud_for_os_arch_pair, find_wasmcloud_binary, is_bin_installed, start_nats_server, start_wasmcloud_host, NatsConfig, NATS_SERVER_BINARY, }; + + use anyhow::{bail, Context, Result}; use reqwest::StatusCode; use std::{collections::HashMap, env::temp_dir}; use tokio::fs::{create_dir_all, remove_dir_all}; + use tokio::net::TcpStream; + use tokio::time::Duration; + const WASMCLOUD_VERSION: &str = "v0.63.0"; + const RANDOM_PORT_RANGE_START: u16 = 5000; + const RANDOM_PORT_RANGE_END: u16 = 6000; + const LOCALHOST: &str = "127.0.0.1"; + + /// Returns an open port on the interface, searching within the range endpoints, inclusive + async fn find_open_port() -> Result { + for i in RANDOM_PORT_RANGE_START..=RANDOM_PORT_RANGE_END { + if let Ok(conn) = TcpStream::connect((LOCALHOST, i)).await { + drop(conn); + } else { + return Ok(i); + } + } + bail!("Failed to find open port for host") + } #[tokio::test] async fn can_request_supported_wasmcloud_urls() { @@ -417,7 +440,7 @@ mod test { .is_none()); // Install and start NATS server for this test - let nats_port = 10004; + let nats_port = find_open_port().await?; assert!(ensure_nats_server(NATS_SERVER_VERSION, &install_dir) .await .is_ok()); @@ -470,23 +493,52 @@ mod test { .await .expect("Unable to start wasmcloud host"); - // Give wasmCloud max 15 seconds to start up - for _ in 0..14 { - let log_contents = tokio::fs::read_to_string(&stderr_log_path).await?; - if log_contents.is_empty() { - println!("wasmCloud hasn't started up yet, waiting 1 second"); - tokio::time::sleep(std::time::Duration::from_millis(1000)).await; - } else { - // Give just a little bit of time for the startup logs to flow in, re-read logs - tokio::time::sleep(std::time::Duration::from_millis(5000)).await; - let log_contents = tokio::fs::read_to_string(&stderr_log_path).await?; - assert!(log_contents - .contains("connect to control interface NATS without authentication")); - assert!(log_contents.contains("connect to lattice rpc NATS without authentication")); - assert!(log_contents.contains("Started wasmCloud OTP Host Runtime")); - break; + // Wait at most 10 seconds for wasmcloud to start + println!("waiting for wasmcloud to start.."); + let startup_log_path = stderr_log_path.clone(); + tokio::time::timeout(Duration::from_secs(10), async move { + loop { + match tokio::fs::read_to_string(&startup_log_path).await { + Ok(file_contents) if !file_contents.is_empty() => break, + _ => { + println!("wasmCloud hasn't started up yet, waiting 1 second"); + tokio::time::sleep(Duration::from_secs(1)).await; + } + } } - } + }) + .await + .context("failed to start wasmcloud (log path is missing)")?; + + // Wait for up to 15 seconds for the logs to contain expected lines + println!("wasmCloud has started, waiting for expected startup logs..."); + let startup_log_path = stderr_log_path.clone(); + tokio::time::timeout(Duration::from_secs(15), async move { + loop { + match tokio::fs::read_to_string(&startup_log_path).await { + Ok(file_contents) => { + if [ + "connect to control interface NATS without authentication", + "connect to lattice rpc NATS without authentication", + "Started wasmCloud OTP Host Runtime", + ] + .into_iter() + .all(|l| file_contents.contains(l)) + { + // After wasmcloud says it's ready, it still requires some seconds to start up. + tokio::time::sleep(Duration::from_secs(3)).await; + break; + } + } + _ => { + println!("no host startup logs in output yet, waiting 1 second"); + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + } + }) + .await + .context("failed to start wasmcloud (logs did not contain expected content)")?; // Should fail because the port is already in use by another host let mut host_env = HashMap::new(); diff --git a/crates/wash-lib/tests/parser/files/minimal_rust_actor_core_module.toml b/crates/wash-lib/tests/parser/files/minimal_rust_actor_core_module.toml new file mode 100644 index 00000000..f391bfc4 --- /dev/null +++ b/crates/wash-lib/tests/parser/files/minimal_rust_actor_core_module.toml @@ -0,0 +1,8 @@ +language = "rust" +type = "actor" +name = "testactor" +version = "0.1.0" + +[actor] +claims = ["wasmcloud:httpserver"] +wasm_target = "wasm32-unknown-unknown" \ No newline at end of file diff --git a/crates/wash-lib/tests/parser/files/minimal_rust_actor_preview1.toml b/crates/wash-lib/tests/parser/files/minimal_rust_actor_preview1.toml new file mode 100644 index 00000000..6ae98edd --- /dev/null +++ b/crates/wash-lib/tests/parser/files/minimal_rust_actor_preview1.toml @@ -0,0 +1,8 @@ +language = "rust" +type = "actor" +name = "testactor" +version = "0.1.0" + +[actor] +claims = ["wasmcloud:httpserver"] +wasm_target = "wasm32-wasi-preview1" \ No newline at end of file diff --git a/crates/wash-lib/tests/parser/files/minimal_rust_actor_preview2.toml b/crates/wash-lib/tests/parser/files/minimal_rust_actor_preview2.toml new file mode 100644 index 00000000..db0adafa --- /dev/null +++ b/crates/wash-lib/tests/parser/files/minimal_rust_actor_preview2.toml @@ -0,0 +1,8 @@ +language = "rust" +type = "actor" +name = "testactor" +version = "0.1.0" + +[actor] +claims = ["wasmcloud:httpserver"] +wasm_target = "wasm32-wasi-preview2" \ No newline at end of file diff --git a/crates/wash-lib/tests/parser/main.rs b/crates/wash-lib/tests/parser/main.rs index e88f2092..e22fb2b5 100644 --- a/crates/wash-lib/tests/parser/main.rs +++ b/crates/wash-lib/tests/parser/main.rs @@ -4,6 +4,7 @@ use claims::{assert_err, assert_ok}; use semver::Version; use wash_lib::parser::{ get_config, ActorConfig, CommonConfig, LanguageConfig, RustConfig, TinyGoConfig, TypeConfig, + WasmTarget, }; #[test] @@ -32,7 +33,7 @@ fn rust_actor() { push_insecure: false, key_directory: PathBuf::from("./keys"), filename: Some("testactor.wasm".to_string()), - wasm_target: "wasm32-unknown-unknown".to_string(), + wasm_target: WasmTarget::CoreModule, call_alias: Some("testactor".to_string()) }) ); @@ -74,7 +75,7 @@ fn tinygo_actor() { push_insecure: false, key_directory: PathBuf::from("./keys"), filename: Some("testactor.wasm".to_string()), - wasm_target: "wasm32-unknown-unknown".to_string(), + wasm_target: WasmTarget::CoreModule, call_alias: Some("testactor".to_string()) }) ); @@ -256,7 +257,7 @@ fn minimal_rust_actor() { push_insecure: false, key_directory: PathBuf::from("./keys"), filename: None, - wasm_target: "wasm32-unknown-unknown".to_string(), + wasm_target: WasmTarget::CoreModule, call_alias: None }) ); @@ -301,7 +302,7 @@ fn cargo_toml_actor() { push_insecure: false, key_directory: PathBuf::from("./keys"), filename: None, - wasm_target: "wasm32-unknown-unknown".to_string(), + wasm_target: WasmTarget::CoreModule, call_alias: None }) ); @@ -318,3 +319,66 @@ fn cargo_toml_actor() { } ) } + +/// wasm_target=wasm32-wasi-preview2 is properly parsed +/// see: https://github.com/wasmCloud/wash/issues/640 +#[test] +fn minimal_rust_actor_preview2() { + let result = get_config( + Some(PathBuf::from( + "./tests/parser/files/minimal_rust_actor_preview2.toml", + )), + None, + ); + + let config = assert_ok!(result); + assert!(matches!( + config.project_type, + TypeConfig::Actor(ActorConfig { + wasm_target: WasmTarget::WasiPreview2, + .. + }) + )); +} + +/// wasm_target=wasm32-wasi-preview1 is properly parsed +/// see: https://github.com/wasmCloud/wash/issues/640 +#[test] +fn minimal_rust_actor_preview1() { + let result = get_config( + Some(PathBuf::from( + "./tests/parser/files/minimal_rust_actor_preview1.toml", + )), + None, + ); + + let config = assert_ok!(result); + assert!(matches!( + config.project_type, + TypeConfig::Actor(ActorConfig { + wasm_target: WasmTarget::WasiPreview1, + .. + }) + )); +} + +/// wasm_target=wasm32-unknown-unknown is properly parsed +/// see: https://github.com/wasmCloud/wash/issues/640 +#[test] +fn minimal_rust_actor_core_module() { + let result = get_config( + Some(PathBuf::from( + "./tests/parser/files/minimal_rust_actor_core_module.toml", + )), + None, + ); + + let config = assert_ok!(result); + assert!(matches!( + config.project_type, + TypeConfig::Actor(ActorConfig { + wasm_target: WasmTarget::CoreModule, + .. + }) + )); +} diff --git a/tests/common.rs b/tests/common.rs index d675536d..4441eb2e 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -194,19 +194,25 @@ impl TestWashInstance { }; // Wait until the host starts by checking the logs - let mut tries: i32 = 30; - let mut start_message_logs: String = String::new(); - loop { - start_message_logs = read_to_string(wasmcloud_log.to_string().trim_matches('"')) - .context("could not read log file output")?; - if (start_message_logs.contains("Started wasmCloud OTP Host Runtime")) { - break; + let logs_path = String::from(wasmcloud_log.to_string().trim_matches('"')); + tokio::time::timeout(Duration::from_secs(15), async move { + loop { + match tokio::fs::read_to_string(&logs_path).await { + Ok(file_contents) => { + if file_contents.contains("Started wasmCloud OTP Host Runtime") { + // After wasmcloud says it's ready, it still requires some seconds to start up. + tokio::time::sleep(Duration::from_secs(3)).await; + break; + } + } + _ => { + println!("no host startup logs in output yet, waiting 1 second"); + tokio::time::sleep(Duration::from_secs(1)).await; + } + } } - tries -= 1; - assert!(tries >= 0); - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - } - tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + }) + .await?; Ok(TestWashInstance { test_dir, @@ -412,7 +418,7 @@ pub(crate) async fn wait_for_no_hosts() -> Result<()> { wait_until_process_has_count( "beam.smp", |v| v == 0, - Duration::from_secs(10), + Duration::from_secs(15), Duration::from_millis(250), ) .await @@ -430,3 +436,15 @@ pub(crate) async fn wait_for_nats_to_start() -> Result<()> { ) .await } + +/// Wait for no nats to be running by checking for process names +#[allow(dead_code)] +pub(crate) async fn wait_for_no_nats() -> Result<()> { + wait_until_process_has_count( + "nats-server", + |v| v == 0, + Duration::from_secs(10), + Duration::from_millis(250), + ) + .await +} diff --git a/tests/integration_dev.rs b/tests/integration_dev.rs index 86da4bb8..385b72f7 100644 --- a/tests/integration_dev.rs +++ b/tests/integration_dev.rs @@ -8,7 +8,9 @@ use tokio::{process::Command, sync::RwLock, time::Duration}; mod common; -use crate::common::{init, start_nats, test_dir_with_subfolder, wait_for_no_hosts}; +use crate::common::{ + init, start_nats, test_dir_with_subfolder, wait_for_no_hosts, wait_for_no_nats, +}; #[tokio::test] #[serial] @@ -95,6 +97,12 @@ async fn integration_dev_hello_actor_serial() -> Result<()> { .await .context("wasmcloud instance failed to exit cleanly (processes still left over)")?; + // Kill the nats instance nats.kill().await.map_err(|e| anyhow!(e))?; + + wait_for_no_nats() + .await + .context("nats instance failed to exit cleanly (processes still left over")?; + Ok(()) } diff --git a/tests/integration_get.rs b/tests/integration_get.rs index 7cc39dfc..1c970217 100644 --- a/tests/integration_get.rs +++ b/tests/integration_get.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use serial_test::serial; use tokio::process::Command; use wash_lib::cli::output::{ @@ -73,7 +73,13 @@ async fn integration_get_host_inventory_serial() -> Result<()> { .await .context("failed to execute get inventory")?; - assert!(output.status.success(), "executed get inventory"); + if !output.status.success() { + bail!( + "failed to execute `wash get inventory`, stdout: {} \nstderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr), + ); + } let cmd_output: GetHostInventoryCommandOutput = serde_json::from_slice(&output.stdout)?; assert!(cmd_output.success, "command returned success");