From b479931b085799095af7db597206bd09deb83573 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 11:39:40 +0800 Subject: [PATCH 01/17] Use the "--registry" flag instead of running "wasmer login" --- tests/integration/cli/tests/run.rs | 51 ++++++------------------------ 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 00c106a9ac8..457ac705639 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -196,18 +196,11 @@ fn run_whoami_works() { return; } - Command::new(get_wasmer_path()) - .arg("login") - .arg("--registry") - .arg("wapm.dev") - .arg(ciuser_token) - .assert() - .success(); - let assert = Command::new(get_wasmer_path()) .arg("whoami") - .arg("--registry") - .arg("wapm.dev") + .arg("--registry=wapm.dev") + .arg("--token") + .arg(&ciuser_token) .assert() .success(); @@ -379,21 +372,12 @@ fn test_wasmer_run_works() { assert.stdout("hello\n"); - // set wapm.io as the current registry - let _ = Command::new(get_wasmer_path()) - .arg("login") - .arg("--registry") - .arg("wapm.io") - // will fail, but set wapm.io as the current registry regardless - .arg("öladkfjasöldfkjasdölfkj") - .assert() - .success(); - - // same test again, but this time without specifying the registry + // same test again, but this time without specifying the registry in the URL let assert = Command::new(get_wasmer_path()) .arg("run") .arg("python/python") .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg("--registry=wasmer.io") .arg("test.py") .assert() .success(); @@ -405,6 +389,7 @@ fn test_wasmer_run_works() { .arg("run") .arg("_/python") .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg("--registry=wasmer.io") .arg("test.py") .assert() .success(); @@ -442,19 +427,10 @@ fn run_wasi_works_non_existent() -> anyhow::Result<()> { #[ignore] #[test] fn run_test_caching_works_for_packages() { - // set wapm.io as the current registry - Command::new(get_wasmer_path()) - .arg("login") - .arg("--registry") - .arg("wapm.io") - // will fail, but set wapm.io as the current registry regardless - .arg("öladkfjasöldfkjasdölfkj") - .assert() - .success(); - let assert = Command::new(get_wasmer_path()) .arg("python/python") .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg("--registry=wasmer.io") .arg("test.py") .assert() .success(); @@ -466,6 +442,7 @@ fn run_test_caching_works_for_packages() { let assert = Command::new(get_wasmer_path()) .arg("python/python") .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg("--registry=wasmer.io") .arg("test.py") .assert() .success(); @@ -478,19 +455,10 @@ fn run_test_caching_works_for_packages() { #[test] fn run_test_caching_works_for_packages_with_versions() { - // set wapm.io as the current registry - Command::new(get_wasmer_path()) - .arg("login") - .arg("--registry") - .arg("wapm.io") - // will fail, but set wapm.io as the current registry regardless - .arg("öladkfjasöldfkjasdölfkj") - .assert() - .success(); - let assert = Command::new(get_wasmer_path()) .arg("python/python@0.1.0") .arg(format!("--mapdir=/app:{}", ASSET_PATH)) + .arg("--registry=wasmer.io") .arg("/app/test.py") .assert() .success(); @@ -500,6 +468,7 @@ fn run_test_caching_works_for_packages_with_versions() { let assert = Command::new(get_wasmer_path()) .arg("python/python@0.1.0") .arg(format!("--mapdir=/app:{}", ASSET_PATH)) + .arg("--registry=wasmer.io") .arg("/app/test.py") .env( "RUST_LOG", From d6f0e98cfddbda49e119299949f6b866ba3bcb64 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 11:50:13 +0800 Subject: [PATCH 02/17] Moved a create-exe test from the "run.rs" integration tests into "create_exe.rs" --- tests/integration/cli/tests/create_exe.rs | 79 ++++++++++++++++++++--- tests/integration/cli/tests/run.rs | 55 ---------------- 2 files changed, 69 insertions(+), 65 deletions(-) diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index e368d422d6b..e863c240bc4 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -1,24 +1,28 @@ //! Tests of the `wasmer create-exe` command. +use std::{ + fs, + io::prelude::*, + path::{Path, PathBuf}, + process::Command, +}; + use anyhow::{bail, Context}; -use std::fs; -use std::io::prelude::*; -use std::path::PathBuf; -use std::process::Command; +use assert_cmd::prelude::OutputAssertExt; use tempfile::TempDir; use wasmer_integration_tests_cli::*; -fn create_exe_wabt_path() -> String { - format!("{}/{}", C_ASSET_PATH, "wabt-1.0.37.wasmer") +fn create_exe_wabt_path() -> PathBuf { + Path::new(C_ASSET_PATH).join("wabt-1.0.37.wasmer") } #[allow(dead_code)] -fn create_exe_python_wasmer() -> String { - format!("{}/{}", C_ASSET_PATH, "python-0.1.0.wasmer") +fn create_exe_python_wasmer() -> PathBuf { + Path::new(C_ASSET_PATH).join("python-0.1.0.wasmer") } -fn create_exe_test_wasm_path() -> String { - format!("{}/{}", C_ASSET_PATH, "qjs.wasm") +fn create_exe_test_wasm_path() -> PathBuf { + Path::new(C_ASSET_PATH).join("qjs.wasm") } const JS_TEST_SRC_CODE: &[u8] = b"function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));\n"; @@ -684,3 +688,58 @@ fn create_exe_with_object_input(args: Vec) -> anyhow::Result<()> { fn create_exe_with_object_input_default() -> anyhow::Result<()> { create_exe_with_object_input(vec![]) } + +/// TODO: on linux-musl, the packaging of libwasmer.a doesn't work properly +/// Tracked in https://github.com/wasmerio/wasmer/issues/3271 +#[cfg_attr(any(target_env = "musl", target_os = "windows"), ignore)] +#[test] +fn test_wasmer_create_exe_pirita_works() { + // let temp_dir = Path::new("debug"); + // std::fs::create_dir_all(&temp_dir); + + use wasmer_integration_tests_cli::get_repo_root_path; + let temp_dir = tempfile::TempDir::new().unwrap(); + let temp_dir = temp_dir.path().to_path_buf(); + let python_wasmer_path = temp_dir.join("python.wasmer"); + std::fs::copy(create_exe_python_wasmer(), &python_wasmer_path).unwrap(); + let python_exe_output_path = temp_dir.join("python"); + + let native_target = target_lexicon::HOST; + let tmp_targz_path = get_repo_root_path().unwrap().join("link.tar.gz"); + + println!("compiling to target {native_target}"); + + let mut cmd = Command::new(get_wasmer_path()); + cmd.arg("create-exe"); + cmd.arg(&python_wasmer_path); + cmd.arg("--tarball"); + cmd.arg(&tmp_targz_path); + cmd.arg("--target"); + cmd.arg(format!("{native_target}")); + cmd.arg("-o"); + cmd.arg(&python_exe_output_path); + // change temp_dir to a local path and run this test again + // to output the compilation files into a debug folder + // + // cmd.arg("--debug-dir"); + // cmd.arg(&temp_dir); + + cmd.assert().success(); + + println!("compilation ok!"); + + if !python_exe_output_path.exists() { + panic!( + "python_exe_output_path {} does not exist", + python_exe_output_path.display() + ); + } + + println!("invoking command..."); + + let mut command = Command::new(&python_exe_output_path); + command.arg("-c"); + command.arg("print(\"hello\")"); + + command.assert().success().stdout("hello\n"); +} diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 457ac705639..982cf115db2 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -222,61 +222,6 @@ fn run_wasi_works() { assert.stdout("27\n"); } -/// TODO: on linux-musl, the packaging of libwasmer.a doesn't work properly -/// Tracked in https://github.com/wasmerio/wasmer/issues/3271 -#[cfg_attr(any(target_env = "musl", target_os = "windows"), ignore)] -#[test] -fn test_wasmer_create_exe_pirita_works() { - // let temp_dir = Path::new("debug"); - // std::fs::create_dir_all(&temp_dir); - - use wasmer_integration_tests_cli::get_repo_root_path; - let temp_dir = tempfile::TempDir::new().unwrap(); - let temp_dir = temp_dir.path().to_path_buf(); - let python_wasmer_path = temp_dir.join("python.wasmer"); - std::fs::copy(wasi_test_python_path(), &python_wasmer_path).unwrap(); - let python_exe_output_path = temp_dir.join("python"); - - let native_target = target_lexicon::HOST; - let tmp_targz_path = get_repo_root_path().unwrap().join("link.tar.gz"); - - println!("compiling to target {native_target}"); - - let mut cmd = Command::new(get_wasmer_path()); - cmd.arg("create-exe"); - cmd.arg(&python_wasmer_path); - cmd.arg("--tarball"); - cmd.arg(&tmp_targz_path); - cmd.arg("--target"); - cmd.arg(format!("{native_target}")); - cmd.arg("-o"); - cmd.arg(&python_exe_output_path); - // change temp_dir to a local path and run this test again - // to output the compilation files into a debug folder - // - // cmd.arg("--debug-dir"); - // cmd.arg(&temp_dir); - - cmd.assert().success(); - - println!("compilation ok!"); - - if !python_exe_output_path.exists() { - panic!( - "python_exe_output_path {} does not exist", - python_exe_output_path.display() - ); - } - - println!("invoking command..."); - - let mut command = Command::new(&python_exe_output_path); - command.arg("-c"); - command.arg("print(\"hello\")"); - - command.assert().success().stdout("hello\n"); -} - // FIXME: Re-enable. See https://github.com/wasmerio/wasmer/issues/3717 #[test] #[ignore] From 0eec9aeda454c5915fab2c95ece83b2d3c4bf8be Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 11:50:43 +0800 Subject: [PATCH 03/17] Make sure the caching test doesn't use the global $WASMER_DIR --- lib/wasix/src/runtime/resolver/wapm_source.rs | 1 + tests/integration/cli/tests/run.rs | 37 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/wasix/src/runtime/resolver/wapm_source.rs b/lib/wasix/src/runtime/resolver/wapm_source.rs index 5eda690aa43..1a4437f39ef 100644 --- a/lib/wasix/src/runtime/resolver/wapm_source.rs +++ b/lib/wasix/src/runtime/resolver/wapm_source.rs @@ -51,6 +51,7 @@ impl WapmSource { if let Some(cache) = &self.cache { match cache.lookup_cached_query(package_name) { Ok(Some(cached)) => { + tracing::debug!("Cache hit!"); return Ok(cached); } Ok(None) => {} diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 982cf115db2..83a15be15b3 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -1,8 +1,10 @@ //! Basic tests for the `run` subcommand +use std::path::{Path, PathBuf}; + use assert_cmd::Command; use predicates::str::contains; -use std::path::{Path, PathBuf}; +use tempfile::TempDir; use wasmer_integration_tests_cli::{get_wasmer_path, ASSET_PATH, C_ASSET_PATH}; fn wasi_test_python_path() -> PathBuf { @@ -265,7 +267,7 @@ fn test_wasmer_run_works_with_dir() { std::fs::copy(wasi_test_wasm_path(), &qjs_path).unwrap(); std::fs::copy( - format!("{}/{}", C_ASSET_PATH, "qjs-wasmer.toml"), + Path::new(C_ASSET_PATH).join("qjs-wasmer.toml"), temp_dir.path().join("wasmer.toml"), ) .unwrap(); @@ -372,30 +374,39 @@ fn run_wasi_works_non_existent() -> anyhow::Result<()> { #[ignore] #[test] fn run_test_caching_works_for_packages() { + // we're testing the cache, so we don't want to reuse the current user's + // $WASMER_DIR + let wasmer_dir = TempDir::new().unwrap(); + let rust_log = [ + "wasmer_wasix::runtime::resolver::wapm_source=debug", + "wasmer_wasix::runtime::package_loader::builtin_loader=debug", + ] + .join(","); + let assert = Command::new(get_wasmer_path()) .arg("python/python") .arg(format!("--mapdir=.:{}", ASSET_PATH)) .arg("--registry=wasmer.io") .arg("test.py") - .assert() - .success(); - - assert.stdout("hello\n"); + .env("WASMER_DIR", wasmer_dir.path()) + .env("RUST_LOG", &rust_log) + .assert(); - let time = std::time::Instant::now(); + assert + .success() + .stderr("Downloading a webc") + .stderr("Querying the GraphQL API"); let assert = Command::new(get_wasmer_path()) .arg("python/python") .arg(format!("--mapdir=.:{}", ASSET_PATH)) .arg("--registry=wasmer.io") .arg("test.py") - .assert() - .success(); - - assert.stdout("hello\n"); + .env("WASMER_DIR", wasmer_dir.path()) + .env("RUST_LOG", &rust_log) + .assert(); - // package should be cached - assert!(std::time::Instant::now() - time < std::time::Duration::from_secs(1)); + assert.success().stderr("asdf"); } #[test] From 99a7ed9ccea736e6c72cc5f54b388873907093fd Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 11:57:19 +0800 Subject: [PATCH 04/17] Use &Path for asset paths instead of &str --- tests/integration/cli/src/assets.rs | 137 +++++++++++--------- tests/integration/cli/tests/create_exe.rs | 13 +- tests/integration/cli/tests/gen_c_header.rs | 15 +-- tests/integration/cli/tests/init.rs | 99 ++++++-------- tests/integration/cli/tests/publish.rs | 8 +- tests/integration/cli/tests/run.rs | 32 ++--- tests/integration/cli/tests/run_unstable.rs | 16 +-- 7 files changed, 151 insertions(+), 169 deletions(-) diff --git a/tests/integration/cli/src/assets.rs b/tests/integration/cli/src/assets.rs index 946f851772a..c3882c0c8ed 100644 --- a/tests/integration/cli/src/assets.rs +++ b/tests/integration/cli/src/assets.rs @@ -1,51 +1,70 @@ -use std::env; use std::path::PathBuf; +use std::{env, path::Path}; -pub const C_ASSET_PATH: &str = concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../../lib/c-api/examples/assets/" -); -pub const ASSET_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../tests/examples/"); +pub fn c_asset_path() -> &'static Path { + Path::new(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../../lib/c-api/examples/assets/" + )) +} -pub const WASMER_INCLUDE_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../lib/c-api/"); +pub fn asset_path() -> &'static Path { + Path::new(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../../tests/examples/" + )) +} -#[cfg(feature = "debug")] -pub const WASMER_TARGET_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/debug/"); -#[cfg(feature = "debug")] -pub const WASMER_TARGET_PATH_2: &str = concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../../target/", - env!("CARGO_BUILD_TARGET"), - "/debug/" -); +pub fn wasmer_include_path() -> &'static Path { + Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../../../lib/c-api/")) +} -/* env var TARGET is set by tests/integration/cli/build.rs on compile-time */ +pub fn wasmer_target_path() -> &'static Path { + let path = if cfg!(feature = "debug") { + concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/debug/") + } else { + concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/release/") + }; + Path::new(path) +} -#[cfg(not(feature = "debug"))] -pub const WASMER_TARGET_PATH: &str = - concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/release/"); -#[cfg(not(feature = "debug"))] -pub const WASMER_TARGET_PATH_2: &str = concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../../target/", - env!("CARGO_BUILD_TARGET"), - "/release/" -); +pub fn wasmer_target_path_2() -> &'static Path { + let path = if cfg!(feature = "debug") { + concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../../target/", + env!("CARGO_BUILD_TARGET"), + "/debug/" + ) + } else { + concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../../target/", + env!("CARGO_BUILD_TARGET"), + "/release/" + ) + }; + Path::new(path) +} -#[cfg(not(windows))] -pub const LIBWASMER_FILENAME: &str = "libwasmer.a"; +/* env var TARGET is set by tests/integration/cli/build.rs on compile-time */ -#[cfg(windows)] -pub const LIBWASMER_FILENAME: &str = "wasmer.lib"; +pub const LIBWASMER_FILENAME: &str = { + if cfg!(windows) { + "wasmer.lib" + } else { + "libwasmer.a" + } +}; /// Get the path to the `libwasmer.a` static library. pub fn get_libwasmer_path() -> PathBuf { - let mut ret = PathBuf::from( - env::var("WASMER_TEST_LIBWASMER_PATH") - .unwrap_or_else(|_| format!("{}{}", WASMER_TARGET_PATH, LIBWASMER_FILENAME)), - ); + let mut ret = env::var("WASMER_TEST_LIBWASMER_PATH") + .map(PathBuf::from) + .unwrap_or_else(|_| wasmer_target_path().join(LIBWASMER_FILENAME)); + if !ret.exists() { - ret = PathBuf::from(format!("{}{}", WASMER_TARGET_PATH_2, LIBWASMER_FILENAME)); + ret = wasmer_target_path_2().join(LIBWASMER_FILENAME); } if !ret.exists() { panic!("Could not find libwasmer path! {:?}", ret); @@ -55,23 +74,22 @@ pub fn get_libwasmer_path() -> PathBuf { /// Get the path to the `wasmer` executable to be used in this test. pub fn get_wasmer_path() -> PathBuf { - let mut ret = PathBuf::from( - env::var("WASMER_TEST_WASMER_PATH") - .unwrap_or_else(|_| format!("{}wasmer", WASMER_TARGET_PATH)), - ); + let mut ret = env::var("WASMER_TEST_WASMER_PATH") + .map(PathBuf::from) + .unwrap_or_else(|_| wasmer_target_path().join("wasmer")); + if !ret.exists() { - ret = PathBuf::from(format!("{}wasmer", WASMER_TARGET_PATH_2)); + ret = wasmer_target_path_2().join("wasmer"); } if !ret.exists() { ret = match get_repo_root_path() { Some(s) => { - #[cfg(target_os = "windows")] - { - s.join("target").join("release").join("wasmer.exe") - } - #[cfg(not(target_os = "windows"))] - { - s.join("target").join("release").join("wasmer") + let release_dir = s.join("target").join("release"); + + if cfg!(windows) { + release_dir.join("wasmer.exe") + } else { + release_dir.join("wasmer") } } None => { @@ -83,20 +101,15 @@ pub fn get_wasmer_path() -> PathBuf { if !ret.exists() { ret = match get_repo_root_path() { Some(s) => { - #[cfg(target_os = "windows")] - { - s.join("target") - .join(target_lexicon::HOST.to_string()) - .join("release") - .join("wasmer.exe") - } - #[cfg(not(target_os = "windows"))] - { - s.join("target") - .join(target_lexicon::HOST.to_string()) - .join("release") - .join("wasmer") - } + let executable = if cfg!(windows) { + "wasmer.exe" + } else { + "wasmer" + }; + s.join("target") + .join(target_lexicon::HOST.to_string()) + .join("release") + .join(executable) } None => { panic!("Could not find wasmer executable path! {:?}", ret); diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index e863c240bc4..21a80d62f20 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -1,11 +1,6 @@ //! Tests of the `wasmer create-exe` command. -use std::{ - fs, - io::prelude::*, - path::{Path, PathBuf}, - process::Command, -}; +use std::{fs, io::prelude::*, path::PathBuf, process::Command}; use anyhow::{bail, Context}; use assert_cmd::prelude::OutputAssertExt; @@ -13,16 +8,16 @@ use tempfile::TempDir; use wasmer_integration_tests_cli::*; fn create_exe_wabt_path() -> PathBuf { - Path::new(C_ASSET_PATH).join("wabt-1.0.37.wasmer") + c_asset_path().join("wabt-1.0.37.wasmer") } #[allow(dead_code)] fn create_exe_python_wasmer() -> PathBuf { - Path::new(C_ASSET_PATH).join("python-0.1.0.wasmer") + c_asset_path().join("python-0.1.0.wasmer") } fn create_exe_test_wasm_path() -> PathBuf { - Path::new(C_ASSET_PATH).join("qjs.wasm") + c_asset_path().join("qjs.wasm") } const JS_TEST_SRC_CODE: &[u8] = b"function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));\n"; diff --git a/tests/integration/cli/tests/gen_c_header.rs b/tests/integration/cli/tests/gen_c_header.rs index af56cac610a..3cb1e88532c 100644 --- a/tests/integration/cli/tests/gen_c_header.rs +++ b/tests/integration/cli/tests/gen_c_header.rs @@ -1,14 +1,13 @@ -use std::path::PathBuf; -use std::process::Command; -use wasmer_integration_tests_cli::get_wasmer_path; -use wasmer_integration_tests_cli::C_ASSET_PATH; +use std::{path::PathBuf, process::Command}; -fn create_exe_wabt_path() -> String { - format!("{}/{}", C_ASSET_PATH, "wabt-1.0.37.wasmer") +use wasmer_integration_tests_cli::{c_asset_path, get_wasmer_path}; + +fn create_exe_wabt_path() -> PathBuf { + c_asset_path().join("wabt-1.0.37.wasmer") } -fn create_exe_test_wasm_path() -> String { - format!("{}/{}", C_ASSET_PATH, "qjs.wasm") +fn create_exe_test_wasm_path() -> PathBuf { + c_asset_path().join("qjs.wasm") } #[test] diff --git a/tests/integration/cli/tests/init.rs b/tests/integration/cli/tests/init.rs index 8b2029c254c..3413f5b998d 100644 --- a/tests/integration/cli/tests/init.rs +++ b/tests/integration/cli/tests/init.rs @@ -1,24 +1,18 @@ -use anyhow::bail; +#[macro_use] +extern crate pretty_assertions; -use std::process::{Command, Stdio}; -use wasmer_integration_tests_cli::get_wasmer_path; +use assert_cmd::prelude::OutputAssertExt; +use tempfile::TempDir; -macro_rules! check_output { - ($output:expr) => { - let stdout_output = std::str::from_utf8(&$output.stdout).unwrap(); - let stderr_output = std::str::from_utf8(&$output.stdout).unwrap(); - if !$output.status.success() { - bail!("wasmer init failed with: stdout: {stdout_output}\n\nstderr: {stderr_output}"); - } - }; -} +use std::process::Command; +use wasmer_integration_tests_cli::get_wasmer_path; // Test that wasmer init without arguments works #[test] fn wasmer_init_works_1() -> anyhow::Result<()> { + let wasmer_dir = TempDir::new()?; let tempdir = tempfile::tempdir()?; - let path = tempdir.path(); - let path = path.join("testfirstproject"); + let path = tempdir.path().join("testfirstproject"); std::fs::create_dir_all(&path)?; if std::env::var("GITHUB_TOKEN").is_err() { @@ -33,36 +27,29 @@ fn wasmer_init_works_1() -> anyhow::Result<()> { if token.is_empty() { return Ok(()); } - let output = Command::new(get_wasmer_path()) + Command::new(get_wasmer_path()) .arg("login") - .arg("--registry") - .arg("wapm.dev") + .arg("--registry=wapm.dev") .arg(token) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .stdin(Stdio::null()) - .output()?; - check_output!(output); + .env("WASMER_DIR", wasmer_dir.path()) + .assert() + .success(); } println!("wasmer login ok!"); - let output = Command::new(get_wasmer_path()) + Command::new(get_wasmer_path()) .arg("init") .current_dir(&path) - .output()?; - check_output!(output); - - let read = std::fs::read_to_string(path.join("wasmer.toml")) - .unwrap() - .lines() - .collect::>() - .join("\n"); - let target = include_str!("./fixtures/init1.toml") - .lines() - .collect::>() - .join("\n"); - pretty_assertions::assert_eq!(read.trim(), target.trim()); + .env("WASMER_DIR", wasmer_dir.path()) + .assert() + .success(); + + assert_eq!( + std::fs::read_to_string(path.join("wasmer.toml")).unwrap(), + include_str!("./fixtures/init1.toml"), + ); + Ok(()) } @@ -91,45 +78,33 @@ fn wasmer_init_works_2() -> anyhow::Result<()> { if token.is_empty() { return Ok(()); } - let mut cmd = Command::new(get_wasmer_path()); - cmd.arg("login"); - cmd.arg("--registry"); - cmd.arg("wapm.dev"); - cmd.arg(token); - cmd.stdout(Stdio::inherit()); - cmd.stderr(Stdio::inherit()); - cmd.stdin(Stdio::null()); - let output = cmd.output()?; - check_output!(output); + Command::new(get_wasmer_path()) + .arg("login") + .arg("--registry=wapm.dev") + .arg(token) + .assert() + .success(); } println!("wasmer login ok!"); - let output = Command::new(get_wasmer_path()) + Command::new(get_wasmer_path()) .arg("init") - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) .current_dir(&path) - .output()?; - check_output!(output); + .assert() + .success(); - pretty_assertions::assert_eq!( + assert_eq!( std::fs::read_to_string(path.join("Cargo.toml")).unwrap(), include_str!("./fixtures/init2.toml") ); println!("ok 1"); - let read = std::fs::read_to_string(path.join("wasmer.toml")) - .unwrap() - .lines() - .collect::>() - .join("\n"); - let target = include_str!("./fixtures/init4.toml") - .lines() - .collect::>() - .join("\n"); - pretty_assertions::assert_eq!(read.trim(), target.trim()); + assert_eq!( + std::fs::read_to_string(path.join("wasmer.toml")).unwrap(), + include_str!("./fixtures/init4.toml") + ); Ok(()) } diff --git a/tests/integration/cli/tests/publish.rs b/tests/integration/cli/tests/publish.rs index 3b0d09b2d40..0281c1e9fae 100644 --- a/tests/integration/cli/tests/publish.rs +++ b/tests/integration/cli/tests/publish.rs @@ -1,8 +1,8 @@ -use std::process::Stdio; -use wasmer_integration_tests_cli::{get_wasmer_path, C_ASSET_PATH}; +use std::{path::PathBuf, process::Stdio}; +use wasmer_integration_tests_cli::{c_asset_path, get_wasmer_path}; -fn create_exe_test_wasm_path() -> String { - format!("{}/{}", C_ASSET_PATH, "qjs.wasm") +fn create_exe_test_wasm_path() -> PathBuf { + c_asset_path().join("qjs.wasm") } #[test] diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 83a15be15b3..d53b38f6617 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -5,22 +5,22 @@ use std::path::{Path, PathBuf}; use assert_cmd::Command; use predicates::str::contains; use tempfile::TempDir; -use wasmer_integration_tests_cli::{get_wasmer_path, ASSET_PATH, C_ASSET_PATH}; +use wasmer_integration_tests_cli::{asset_path, c_asset_path, get_wasmer_path}; fn wasi_test_python_path() -> PathBuf { - Path::new(C_ASSET_PATH).join("python-0.1.0.wasmer") + c_asset_path().join("python-0.1.0.wasmer") } fn wasi_test_wasm_path() -> PathBuf { - Path::new(C_ASSET_PATH).join("qjs.wasm") + c_asset_path().join("qjs.wasm") } fn test_no_imports_wat_path() -> PathBuf { - Path::new(ASSET_PATH).join("fib.wat") + asset_path().join("fib.wat") } fn test_no_start_wat_path() -> PathBuf { - Path::new(ASSET_PATH).join("no_start.wat") + asset_path().join("no_start.wat") } /// Ignored on Windows because running vendored packages does not work @@ -267,7 +267,7 @@ fn test_wasmer_run_works_with_dir() { std::fs::copy(wasi_test_wasm_path(), &qjs_path).unwrap(); std::fs::copy( - Path::new(C_ASSET_PATH).join("qjs-wasmer.toml"), + c_asset_path().join("qjs-wasmer.toml"), temp_dir.path().join("wasmer.toml"), ) .unwrap(); @@ -301,7 +301,7 @@ fn test_wasmer_run_works_with_dir() { fn test_wasmer_run_works() { let assert = Command::new(get_wasmer_path()) .arg("https://wapm.io/python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("test.py") .assert() .success(); @@ -312,7 +312,7 @@ fn test_wasmer_run_works() { let assert = Command::new(get_wasmer_path()) .arg("run") .arg("https://wapm.io/python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("test.py") .assert() .success(); @@ -323,7 +323,7 @@ fn test_wasmer_run_works() { let assert = Command::new(get_wasmer_path()) .arg("run") .arg("python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("test.py") .assert() @@ -335,7 +335,7 @@ fn test_wasmer_run_works() { let assert = Command::new(get_wasmer_path()) .arg("run") .arg("_/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("test.py") .assert() @@ -385,7 +385,7 @@ fn run_test_caching_works_for_packages() { let assert = Command::new(get_wasmer_path()) .arg("python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("test.py") .env("WASMER_DIR", wasmer_dir.path()) @@ -399,7 +399,7 @@ fn run_test_caching_works_for_packages() { let assert = Command::new(get_wasmer_path()) .arg("python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("test.py") .env("WASMER_DIR", wasmer_dir.path()) @@ -413,7 +413,7 @@ fn run_test_caching_works_for_packages() { fn run_test_caching_works_for_packages_with_versions() { let assert = Command::new(get_wasmer_path()) .arg("python/python@0.1.0") - .arg(format!("--mapdir=/app:{}", ASSET_PATH)) + .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("/app/test.py") .assert() @@ -423,7 +423,7 @@ fn run_test_caching_works_for_packages_with_versions() { let assert = Command::new(get_wasmer_path()) .arg("python/python@0.1.0") - .arg(format!("--mapdir=/app:{}", ASSET_PATH)) + .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("/app/test.py") .env( @@ -448,7 +448,7 @@ fn run_test_caching_works_for_packages_with_versions() { fn run_test_caching_works_for_urls() { let assert = Command::new(get_wasmer_path()) .arg("https://wapm.io/python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("test.py") .assert() .success(); @@ -459,7 +459,7 @@ fn run_test_caching_works_for_urls() { let assert = Command::new(get_wasmer_path()) .arg("https://wapm.io/python/python") - .arg(format!("--mapdir=.:{}", ASSET_PATH)) + .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("test.py") .assert() .success(); diff --git a/tests/integration/cli/tests/run_unstable.rs b/tests/integration/cli/tests/run_unstable.rs index 4c418c234d9..5520287b123 100644 --- a/tests/integration/cli/tests/run_unstable.rs +++ b/tests/integration/cli/tests/run_unstable.rs @@ -470,11 +470,11 @@ mod remote_webc { mod fixtures { use std::path::{Path, PathBuf}; - use wasmer_integration_tests_cli::{ASSET_PATH, C_ASSET_PATH}; + use wasmer_integration_tests_cli::{asset_path, c_asset_path}; /// A WEBC file containing the Python interpreter, compiled to WASI. pub fn python() -> PathBuf { - Path::new(C_ASSET_PATH).join("python-0.1.0.wasmer") + c_asset_path().join("python-0.1.0.wasmer") } pub fn coreutils() -> PathBuf { @@ -494,17 +494,17 @@ mod fixtures { /// A WEBC file containing `wat2wasm`, `wasm-validate`, and other helpful /// WebAssembly-related commands. pub fn wabt() -> PathBuf { - Path::new(C_ASSET_PATH).join("wabt-1.0.37.wasmer") + c_asset_path().join("wabt-1.0.37.wasmer") } /// A WEBC file containing the WCGI static server. pub fn static_server() -> PathBuf { - Path::new(C_ASSET_PATH).join("staticserver.webc") + c_asset_path().join("staticserver.webc") } /// The QuickJS interpreter, compiled to a WASI module. pub fn qjs() -> PathBuf { - Path::new(C_ASSET_PATH).join("qjs.wasm") + c_asset_path().join("qjs.wasm") } pub fn hello() -> PathBuf { @@ -516,16 +516,16 @@ mod fixtures { /// The `wasmer.toml` file for QuickJS. pub fn qjs_wasmer_toml() -> PathBuf { - Path::new(C_ASSET_PATH).join("qjs-wasmer.toml") + c_asset_path().join("qjs-wasmer.toml") } /// An executable which calculates fib(40) and exits with no output. pub fn fib() -> PathBuf { - Path::new(ASSET_PATH).join("fib.wat") + asset_path().join("fib.wat") } pub fn wat_no_start() -> PathBuf { - Path::new(ASSET_PATH).join("no_start.wat") + asset_path().join("no_start.wat") } } From aea06c30e3eae5c8bcb37698be69228996bc3258 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 11:59:12 +0800 Subject: [PATCH 05/17] Use get_wasmer_path() for run-unstable tests instead of going through "cargo run" --- tests/integration/cli/tests/run_unstable.rs | 80 +++++++++------------ 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/tests/integration/cli/tests/run_unstable.rs b/tests/integration/cli/tests/run_unstable.rs index 5520287b123..2b709d7a69a 100644 --- a/tests/integration/cli/tests/run_unstable.rs +++ b/tests/integration/cli/tests/run_unstable.rs @@ -14,34 +14,24 @@ use wasmer_integration_tests_cli::get_wasmer_path; const HTTP_GET_TIMEOUT: Duration = Duration::from_secs(5); -#[cfg(feature = "debug")] -static RUST_LOG: Lazy = Lazy::new(|| ["trace"].join(",")); - -#[cfg(not(feature = "debug"))] static RUST_LOG: Lazy = Lazy::new(|| { - [ - "info", - "wasmer_wasix::resolve=debug", - "wasmer_wasix::runners=debug", - "wasmer_wasix=debug", - "virtual_fs::trace_fs=trace", - ] - .join(",") + if cfg!(feature = "debug") { + String::from("trace") + } else { + [ + "info", + "wasmer_wasix::resolve=debug", + "wasmer_wasix::runners=debug", + "wasmer_wasix=debug", + "virtual_fs::trace_fs=trace", + ] + .join(",") + } }); -fn wasmer_run_unstable(inherit_stderr: bool) -> std::process::Command { - let mut cmd = std::process::Command::new("cargo"); - cmd.arg("run") - .arg("--quiet") - .arg("--package=wasmer-cli") - .arg("--features=singlepass,cranelift,compiler") - .arg("--color=never") - .arg("--") - .arg("run"); - cmd.env("RUST_LOG", &*RUST_LOG); - if inherit_stderr { - cmd.stderr(Stdio::inherit()); - } +fn wasmer_run_unstable() -> std::process::Command { + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("run").env("RUST_LOG", &*RUST_LOG); cmd } @@ -54,7 +44,7 @@ mod webc_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn wasi_runner() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::qjs()) .arg("--") .arg("--eval") @@ -70,7 +60,7 @@ mod webc_on_disk { let temp = TempDir::new_in(env!("CARGO_TARGET_TMPDIR")).unwrap(); std::fs::write(temp.path().join("main.py"), "print('Hello, World!')").unwrap(); - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::python()) .arg("--mapdir=/app:.") .arg("--") @@ -90,7 +80,7 @@ mod webc_on_disk { let temp = TempDir::new().unwrap(); std::fs::write(temp.path().join("index.js"), "console.log('Hello, World!')").unwrap(); - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::qjs()) .arg(format!("--mapdir=/app:{}", temp.path().display())) .arg("--") @@ -109,7 +99,7 @@ mod webc_on_disk { let temp = TempDir::new().unwrap(); std::fs::write(temp.path().join("main.py"), "print('Hello, World!')").unwrap(); - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::python()) .arg(format!("--mapdir=/app:{}", temp.path().display())) .arg("--") @@ -126,7 +116,7 @@ mod webc_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn wasi_runner_with_dependencies() { - let mut cmd = wasmer_run_unstable(false); + let mut cmd = wasmer_run_unstable(); let port = random_port(); cmd.arg(fixtures::hello()) .arg(format!("--env=SERVER_PORT={port}")) @@ -155,7 +145,7 @@ mod webc_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn webc_files_with_multiple_commands_require_an_entrypoint_flag() { - let assert = wasmer_run_unstable(false).arg(fixtures::wabt()).assert(); + let assert = wasmer_run_unstable().arg(fixtures::wabt()).assert(); let msg = r#"Unable to determine the WEBC file's entrypoint. Please choose one of ["wasm-interp", "wasm-strip", "wasm-validate", "wasm2wat", "wast2json", "wat2wasm"]"#; assert.failure().stderr(contains(msg)); @@ -167,7 +157,7 @@ mod webc_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn wasi_runner_with_env_vars() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::python()) .arg("--env=SOME_VAR=Hello, World!") .arg("--") @@ -187,7 +177,7 @@ mod webc_on_disk { fn wcgi_runner() { // Start the WCGI server in the background let port = random_port(); - let mut cmd = wasmer_run_unstable(false); + let mut cmd = wasmer_run_unstable(); cmd.arg(format!("--addr=127.0.0.1:{port}")) .arg(fixtures::static_server()); @@ -223,7 +213,7 @@ mod webc_on_disk { std::fs::write(temp.path().join("file.txt"), "Hello, World!").unwrap(); // Start the WCGI server in the background let port = random_port(); - let mut cmd = wasmer_run_unstable(false); + let mut cmd = wasmer_run_unstable(); cmd.arg(format!("--addr=127.0.0.1:{port}")) .arg(format!("--mapdir=/path/to:{}", temp.path().display())) .arg(fixtures::static_server()); @@ -255,7 +245,7 @@ mod webc_on_disk { let temp = TempDir::new().unwrap(); std::fs::write(temp.path().join("message.txt"), b"Hello, World!").unwrap(); - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::coreutils()) .arg(format!("--mapdir=./some-dir/:{}", temp.path().display())) .arg("--command-name=cat") @@ -276,7 +266,7 @@ mod webc_on_disk { ignore = "FIXME(Michael-F-Bryan): Temporarily broken on Windows - https://github.com/wasmerio/wasmer/issues/3929" )] fn merged_filesystem_contains_all_files() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::bash()) .arg("--entrypoint=bash") .arg("--use") @@ -307,7 +297,7 @@ mod wasm_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn wasi_executable() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(fixtures::qjs()) .arg("--") .arg("--eval") @@ -323,7 +313,7 @@ mod wasm_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn no_abi() { - let assert = wasmer_run_unstable(true).arg(fixtures::fib()).assert(); + let assert = wasmer_run_unstable().arg(fixtures::fib()).assert(); assert.success(); } @@ -334,9 +324,7 @@ mod wasm_on_disk { ignore = "wasmer run-unstable segfaults on musl" )] fn error_if_no_start_function_found() { - let assert = wasmer_run_unstable(false) - .arg(fixtures::wat_no_start()) - .assert(); + let assert = wasmer_run_unstable().arg(fixtures::wat_no_start()).assert(); assert .failure() @@ -363,7 +351,7 @@ mod wasm_on_disk { assert!(dest.exists()); // Now we can try to run the compiled artifact - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(&dest) .arg("--") .arg("--eval") @@ -387,7 +375,7 @@ mod local_directory { std::fs::copy(fixtures::qjs(), temp.path().join("qjs.wasm")).unwrap(); std::fs::copy(fixtures::qjs_wasmer_toml(), temp.path().join("wasmer.toml")).unwrap(); - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg(temp.path()) .arg("--") .arg("--eval") @@ -407,7 +395,7 @@ mod remote_webc { ignore = "wasmer run-unstable segfaults on musl" )] fn quickjs_as_package_name() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg("saghul/quickjs") .arg("--entrypoint=quickjs") .arg("--registry=wapm.io") @@ -425,7 +413,7 @@ mod remote_webc { ignore = "wasmer run-unstable segfaults on musl" )] fn quickjs_as_url() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg("https://wapm.io/saghul/quickjs") .arg("--entrypoint=quickjs") .arg("--") @@ -446,7 +434,7 @@ mod remote_webc { ignore = "TODO(Michael-F-Bryan): Figure out why WasiFs::get_inode_at_path_inner() returns Errno::notcapable on Windows" )] fn bash_using_coreutils() { - let assert = wasmer_run_unstable(true) + let assert = wasmer_run_unstable() .arg("sharrattj/bash") .arg("--entrypoint=bash") .arg("--use=sharrattj/coreutils") From 2aec98539d7bfa8e42730ad1c9a69b9687770ab2 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 12:29:16 +0800 Subject: [PATCH 06/17] Merged run-unstable tests into "run.rs" --- tests/integration/cli/tests/run.rs | 690 +++++++++++++++++++- tests/integration/cli/tests/run_unstable.rs | 668 ------------------- 2 files changed, 683 insertions(+), 675 deletions(-) delete mode 100644 tests/integration/cli/tests/run_unstable.rs diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index d53b38f6617..8234abfbfec 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -1,12 +1,37 @@ //! Basic tests for the `run` subcommand -use std::path::{Path, PathBuf}; - -use assert_cmd::Command; +use std::{ + io::{ErrorKind, Read}, + path::{Path, PathBuf}, + process::{Child, Command, Stdio}, + time::{Duration, Instant}, +}; + +use assert_cmd::{assert::Assert, prelude::OutputAssertExt}; +use once_cell::sync::Lazy; use predicates::str::contains; +use rand::Rng; +use reqwest::{blocking::Client, IntoUrl}; use tempfile::TempDir; use wasmer_integration_tests_cli::{asset_path, c_asset_path, get_wasmer_path}; +const HTTP_GET_TIMEOUT: Duration = Duration::from_secs(5); + +static RUST_LOG: Lazy = Lazy::new(|| { + if cfg!(feature = "debug") { + "trace".to_string() + } else { + [ + "info", + "wasmer_wasix::resolve=debug", + "wasmer_wasix::runners=debug", + "wasmer_wasix=debug", + "virtual_fs::trace_fs=trace", + ] + .join(",") + } +}); + fn wasi_test_python_path() -> PathBuf { c_asset_path().join("python-0.1.0.wasmer") } @@ -29,8 +54,8 @@ fn test_no_start_wat_path() -> PathBuf { /// The syntax for vendored package atoms has to be reworked for this to be fixed, see /// https://github.com/wasmerio/wasmer/issues/3535 // FIXME: Re-enable. See https://github.com/wasmerio/wasmer/issues/3717 -#[ignore] #[test] +#[ignore] fn test_run_customlambda() { let assert = Command::new(get_wasmer_path()) .arg("config") @@ -72,7 +97,6 @@ fn test_run_customlambda() { assert.stdout("139583862445\n"); } -#[allow(dead_code)] fn assert_tarball_is_present_local(target: &str) -> Result { let wasmer_dir = std::env::var("WASMER_DIR").expect("no WASMER_DIR set"); let directory = match target { @@ -96,8 +120,8 @@ fn assert_tarball_is_present_local(target: &str) -> Result for more. +#[test] +fn wasi_runner_on_disk_mount_using_relative_directory_on_the_host() { + let temp = TempDir::new_in(env!("CARGO_TARGET_TMPDIR")).unwrap(); + std::fs::write(temp.path().join("main.py"), "print('Hello, World!')").unwrap(); + + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::python()) + .arg("--mapdir=/app:.") + .arg("--") + .arg("/app/main.py") + .env("RUST_LOG", &*RUST_LOG) + .current_dir(temp.path()) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wasi_runner_on_disk_with_mounted_directories() { + let temp = TempDir::new().unwrap(); + std::fs::write(temp.path().join("index.js"), "console.log('Hello, World!')").unwrap(); + + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::qjs()) + .arg(format!("--mapdir=/app:{}", temp.path().display())) + .arg("--") + .arg("/app/index.js") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wasi_runner_on_disk_with_mounted_directories_and_webc_volumes() { + let temp = TempDir::new().unwrap(); + std::fs::write(temp.path().join("main.py"), "print('Hello, World!')").unwrap(); + + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::python()) + .arg(format!("--mapdir=/app:{}", temp.path().display())) + .arg("--") + .arg("-B") + .arg("/app/main.py") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wasi_runner_on_disk_with_dependencies() { + let port = random_port(); + let mut cmd = Command::new(get_wasmer_path()); + cmd.arg("run") + .arg(fixtures::hello()) + .arg(format!("--env=SERVER_PORT={port}")) + .arg("--net") + .arg("--") + .arg("--log-level=info") + .env("RUST_LOG", &*RUST_LOG); + let mut child = JoinableChild::spawn(cmd); + child.wait_for_stderr("listening"); + + // Make sure we get the page we want + let html = reqwest::blocking::get(format!("http://localhost:{port}/")) + .unwrap() + .text() + .unwrap(); + assert!(html.contains("Hello World"), "{html}"); + + // and make sure our request was logged + child + .join() + .stderr(contains("incoming request: method=GET uri=/")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn webc_files_on_disk_with_multiple_commands_require_an_entrypoint_flag() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::wabt()) + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + let msg = r#"Unable to determine the WEBC file's entrypoint. Please choose one of ["wasm-interp", "wasm-strip", "wasm-validate", "wasm2wat", "wast2json", "wat2wasm"]"#; + assert.failure().stderr(contains(msg)); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wasi_runner_on_disk_with_env_vars() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::python()) + .arg("--env=SOME_VAR=Hello, World!") + .arg("--") + .arg("-B") + .arg("-c") + .arg("import os; print(os.environ['SOME_VAR'])") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wcgi_runner_on_disk() { + // Start the WCGI server in the background + let port = random_port(); + let mut cmd = Command::new(get_wasmer_path()); + cmd.arg("run") + .arg(format!("--addr=127.0.0.1:{port}")) + .arg(fixtures::static_server()) + .env("RUST_LOG", &*RUST_LOG); + + // Let's run the command and wait until the server has started + let mut child = JoinableChild::spawn(cmd); + child.wait_for_stdout("WCGI Server running"); + + // make the request + let body = http_get(format!("http://127.0.0.1:{port}/")).unwrap(); + assert!(body.contains("Index of /"), "{body}"); + + // Let's make sure 404s work too + let err = http_get(format!("http://127.0.0.1:{port}/this/does/not/exist.html")).unwrap_err(); + assert_eq!(err.status().unwrap(), reqwest::StatusCode::NOT_FOUND); + + // And kill the server, making sure it generated the expected logs + let assert = child.join(); + + assert + .stderr(contains("Starting the server")) + .stderr(contains( + "response generated method=GET uri=/ status_code=200 OK", + )) + .stderr(contains( + "response generated method=GET uri=/this/does/not/exist.html status_code=404 Not Found", + )); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wcgi_runner_on_disk_with_mounted_directories() { + let temp = TempDir::new().unwrap(); + std::fs::write(temp.path().join("file.txt"), "Hello, World!").unwrap(); + // Start the WCGI server in the background + let port = random_port(); + let mut cmd = Command::new(get_wasmer_path()); + cmd.arg("run") + .arg(format!("--addr=127.0.0.1:{port}")) + .arg(format!("--mapdir=/path/to:{}", temp.path().display())) + .arg(fixtures::static_server()) + .env("RUST_LOG", &*RUST_LOG); + + // Let's run the command and wait until the server has started + let mut child = JoinableChild::spawn(cmd); + child.wait_for_stdout("WCGI Server running"); + + let body = http_get(format!("http://127.0.0.1:{port}/path/to/file.txt")).unwrap(); + assert!(body.contains("Hello, World!"), "{body}"); + + // And kill the server, making sure it generated the expected logs + let assert = child.join(); + + assert + .stderr(contains("Starting the server")) + .stderr(contains( + "response generated method=GET uri=/path/to/file.txt status_code=200 OK", + )); +} + +/// See https://github.com/wasmerio/wasmer/issues/3794 +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn issue_3794_unable_to_mount_relative_paths() { + let temp = TempDir::new().unwrap(); + std::fs::write(temp.path().join("message.txt"), b"Hello, World!").unwrap(); + + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::coreutils()) + .arg(format!("--mapdir=./some-dir/:{}", temp.path().display())) + .arg("--command-name=cat") + .arg("--") + .arg("./some-dir/message.txt") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +#[cfg_attr( + windows, + ignore = "FIXME(Michael-F-Bryan): Temporarily broken on Windows - https://github.com/wasmerio/wasmer/issues/3929" +)] +fn merged_filesystem_contains_all_files() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::bash()) + .arg("--entrypoint=bash") + .arg("--use") + .arg(fixtures::coreutils()) + .arg("--use") + .arg(fixtures::python()) + .arg("--") + .arg("-c") + .arg("ls -l /usr/coreutils/*.md && ls -l /lib/python3.6/*.py") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert + .success() + .stdout(contains("/usr/coreutils/README.md")) + .stdout(contains("/lib/python3.6/this.py")); +} + +#[test] +fn run_a_wasi_executable() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::qjs()) + .arg("--") + .arg("--eval") + .arg("console.log('Hello, World!')") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +fn wasm_file_with_no_abi() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::fib()) + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success(); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn error_if_no_start_function_found() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(fixtures::wat_no_start()) + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert + .failure() + .stderr(contains("The module doesn't contain a \"_start\" function")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn run_a_pre_compiled_wasm_file() { + let temp = TempDir::new().unwrap(); + let dest = temp.path().join("qjs.wasmu"); + let qjs = fixtures::qjs(); + // Make sure it is compiled + Command::new(get_wasmer_path()) + .arg("compile") + .arg("-o") + .arg(&dest) + .arg(&qjs) + .assert() + .success(); + assert!(dest.exists()); + + // Now we can try to run the compiled artifact + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(&dest) + .arg("--") + .arg("--eval") + .arg("console.log('Hello, World!')") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn wasmer_run_some_directory() { + let temp = TempDir::new().unwrap(); + std::fs::copy(fixtures::qjs(), temp.path().join("qjs.wasm")).unwrap(); + std::fs::copy(fixtures::qjs_wasmer_toml(), temp.path().join("wasmer.toml")).unwrap(); + + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg(temp.path()) + .arg("--") + .arg("--eval") + .arg("console.log('Hello, World!')") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn run_quickjs_via_package_name() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg("saghul/quickjs") + .arg("--entrypoint=quickjs") + .arg("--registry=wapm.io") + .arg("--") + .arg("--eval") + .arg("console.log('Hello, World!')") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +fn run_quickjs_via_url() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg("https://wapm.io/saghul/quickjs") + .arg("--entrypoint=quickjs") + .arg("--") + .arg("--eval") + .arg("console.log('Hello, World!')") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + assert.success().stdout(contains("Hello, World!")); +} + +#[test] +#[cfg_attr( + all(target_env = "musl", target_os = "linux"), + ignore = "wasmer run-unstable segfaults on musl" +)] +#[cfg_attr( + windows, + ignore = "TODO(Michael-F-Bryan): Figure out why WasiFs::get_inode_at_path_inner() returns Errno::notcapable on Windows" +)] +fn run_bash_using_coreutils() { + let assert = Command::new(get_wasmer_path()) + .arg("run") + .arg("sharrattj/bash") + .arg("--entrypoint=bash") + .arg("--use=sharrattj/coreutils") + .arg("--registry=wapm.io") + .arg("--") + .arg("-c") + .arg("ls /bin") + .env("RUST_LOG", &*RUST_LOG) + .assert(); + + // Note: the resulting filesystem should contain the main command as + // well as the commands from all the --use packages + + let some_expected_binaries = [ + "arch", "base32", "base64", "baseenc", "basename", "bash", "cat", + ] + .join("\n"); + assert.success().stdout(contains(some_expected_binaries)); +} + +mod fixtures { + use std::path::{Path, PathBuf}; + + use wasmer_integration_tests_cli::{asset_path, c_asset_path}; + + /// A WEBC file containing the Python interpreter, compiled to WASI. + pub fn python() -> PathBuf { + c_asset_path().join("python-0.1.0.wasmer") + } + + pub fn coreutils() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("webc") + .join("coreutils-1.0.16-e27dbb4f-2ef2-4b44-b46a-ddd86497c6d7.webc") + } + + pub fn bash() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("webc") + .join("bash-1.0.16-f097441a-a80b-4e0d-87d7-684918ef4bb6.webc") + } + + /// A WEBC file containing `wat2wasm`, `wasm-validate`, and other helpful + /// WebAssembly-related commands. + pub fn wabt() -> PathBuf { + c_asset_path().join("wabt-1.0.37.wasmer") + } + + /// A WEBC file containing the WCGI static server. + pub fn static_server() -> PathBuf { + c_asset_path().join("staticserver.webc") + } + + /// The QuickJS interpreter, compiled to a WASI module. + pub fn qjs() -> PathBuf { + c_asset_path().join("qjs.wasm") + } + + pub fn hello() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("webc") + .join("hello-0.1.0-665d2ddc-80e6-4845-85d3-4587b1693bb7.webc") + } + + /// The `wasmer.toml` file for QuickJS. + pub fn qjs_wasmer_toml() -> PathBuf { + c_asset_path().join("qjs-wasmer.toml") + } + + /// An executable which calculates fib(40) and exits with no output. + pub fn fib() -> PathBuf { + asset_path().join("fib.wat") + } + + pub fn wat_no_start() -> PathBuf { + asset_path().join("no_start.wat") + } +} + +/// A helper that wraps [`Child`] to make sure it gets terminated +/// when it is no longer needed. +struct JoinableChild { + command: Command, + child: Option, +} + +impl JoinableChild { + fn spawn(mut cmd: Command) -> Self { + let child = cmd + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(); + + JoinableChild { + child: Some(child), + command: cmd, + } + } + + /// Keep reading lines from the child's stdout until a line containing the + /// desired text is found. + fn wait_for_stdout(&mut self, text: &str) -> String { + let stdout = self + .child + .as_mut() + .and_then(|child| child.stdout.as_mut()) + .unwrap(); + + wait_for(text, stdout) + } + + /// Keep reading lines from the child's stderr until a line containing the + /// desired text is found. + fn wait_for_stderr(&mut self, text: &str) -> String { + let stderr = self + .child + .as_mut() + .and_then(|child| child.stderr.as_mut()) + .unwrap(); + + wait_for(text, stderr) + } + + /// Kill the underlying [`Child`] and get an [`Assert`] we + /// can use to check it. + fn join(mut self) -> Assert { + let mut child = self.child.take().unwrap(); + child.kill().unwrap(); + child.wait_with_output().unwrap().assert() + } +} + +fn wait_for(text: &str, reader: &mut dyn Read) -> String { + let mut all_output = String::new(); + + loop { + let line = read_line(reader).unwrap(); + + if line.is_empty() { + eprintln!("=== All Output === "); + eprintln!("{all_output}"); + panic!("EOF before \"{text}\" was found"); + } + + let found = line.contains(text); + all_output.push_str(&line); + + if found { + return all_output; + } + } +} + +fn read_line(reader: &mut dyn Read) -> Result { + let mut line = Vec::new(); + + while !line.ends_with(&[b'\n']) { + let mut buffer = [0_u8]; + match reader.read_exact(&mut buffer) { + Ok(_) => { + line.push(buffer[0]); + } + Err(e) if e.kind() == ErrorKind::UnexpectedEof => break, + Err(e) => return Err(e), + } + } + + let line = String::from_utf8(line).map_err(|e| std::io::Error::new(ErrorKind::Other, e))?; + Ok(line) +} + +impl Drop for JoinableChild { + fn drop(&mut self) { + if let Some(mut child) = self.child.take() { + eprintln!("==== WARNING: Child was dropped before being joined ===="); + eprintln!("Command: {:?}", self.command); + + let _ = child.kill(); + + if let Some(mut stderr) = child.stderr.take() { + let mut buffer = String::new(); + if stderr.read_to_string(&mut buffer).is_ok() { + eprintln!("---- STDERR ----"); + eprintln!("{buffer}"); + } + } + + if let Some(mut stdout) = child.stdout.take() { + let mut buffer = String::new(); + if stdout.read_to_string(&mut buffer).is_ok() { + eprintln!("---- STDOUT ----"); + eprintln!("{buffer}"); + } + } + + if !std::thread::panicking() { + panic!("Child was dropped before being joined"); + } + } + } +} + +/// Send a GET request to a particular URL, automatically retrying (with +/// a timeout) if there are any connection errors. +fn http_get(url: impl IntoUrl) -> Result { + let start = Instant::now(); + let url = url.into_url().unwrap(); + + let client = Client::new(); + + while start.elapsed() < HTTP_GET_TIMEOUT { + match client.get(url.clone()).send() { + Ok(response) => { + return response.error_for_status()?.text(); + } + Err(e) if e.is_connect() => continue, + Err(other) => return Err(other), + } + } + + panic!("Didn't receive a response from \"{url}\" within the allocated time"); +} + +fn random_port() -> u16 { + rand::thread_rng().gen_range(10_000_u16..u16::MAX) +} diff --git a/tests/integration/cli/tests/run_unstable.rs b/tests/integration/cli/tests/run_unstable.rs deleted file mode 100644 index 2b709d7a69a..00000000000 --- a/tests/integration/cli/tests/run_unstable.rs +++ /dev/null @@ -1,668 +0,0 @@ -use std::{ - io::{ErrorKind, Read}, - process::Stdio, - time::{Duration, Instant}, -}; - -use assert_cmd::{assert::Assert, prelude::OutputAssertExt}; -use once_cell::sync::Lazy; -use predicates::str::contains; -use rand::Rng; -use reqwest::{blocking::Client, IntoUrl}; -use tempfile::TempDir; -use wasmer_integration_tests_cli::get_wasmer_path; - -const HTTP_GET_TIMEOUT: Duration = Duration::from_secs(5); - -static RUST_LOG: Lazy = Lazy::new(|| { - if cfg!(feature = "debug") { - String::from("trace") - } else { - [ - "info", - "wasmer_wasix::resolve=debug", - "wasmer_wasix::runners=debug", - "wasmer_wasix=debug", - "virtual_fs::trace_fs=trace", - ] - .join(",") - } -}); - -fn wasmer_run_unstable() -> std::process::Command { - let mut cmd = std::process::Command::new(get_wasmer_path()); - cmd.arg("run").env("RUST_LOG", &*RUST_LOG); - cmd -} - -mod webc_on_disk { - use super::*; - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasi_runner() { - let assert = wasmer_run_unstable() - .arg(fixtures::qjs()) - .arg("--") - .arg("--eval") - .arg("console.log('Hello, World!')") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - /// See for more. - #[test] - fn wasi_runner_mount_using_relative_directory_on_the_host() { - let temp = TempDir::new_in(env!("CARGO_TARGET_TMPDIR")).unwrap(); - std::fs::write(temp.path().join("main.py"), "print('Hello, World!')").unwrap(); - - let assert = wasmer_run_unstable() - .arg(fixtures::python()) - .arg("--mapdir=/app:.") - .arg("--") - .arg("/app/main.py") - .current_dir(temp.path()) - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasi_runner_with_mounted_directories() { - let temp = TempDir::new().unwrap(); - std::fs::write(temp.path().join("index.js"), "console.log('Hello, World!')").unwrap(); - - let assert = wasmer_run_unstable() - .arg(fixtures::qjs()) - .arg(format!("--mapdir=/app:{}", temp.path().display())) - .arg("--") - .arg("/app/index.js") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasi_runner_with_mounted_directories_and_webc_volumes() { - let temp = TempDir::new().unwrap(); - std::fs::write(temp.path().join("main.py"), "print('Hello, World!')").unwrap(); - - let assert = wasmer_run_unstable() - .arg(fixtures::python()) - .arg(format!("--mapdir=/app:{}", temp.path().display())) - .arg("--") - .arg("-B") - .arg("/app/main.py") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasi_runner_with_dependencies() { - let mut cmd = wasmer_run_unstable(); - let port = random_port(); - cmd.arg(fixtures::hello()) - .arg(format!("--env=SERVER_PORT={port}")) - .arg("--net") - .arg("--") - .arg("--log-level=info"); - let mut child = JoinableChild::spawn(cmd); - child.wait_for_stderr("listening"); - - // Make sure we get the page we want - let html = reqwest::blocking::get(format!("http://localhost:{port}/")) - .unwrap() - .text() - .unwrap(); - assert!(html.contains("Hello World"), "{html}"); - - // and make sure our request was logged - child - .join() - .stderr(contains("incoming request: method=GET uri=/")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn webc_files_with_multiple_commands_require_an_entrypoint_flag() { - let assert = wasmer_run_unstable().arg(fixtures::wabt()).assert(); - - let msg = r#"Unable to determine the WEBC file's entrypoint. Please choose one of ["wasm-interp", "wasm-strip", "wasm-validate", "wasm2wat", "wast2json", "wat2wasm"]"#; - assert.failure().stderr(contains(msg)); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasi_runner_with_env_vars() { - let assert = wasmer_run_unstable() - .arg(fixtures::python()) - .arg("--env=SOME_VAR=Hello, World!") - .arg("--") - .arg("-B") - .arg("-c") - .arg("import os; print(os.environ['SOME_VAR'])") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wcgi_runner() { - // Start the WCGI server in the background - let port = random_port(); - let mut cmd = wasmer_run_unstable(); - cmd.arg(format!("--addr=127.0.0.1:{port}")) - .arg(fixtures::static_server()); - - // Let's run the command and wait until the server has started - let mut child = JoinableChild::spawn(cmd); - child.wait_for_stdout("WCGI Server running"); - - // make the request - let body = http_get(format!("http://127.0.0.1:{port}/")).unwrap(); - assert!(body.contains("Index of /"), "{body}"); - - // Let's make sure 404s work too - let err = - http_get(format!("http://127.0.0.1:{port}/this/does/not/exist.html")).unwrap_err(); - assert_eq!(err.status().unwrap(), reqwest::StatusCode::NOT_FOUND); - - // And kill the server, making sure it generated the expected logs - let assert = child.join(); - - assert - .stderr(contains("Starting the server")) - .stderr(contains("response generated method=GET uri=/ status_code=200 OK")) - .stderr(contains("response generated method=GET uri=/this/does/not/exist.html status_code=404 Not Found")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wcgi_runner_with_mounted_directories() { - let temp = TempDir::new().unwrap(); - std::fs::write(temp.path().join("file.txt"), "Hello, World!").unwrap(); - // Start the WCGI server in the background - let port = random_port(); - let mut cmd = wasmer_run_unstable(); - cmd.arg(format!("--addr=127.0.0.1:{port}")) - .arg(format!("--mapdir=/path/to:{}", temp.path().display())) - .arg(fixtures::static_server()); - - // Let's run the command and wait until the server has started - let mut child = JoinableChild::spawn(cmd); - child.wait_for_stdout("WCGI Server running"); - - let body = http_get(format!("http://127.0.0.1:{port}/path/to/file.txt")).unwrap(); - assert!(body.contains("Hello, World!"), "{body}"); - - // And kill the server, making sure it generated the expected logs - let assert = child.join(); - - assert - .stderr(contains("Starting the server")) - .stderr(contains( - "response generated method=GET uri=/path/to/file.txt status_code=200 OK", - )); - } - - /// See https://github.com/wasmerio/wasmer/issues/3794 - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn issue_3794_unable_to_mount_relative_paths() { - let temp = TempDir::new().unwrap(); - std::fs::write(temp.path().join("message.txt"), b"Hello, World!").unwrap(); - - let assert = wasmer_run_unstable() - .arg(fixtures::coreutils()) - .arg(format!("--mapdir=./some-dir/:{}", temp.path().display())) - .arg("--command-name=cat") - .arg("--") - .arg("./some-dir/message.txt") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - #[cfg_attr( - windows, - ignore = "FIXME(Michael-F-Bryan): Temporarily broken on Windows - https://github.com/wasmerio/wasmer/issues/3929" - )] - fn merged_filesystem_contains_all_files() { - let assert = wasmer_run_unstable() - .arg(fixtures::bash()) - .arg("--entrypoint=bash") - .arg("--use") - .arg(fixtures::coreutils()) - .arg("--use") - .arg(fixtures::python()) - .arg("--") - .arg("-c") - .arg("ls -l /usr/coreutils/*.md && ls -l /lib/python3.6/*.py") - .assert(); - - assert - .success() - .stdout(contains("/usr/coreutils/README.md")) - .stdout(contains("/lib/python3.6/this.py")); - } -} - -mod wasm_on_disk { - use std::process::Command; - - use super::*; - use predicates::str::contains; - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasi_executable() { - let assert = wasmer_run_unstable() - .arg(fixtures::qjs()) - .arg("--") - .arg("--eval") - .arg("console.log('Hello, World!')") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn no_abi() { - let assert = wasmer_run_unstable().arg(fixtures::fib()).assert(); - - assert.success(); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn error_if_no_start_function_found() { - let assert = wasmer_run_unstable().arg(fixtures::wat_no_start()).assert(); - - assert - .failure() - .stderr(contains("The module doesn't contain a \"_start\" function")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn pre_compiled() { - let temp = TempDir::new().unwrap(); - let dest = temp.path().join("qjs.wasmu"); - let qjs = fixtures::qjs(); - // Make sure it is compiled - Command::new(get_wasmer_path()) - .arg("compile") - .arg("-o") - .arg(&dest) - .arg(&qjs) - .assert() - .success(); - assert!(dest.exists()); - - // Now we can try to run the compiled artifact - let assert = wasmer_run_unstable() - .arg(&dest) - .arg("--") - .arg("--eval") - .arg("console.log('Hello, World!')") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } -} - -mod local_directory { - use super::*; - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn wasmer_package_directory() { - let temp = TempDir::new().unwrap(); - std::fs::copy(fixtures::qjs(), temp.path().join("qjs.wasm")).unwrap(); - std::fs::copy(fixtures::qjs_wasmer_toml(), temp.path().join("wasmer.toml")).unwrap(); - - let assert = wasmer_run_unstable() - .arg(temp.path()) - .arg("--") - .arg("--eval") - .arg("console.log('Hello, World!')") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } -} - -mod remote_webc { - use super::*; - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn quickjs_as_package_name() { - let assert = wasmer_run_unstable() - .arg("saghul/quickjs") - .arg("--entrypoint=quickjs") - .arg("--registry=wapm.io") - .arg("--") - .arg("--eval") - .arg("console.log('Hello, World!')") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - fn quickjs_as_url() { - let assert = wasmer_run_unstable() - .arg("https://wapm.io/saghul/quickjs") - .arg("--entrypoint=quickjs") - .arg("--") - .arg("--eval") - .arg("console.log('Hello, World!')") - .assert(); - - assert.success().stdout(contains("Hello, World!")); - } - - #[test] - #[cfg_attr( - all(target_env = "musl", target_os = "linux"), - ignore = "wasmer run-unstable segfaults on musl" - )] - #[cfg_attr( - windows, - ignore = "TODO(Michael-F-Bryan): Figure out why WasiFs::get_inode_at_path_inner() returns Errno::notcapable on Windows" - )] - fn bash_using_coreutils() { - let assert = wasmer_run_unstable() - .arg("sharrattj/bash") - .arg("--entrypoint=bash") - .arg("--use=sharrattj/coreutils") - .arg("--registry=wapm.io") - .arg("--") - .arg("-c") - .arg("ls /bin") - .assert(); - - // Note: the resulting filesystem should contain the main command as - // well as the commands from all the --use packages - - let some_expected_binaries = [ - "arch", "base32", "base64", "baseenc", "basename", "bash", "cat", - ] - .join("\n"); - assert.success().stdout(contains(some_expected_binaries)); - } -} - -mod fixtures { - use std::path::{Path, PathBuf}; - - use wasmer_integration_tests_cli::{asset_path, c_asset_path}; - - /// A WEBC file containing the Python interpreter, compiled to WASI. - pub fn python() -> PathBuf { - c_asset_path().join("python-0.1.0.wasmer") - } - - pub fn coreutils() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests") - .join("webc") - .join("coreutils-1.0.16-e27dbb4f-2ef2-4b44-b46a-ddd86497c6d7.webc") - } - - pub fn bash() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests") - .join("webc") - .join("bash-1.0.16-f097441a-a80b-4e0d-87d7-684918ef4bb6.webc") - } - - /// A WEBC file containing `wat2wasm`, `wasm-validate`, and other helpful - /// WebAssembly-related commands. - pub fn wabt() -> PathBuf { - c_asset_path().join("wabt-1.0.37.wasmer") - } - - /// A WEBC file containing the WCGI static server. - pub fn static_server() -> PathBuf { - c_asset_path().join("staticserver.webc") - } - - /// The QuickJS interpreter, compiled to a WASI module. - pub fn qjs() -> PathBuf { - c_asset_path().join("qjs.wasm") - } - - pub fn hello() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests") - .join("webc") - .join("hello-0.1.0-665d2ddc-80e6-4845-85d3-4587b1693bb7.webc") - } - - /// The `wasmer.toml` file for QuickJS. - pub fn qjs_wasmer_toml() -> PathBuf { - c_asset_path().join("qjs-wasmer.toml") - } - - /// An executable which calculates fib(40) and exits with no output. - pub fn fib() -> PathBuf { - asset_path().join("fib.wat") - } - - pub fn wat_no_start() -> PathBuf { - asset_path().join("no_start.wat") - } -} - -/// A helper that wraps [`std::process::Child`] to make sure it gets terminated -/// when it is no longer needed. -struct JoinableChild { - command: std::process::Command, - child: Option, -} - -impl JoinableChild { - fn spawn(mut cmd: std::process::Command) -> Self { - let child = cmd - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .unwrap(); - - JoinableChild { - child: Some(child), - command: cmd, - } - } - - /// Keep reading lines from the child's stdout until a line containing the - /// desired text is found. - fn wait_for_stdout(&mut self, text: &str) -> String { - let stdout = self - .child - .as_mut() - .and_then(|child| child.stdout.as_mut()) - .unwrap(); - - wait_for(text, stdout) - } - - /// Keep reading lines from the child's stderr until a line containing the - /// desired text is found. - fn wait_for_stderr(&mut self, text: &str) -> String { - let stderr = self - .child - .as_mut() - .and_then(|child| child.stderr.as_mut()) - .unwrap(); - - wait_for(text, stderr) - } - - /// Kill the underlying [`std::process::Child`] and get an [`Assert`] we - /// can use to check it. - fn join(mut self) -> Assert { - let mut child = self.child.take().unwrap(); - child.kill().unwrap(); - child.wait_with_output().unwrap().assert() - } -} - -fn wait_for(text: &str, reader: &mut dyn Read) -> String { - let mut all_output = String::new(); - - loop { - let line = read_line(reader).unwrap(); - - if line.is_empty() { - eprintln!("=== All Output === "); - eprintln!("{all_output}"); - panic!("EOF before \"{text}\" was found"); - } - - let found = line.contains(text); - all_output.push_str(&line); - - if found { - return all_output; - } - } -} - -fn read_line(reader: &mut dyn Read) -> Result { - let mut line = Vec::new(); - - while !line.ends_with(&[b'\n']) { - let mut buffer = [0_u8]; - match reader.read_exact(&mut buffer) { - Ok(_) => { - line.push(buffer[0]); - } - Err(e) if e.kind() == ErrorKind::UnexpectedEof => break, - Err(e) => return Err(e), - } - } - - let line = String::from_utf8(line).map_err(|e| std::io::Error::new(ErrorKind::Other, e))?; - Ok(line) -} - -impl Drop for JoinableChild { - fn drop(&mut self) { - if let Some(mut child) = self.child.take() { - eprintln!("==== WARNING: Child was dropped before being joined ===="); - eprintln!("Command: {:?}", self.command); - - let _ = child.kill(); - - if let Some(mut stderr) = child.stderr.take() { - let mut buffer = String::new(); - if stderr.read_to_string(&mut buffer).is_ok() { - eprintln!("---- STDERR ----"); - eprintln!("{buffer}"); - } - } - - if let Some(mut stdout) = child.stdout.take() { - let mut buffer = String::new(); - if stdout.read_to_string(&mut buffer).is_ok() { - eprintln!("---- STDOUT ----"); - eprintln!("{buffer}"); - } - } - - if !std::thread::panicking() { - panic!("Child was dropped before being joined"); - } - } - } -} - -/// Send a GET request to a particular URL, automatically retrying (with -/// a timeout) if there are any connection errors. -fn http_get(url: impl IntoUrl) -> Result { - let start = Instant::now(); - let url = url.into_url().unwrap(); - - let client = Client::new(); - - while start.elapsed() < HTTP_GET_TIMEOUT { - match client.get(url.clone()).send() { - Ok(response) => { - return response.error_for_status()?.text(); - } - Err(e) if e.is_connect() => continue, - Err(other) => return Err(other), - } - } - - panic!("Didn't receive a response from \"{url}\" within the allocated time"); -} - -fn random_port() -> u16 { - rand::thread_rng().gen_range(10_000_u16..u16::MAX) -} From 287d884ba127625368f3775529bcd9a007e78c76 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 12:33:03 +0800 Subject: [PATCH 07/17] Moved another create-exe test into "create_exe.rs" --- tests/integration/cli/tests/create_exe.rs | 121 +++++++++++++++++++++- tests/integration/cli/tests/run.rs | 111 -------------------- 2 files changed, 119 insertions(+), 113 deletions(-) diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index 21a80d62f20..45a10f7192f 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -1,6 +1,11 @@ //! Tests of the `wasmer create-exe` command. -use std::{fs, io::prelude::*, path::PathBuf, process::Command}; +use std::{ + fs, + io::prelude::*, + path::{Path, PathBuf}, + process::Command, +}; use anyhow::{bail, Context}; use assert_cmd::prelude::OutputAssertExt; @@ -693,7 +698,7 @@ fn test_wasmer_create_exe_pirita_works() { // std::fs::create_dir_all(&temp_dir); use wasmer_integration_tests_cli::get_repo_root_path; - let temp_dir = tempfile::TempDir::new().unwrap(); + let temp_dir = TempDir::new().unwrap(); let temp_dir = temp_dir.path().to_path_buf(); let python_wasmer_path = temp_dir.join("python.wasmer"); std::fs::copy(create_exe_python_wasmer(), &python_wasmer_path).unwrap(); @@ -738,3 +743,115 @@ fn test_wasmer_create_exe_pirita_works() { command.assert().success().stdout("hello\n"); } + +// FIXME: Fix and re-enable this test +// See https://github.com/wasmerio/wasmer/issues/3615 +#[test] +#[ignore] +fn test_cross_compile_python_windows() { + let temp_dir = TempDir::new().unwrap(); + + let targets: &[&str] = if cfg!(windows) { + &[ + "aarch64-darwin", + "x86_64-darwin", + "x86_64-linux-gnu", + "aarch64-linux-gnu", + ] + } else { + &[ + "aarch64-darwin", + "x86_64-darwin", + "x86_64-linux-gnu", + "aarch64-linux-gnu", + "x86_64-windows-gnu", + ] + }; + + let compilers: &[&str] = if cfg!(target_env = "musl") { + // MUSL has no support for LLVM in C-API + &["cranelift", "singlepass"] + } else { + &["cranelift", "singlepass", "llvm"] + }; + + // llvm-objdump --disassemble-all --demangle ./objects/wasmer_vm-50cb118b098c15db.wasmer_vm.60425a0a-cgu.12.rcgu.o + // llvm-objdump --macho --exports-trie ~/.wasmer/cache/wasmer-darwin-arm64/lib/libwasmer.dylib + let excluded_combinations = &[ + ("aarch64-darwin", "llvm"), // LLVM: aarch64 not supported relocation Arm64MovwG0 not supported + ("aarch64-linux-gnu", "llvm"), // LLVM: aarch64 not supported relocation Arm64MovwG0 not supported + // https://github.com/ziglang/zig/issues/13729 + ("x86_64-darwin", "llvm"), // undefined reference to symbol 'wasmer_vm_raise_trap' kind Unknown + ("x86_64-windows-gnu", "llvm"), // unimplemented symbol `wasmer_vm_raise_trap` kind Unknown + ]; + + for t in targets { + for c in compilers { + if excluded_combinations.contains(&(t, c)) { + continue; + } + println!("{t} target {c}"); + let python_wasmer_path = temp_dir.path().join(format!("{t}-python")); + + let tarball = match std::env::var("GITHUB_TOKEN") { + Ok(_) => Some(assert_tarball_is_present_local(t).unwrap()), + Err(_) => None, + }; + let mut cmd = Command::new(get_wasmer_path()); + + cmd.arg("create-exe"); + cmd.arg(create_exe_python_wasmer()); + cmd.arg("--target"); + cmd.arg(t); + cmd.arg("-o"); + cmd.arg(python_wasmer_path.clone()); + cmd.arg(format!("--{c}")); + if std::env::var("GITHUB_TOKEN").is_ok() { + cmd.arg("--debug-dir"); + cmd.arg(format!("{t}-{c}")); + } + + if t.contains("x86_64") && *c == "singlepass" { + cmd.arg("-m"); + cmd.arg("avx"); + } + + if let Some(t) = tarball { + cmd.arg("--tarball"); + cmd.arg(t); + } + + let assert = cmd.assert().success(); + + if !python_wasmer_path.exists() { + let p = std::fs::read_dir(temp_dir.path()) + .unwrap() + .filter_map(|e| Some(e.ok()?.path())) + .collect::>(); + let output = assert.get_output(); + panic!("target {t} was not compiled correctly tempdir: {p:#?}, {output:?}",); + } + } + } +} + +fn assert_tarball_is_present_local(target: &str) -> Result { + let wasmer_dir = std::env::var("WASMER_DIR").expect("no WASMER_DIR set"); + let directory = match target { + "aarch64-darwin" => "wasmer-darwin-arm64.tar.gz", + "x86_64-darwin" => "wasmer-darwin-amd64.tar.gz", + "x86_64-linux-gnu" => "wasmer-linux-amd64.tar.gz", + "aarch64-linux-gnu" => "wasmer-linux-aarch64.tar.gz", + "x86_64-windows-gnu" => "wasmer-windows-gnu64.tar.gz", + _ => return Err(anyhow::anyhow!("unknown target {target}")), + }; + let libwasmer_cache_path = Path::new(&wasmer_dir).join("cache").join(directory); + if !libwasmer_cache_path.exists() { + return Err(anyhow::anyhow!( + "targz {} does not exist", + libwasmer_cache_path.display() + )); + } + println!("using targz {}", libwasmer_cache_path.display()); + Ok(libwasmer_cache_path) +} diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 8234abfbfec..33f7e733c8f 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -97,117 +97,6 @@ fn test_run_customlambda() { assert.stdout("139583862445\n"); } -fn assert_tarball_is_present_local(target: &str) -> Result { - let wasmer_dir = std::env::var("WASMER_DIR").expect("no WASMER_DIR set"); - let directory = match target { - "aarch64-darwin" => "wasmer-darwin-arm64.tar.gz", - "x86_64-darwin" => "wasmer-darwin-amd64.tar.gz", - "x86_64-linux-gnu" => "wasmer-linux-amd64.tar.gz", - "aarch64-linux-gnu" => "wasmer-linux-aarch64.tar.gz", - "x86_64-windows-gnu" => "wasmer-windows-gnu64.tar.gz", - _ => return Err(anyhow::anyhow!("unknown target {target}")), - }; - let libwasmer_cache_path = Path::new(&wasmer_dir).join("cache").join(directory); - if !libwasmer_cache_path.exists() { - return Err(anyhow::anyhow!( - "targz {} does not exist", - libwasmer_cache_path.display() - )); - } - println!("using targz {}", libwasmer_cache_path.display()); - Ok(libwasmer_cache_path) -} - -// FIXME: Fix and re-enable this test -// See https://github.com/wasmerio/wasmer/issues/3615 -#[test] -#[ignore] -fn test_cross_compile_python_windows() { - let temp_dir = tempfile::TempDir::new().unwrap(); - - #[cfg(not(windows))] - let targets = &[ - "aarch64-darwin", - "x86_64-darwin", - "x86_64-linux-gnu", - "aarch64-linux-gnu", - "x86_64-windows-gnu", - ]; - - #[cfg(windows)] - let targets = &[ - "aarch64-darwin", - "x86_64-darwin", - "x86_64-linux-gnu", - "aarch64-linux-gnu", - ]; - - // MUSL has no support for LLVM in C-API - #[cfg(target_env = "musl")] - let compilers = &["cranelift", "singlepass"]; - #[cfg(not(target_env = "musl"))] - let compilers = &["cranelift", "singlepass", "llvm"]; - - // llvm-objdump --disassemble-all --demangle ./objects/wasmer_vm-50cb118b098c15db.wasmer_vm.60425a0a-cgu.12.rcgu.o - // llvm-objdump --macho --exports-trie ~/.wasmer/cache/wasmer-darwin-arm64/lib/libwasmer.dylib - let excluded_combinations = &[ - ("aarch64-darwin", "llvm"), // LLVM: aarch64 not supported relocation Arm64MovwG0 not supported - ("aarch64-linux-gnu", "llvm"), // LLVM: aarch64 not supported relocation Arm64MovwG0 not supported - // https://github.com/ziglang/zig/issues/13729 - ("x86_64-darwin", "llvm"), // undefined reference to symbol 'wasmer_vm_raise_trap' kind Unknown - ("x86_64-windows-gnu", "llvm"), // unimplemented symbol `wasmer_vm_raise_trap` kind Unknown - ]; - - for t in targets { - for c in compilers { - if excluded_combinations.contains(&(t, c)) { - continue; - } - println!("{t} target {c}"); - let python_wasmer_path = temp_dir.path().join(format!("{t}-python")); - - let tarball = match std::env::var("GITHUB_TOKEN") { - Ok(_) => Some(assert_tarball_is_present_local(t).unwrap()), - Err(_) => None, - }; - let mut cmd = Command::new(get_wasmer_path()); - - cmd.arg("create-exe"); - cmd.arg(wasi_test_python_path()); - cmd.arg("--target"); - cmd.arg(t); - cmd.arg("-o"); - cmd.arg(python_wasmer_path.clone()); - cmd.arg(format!("--{c}")); - if std::env::var("GITHUB_TOKEN").is_ok() { - cmd.arg("--debug-dir"); - cmd.arg(format!("{t}-{c}")); - } - - if t.contains("x86_64") && *c == "singlepass" { - cmd.arg("-m"); - cmd.arg("avx"); - } - - if let Some(t) = tarball { - cmd.arg("--tarball"); - cmd.arg(t); - } - - let assert = cmd.assert().success(); - - if !python_wasmer_path.exists() { - let p = std::fs::read_dir(temp_dir.path()) - .unwrap() - .filter_map(|e| Some(e.ok()?.path())) - .collect::>(); - let output = assert.get_output(); - panic!("target {t} was not compiled correctly tempdir: {p:#?}, {output:?}",); - } - } - } -} - #[test] fn run_whoami_works() { // running test locally: should always pass since From 6ef0f7daaad624860adef81dee5b86db575f89b2 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 12:46:19 +0800 Subject: [PATCH 08/17] Moved all paths to test files into a single "fixtures" module --- tests/integration/cli/src/fixtures.rs | 64 ++++++++++++++ tests/integration/cli/src/lib.rs | 7 +- tests/integration/cli/tests/create_exe.rs | 38 +++------ tests/integration/cli/tests/gen_c_header.rs | 14 +-- tests/integration/cli/tests/publish.rs | 8 +- tests/integration/cli/tests/run.rs | 94 ++------------------- 6 files changed, 93 insertions(+), 132 deletions(-) create mode 100644 tests/integration/cli/src/fixtures.rs diff --git a/tests/integration/cli/src/fixtures.rs b/tests/integration/cli/src/fixtures.rs new file mode 100644 index 00000000000..7f047852b61 --- /dev/null +++ b/tests/integration/cli/src/fixtures.rs @@ -0,0 +1,64 @@ +//! Paths for commonly used test files. + +use std::path::{Path, PathBuf}; + +use crate::{asset_path, c_asset_path}; + +/// A WEBC file containing the Python interpreter, compiled to WASI. +pub fn python() -> PathBuf { + c_asset_path().join("python-0.1.0.wasmer") +} + +/// A WEBC file containing the coreutils. +pub fn coreutils() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("webc") + .join("coreutils-1.0.16-e27dbb4f-2ef2-4b44-b46a-ddd86497c6d7.webc") +} + +/// A WEBC file containing bash. +pub fn bash() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("webc") + .join("bash-1.0.16-f097441a-a80b-4e0d-87d7-684918ef4bb6.webc") +} + +/// A WEBC file containing `wat2wasm`, `wasm-validate`, and other helpful +/// WebAssembly-related commands. +pub fn wabt() -> PathBuf { + c_asset_path().join("wabt-1.0.37.wasmer") +} + +/// A WEBC file containing the WCGI static server. +pub fn static_server() -> PathBuf { + c_asset_path().join("staticserver.webc") +} + +/// The QuickJS interpreter, compiled to a WASI module. +pub fn qjs() -> PathBuf { + c_asset_path().join("qjs.wasm") +} + +pub fn hello() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("webc") + .join("hello-0.1.0-665d2ddc-80e6-4845-85d3-4587b1693bb7.webc") +} + +/// The `wasmer.toml` file for QuickJS. +pub fn qjs_wasmer_toml() -> PathBuf { + c_asset_path().join("qjs-wasmer.toml") +} + +/// A `*.wat` file which calculates fib(40) and exits with no output. +pub fn fib() -> PathBuf { + asset_path().join("fib.wat") +} + +/// A `*.wat` file with no `_start()` function. +pub fn wat_no_start() -> PathBuf { + asset_path().join("no_start.wat") +} diff --git a/tests/integration/cli/src/lib.rs b/tests/integration/cli/src/lib.rs index 43d6ada6a69..2411acdbaa9 100644 --- a/tests/integration/cli/src/lib.rs +++ b/tests/integration/cli/src/lib.rs @@ -1,10 +1,9 @@ #![forbid(unsafe_code)] -//! CLI integration tests - -pub mod assets; +mod assets; +pub mod fixtures; pub mod link_code; -pub mod util; +mod util; pub use assets::*; pub use util::*; diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index 45a10f7192f..d7fb8bcacfc 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -12,18 +12,6 @@ use assert_cmd::prelude::OutputAssertExt; use tempfile::TempDir; use wasmer_integration_tests_cli::*; -fn create_exe_wabt_path() -> PathBuf { - c_asset_path().join("wabt-1.0.37.wasmer") -} - -#[allow(dead_code)] -fn create_exe_python_wasmer() -> PathBuf { - c_asset_path().join("python-0.1.0.wasmer") -} - -fn create_exe_test_wasm_path() -> PathBuf { - c_asset_path().join("qjs.wasm") -} const JS_TEST_SRC_CODE: &[u8] = b"function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));\n"; @@ -53,7 +41,7 @@ impl Default for WasmerCreateExe { Self { current_dir: std::env::current_dir().unwrap(), wasmer_path: get_wasmer_path(), - wasm_path: PathBuf::from(create_exe_test_wasm_path()), + wasm_path: PathBuf::from(fixtures::qjs()), native_executable_path, compiler: Compiler::Cranelift, extra_cli_flags: vec![], @@ -128,7 +116,7 @@ impl Default for WasmerCreateObj { Self { current_dir: std::env::current_dir().unwrap(), wasmer_path: get_wasmer_path(), - wasm_path: PathBuf::from(create_exe_test_wasm_path()), + wasm_path: PathBuf::from(fixtures::qjs()), output_object_path, compiler: Compiler::Cranelift, extra_cli_flags: vec![], @@ -173,7 +161,7 @@ fn test_create_exe_with_pirita_works_1() { let wasm_out = path.join("out.obj"); let cmd = Command::new(get_wasmer_path()) .arg("create-obj") - .arg(create_exe_wabt_path()) + .arg(fixtures::wabt()) .arg("-o") .arg(&wasm_out) .output() @@ -191,7 +179,7 @@ fn test_create_exe_with_pirita_works_1() { let cmd = Command::new(get_wasmer_path()) .arg("create-obj") - .arg(create_exe_wabt_path()) + .arg(fixtures::wabt()) .arg("--atom") .arg("wasm2wat") .arg("-o") @@ -226,7 +214,7 @@ fn test_create_exe_with_precompiled_works_1() { let wasm_out = path.join("out.obj"); let _ = Command::new(get_wasmer_path()) .arg("create-obj") - .arg(create_exe_test_wasm_path()) + .arg(fixtures::qjs()) .arg("--prefix") .arg("sha123123") .arg("-o") @@ -248,7 +236,7 @@ fn test_create_exe_with_precompiled_works_1() { let _ = Command::new(get_wasmer_path()) .arg("create-obj") - .arg(create_exe_test_wasm_path()) + .arg(fixtures::qjs()) .arg("-o") .arg(&wasm_out) .output() @@ -280,7 +268,7 @@ fn create_exe_works() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_test_wasm_path()); + let wasm_path = operating_dir.join(fixtures::qjs()); #[cfg(not(windows))] let executable_path = operating_dir.join("wasm.out"); #[cfg(windows)] @@ -321,7 +309,7 @@ fn create_exe_works_multi_command_args_handling() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_wabt_path()); + let wasm_path = operating_dir.join(fixtures::wabt()); #[cfg(not(windows))] let executable_path = operating_dir.join("multicommand.out"); #[cfg(windows)] @@ -387,7 +375,7 @@ fn create_exe_works_multi_command_args_handling() -> anyhow::Result<()> { fn create_exe_works_underscore_module_name() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_wabt_path()); + let wasm_path = operating_dir.join(fixtures::wabt()); let atoms = &[ "wabt", @@ -454,7 +442,7 @@ fn create_exe_works_multi_command() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_wabt_path()); + let wasm_path = operating_dir.join(fixtures::wabt()); #[cfg(not(windows))] let executable_path = operating_dir.join("multicommand.out"); #[cfg(windows)] @@ -511,7 +499,7 @@ fn create_exe_works_with_file() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_test_wasm_path()); + let wasm_path = operating_dir.join(fixtures::qjs()); #[cfg(not(windows))] let executable_path = operating_dir.join("wasm.out"); #[cfg(windows)] @@ -572,7 +560,7 @@ fn create_obj(args: Vec) -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.as_path().join(create_exe_test_wasm_path()); + let wasm_path = operating_dir.as_path().join(fixtures::qjs()); let object_path = operating_dir.as_path().join("wasm"); let _output: Vec = WasmerCreateObj { @@ -604,7 +592,7 @@ fn create_exe_with_object_input(args: Vec) -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_test_wasm_path()); + let wasm_path = operating_dir.join(fixtures::qjs()); #[cfg(not(windows))] let object_path = operating_dir.join("wasm.o"); diff --git a/tests/integration/cli/tests/gen_c_header.rs b/tests/integration/cli/tests/gen_c_header.rs index 3cb1e88532c..ee1a5a67aa6 100644 --- a/tests/integration/cli/tests/gen_c_header.rs +++ b/tests/integration/cli/tests/gen_c_header.rs @@ -1,21 +1,13 @@ use std::{path::PathBuf, process::Command}; -use wasmer_integration_tests_cli::{c_asset_path, get_wasmer_path}; - -fn create_exe_wabt_path() -> PathBuf { - c_asset_path().join("wabt-1.0.37.wasmer") -} - -fn create_exe_test_wasm_path() -> PathBuf { - c_asset_path().join("qjs.wasm") -} +use wasmer_integration_tests_cli::{fixtures, get_wasmer_path}; #[test] fn gen_c_header_works() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_test_wasm_path()); + let wasm_path = operating_dir.join(fixtures::qjs()); let out_path = temp_dir.path().join("header.h"); let _ = Command::new(get_wasmer_path()) @@ -53,7 +45,7 @@ fn gen_c_header_works_pirita() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?; let operating_dir: PathBuf = temp_dir.path().to_owned(); - let wasm_path = operating_dir.join(create_exe_wabt_path()); + let wasm_path = operating_dir.join(fixtures::wabt()); let out_path = temp_dir.path().join("header.h"); let _ = Command::new(get_wasmer_path()) diff --git a/tests/integration/cli/tests/publish.rs b/tests/integration/cli/tests/publish.rs index 0281c1e9fae..075eef023b7 100644 --- a/tests/integration/cli/tests/publish.rs +++ b/tests/integration/cli/tests/publish.rs @@ -1,9 +1,5 @@ use std::{path::PathBuf, process::Stdio}; -use wasmer_integration_tests_cli::{c_asset_path, get_wasmer_path}; - -fn create_exe_test_wasm_path() -> PathBuf { - c_asset_path().join("qjs.wasm") -} +use wasmer_integration_tests_cli::{fixtures, get_wasmer_path}; #[test] fn wasmer_publish() -> anyhow::Result<()> { @@ -21,7 +17,7 @@ fn wasmer_publish() -> anyhow::Result<()> { let random2 = format!("{}", rand::random::()); let random3 = format!("{}", rand::random::()); - std::fs::copy(create_exe_test_wasm_path(), path.join("largewasmfile.wasm")).unwrap(); + std::fs::copy(fixtures::qjs(), path.join("largewasmfile.wasm")).unwrap(); std::fs::write( path.join("wasmer.toml"), include_str!("./fixtures/init6.toml") diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 33f7e733c8f..4acf3e41271 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -13,7 +13,7 @@ use predicates::str::contains; use rand::Rng; use reqwest::{blocking::Client, IntoUrl}; use tempfile::TempDir; -use wasmer_integration_tests_cli::{asset_path, c_asset_path, get_wasmer_path}; +use wasmer_integration_tests_cli::{asset_path, fixtures, get_wasmer_path}; const HTTP_GET_TIMEOUT: Duration = Duration::from_secs(5); @@ -32,22 +32,6 @@ static RUST_LOG: Lazy = Lazy::new(|| { } }); -fn wasi_test_python_path() -> PathBuf { - c_asset_path().join("python-0.1.0.wasmer") -} - -fn wasi_test_wasm_path() -> PathBuf { - c_asset_path().join("qjs.wasm") -} - -fn test_no_imports_wat_path() -> PathBuf { - asset_path().join("fib.wat") -} - -fn test_no_start_wat_path() -> PathBuf { - asset_path().join("no_start.wat") -} - /// Ignored on Windows because running vendored packages does not work /// since Windows does not allow `::` characters in filenames (every other OS does) /// @@ -127,7 +111,7 @@ fn run_whoami_works() { fn run_wasi_works() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg(wasi_test_wasm_path()) + .arg(fixtures::qjs()) .arg("--") .arg("-e") .arg("print(3 * (4 + 5))") @@ -143,7 +127,7 @@ fn run_wasi_works() { fn test_wasmer_run_pirita_works() { let temp_dir = tempfile::TempDir::new().unwrap(); let python_wasmer_path = temp_dir.path().join("python.wasmer"); - std::fs::copy(wasi_test_python_path(), &python_wasmer_path).unwrap(); + std::fs::copy(fixtures::python(), &python_wasmer_path).unwrap(); let assert = Command::new(get_wasmer_path()) .arg("run") @@ -178,9 +162,9 @@ fn test_wasmer_run_works_with_dir() { let temp_dir = tempfile::TempDir::new().unwrap(); let qjs_path = temp_dir.path().join("qjs.wasm"); - std::fs::copy(wasi_test_wasm_path(), &qjs_path).unwrap(); + std::fs::copy(fixtures::qjs(), &qjs_path).unwrap(); std::fs::copy( - c_asset_path().join("qjs-wasmer.toml"), + fixtures::qjs_wasmer_toml(), temp_dir.path().join("wasmer.toml"), ) .unwrap(); @@ -261,7 +245,7 @@ fn test_wasmer_run_works() { fn run_no_imports_wasm_works() { Command::new(get_wasmer_path()) .arg("run") - .arg(test_no_imports_wat_path()) + .arg(fixtures::fib()) .assert() .success(); } @@ -425,7 +409,7 @@ fn run_invoke_works_with_nomain_wasi() { fn run_no_start_wasm_report_error() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg(test_no_start_wat_path()) + .arg(fixtures::wat_no_start()) .assert() .failure(); @@ -435,7 +419,7 @@ fn run_no_start_wasm_report_error() { // Test that wasmer can run a complex path #[test] fn test_wasmer_run_complex_url() { - let wasm_test_path = wasi_test_wasm_path(); + let wasm_test_path = fixtures::qjs(); let wasm_test_path = wasm_test_path.canonicalize().unwrap_or(wasm_test_path); let mut wasm_test_path = format!("{}", wasm_test_path.display()); if wasm_test_path.starts_with(r#"\\?\"#) { @@ -903,68 +887,6 @@ fn run_bash_using_coreutils() { assert.success().stdout(contains(some_expected_binaries)); } -mod fixtures { - use std::path::{Path, PathBuf}; - - use wasmer_integration_tests_cli::{asset_path, c_asset_path}; - - /// A WEBC file containing the Python interpreter, compiled to WASI. - pub fn python() -> PathBuf { - c_asset_path().join("python-0.1.0.wasmer") - } - - pub fn coreutils() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests") - .join("webc") - .join("coreutils-1.0.16-e27dbb4f-2ef2-4b44-b46a-ddd86497c6d7.webc") - } - - pub fn bash() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests") - .join("webc") - .join("bash-1.0.16-f097441a-a80b-4e0d-87d7-684918ef4bb6.webc") - } - - /// A WEBC file containing `wat2wasm`, `wasm-validate`, and other helpful - /// WebAssembly-related commands. - pub fn wabt() -> PathBuf { - c_asset_path().join("wabt-1.0.37.wasmer") - } - - /// A WEBC file containing the WCGI static server. - pub fn static_server() -> PathBuf { - c_asset_path().join("staticserver.webc") - } - - /// The QuickJS interpreter, compiled to a WASI module. - pub fn qjs() -> PathBuf { - c_asset_path().join("qjs.wasm") - } - - pub fn hello() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests") - .join("webc") - .join("hello-0.1.0-665d2ddc-80e6-4845-85d3-4587b1693bb7.webc") - } - - /// The `wasmer.toml` file for QuickJS. - pub fn qjs_wasmer_toml() -> PathBuf { - c_asset_path().join("qjs-wasmer.toml") - } - - /// An executable which calculates fib(40) and exits with no output. - pub fn fib() -> PathBuf { - asset_path().join("fib.wat") - } - - pub fn wat_no_start() -> PathBuf { - asset_path().join("no_start.wat") - } -} - /// A helper that wraps [`Child`] to make sure it gets terminated /// when it is no longer needed. struct JoinableChild { From eb1b7d912f8a1dfea42d366235fd88876b7f73e5 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 12:56:35 +0800 Subject: [PATCH 09/17] Remove --nocapture and --test-threads=1 from the Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 101453e7ef3..6e6046f281f 100644 --- a/Makefile +++ b/Makefile @@ -619,12 +619,12 @@ test-wasi: test-integration-cli: build-wasmer build-capi package-capi-headless package distribution cp ./dist/wasmer.tar.gz ./link.tar.gz rustup target add wasm32-wasi - WASMER_DIR=`pwd`/package $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture --test-threads=1 + WASMER_DIR=`pwd`/package $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli # Before running this in the CI, we need to set up link.tar.gz and /cache/wasmer-[target].tar.gz test-integration-cli-ci: rustup target add wasm32-wasi - $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-cli -- --test-threads=1 --nocapture + $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-cli test-integration-ios: $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-ios From 175cafbd8ba38fb9bc3a1239dff4d28d732fe82e Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 13:57:37 +0800 Subject: [PATCH 10/17] Updated some fixture paths that were missed --- tests/integration/cli/tests/create_exe.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index d7fb8bcacfc..f46753bee29 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -689,7 +689,7 @@ fn test_wasmer_create_exe_pirita_works() { let temp_dir = TempDir::new().unwrap(); let temp_dir = temp_dir.path().to_path_buf(); let python_wasmer_path = temp_dir.join("python.wasmer"); - std::fs::copy(create_exe_python_wasmer(), &python_wasmer_path).unwrap(); + std::fs::copy(fixtures::python(), &python_wasmer_path).unwrap(); let python_exe_output_path = temp_dir.join("python"); let native_target = target_lexicon::HOST; @@ -788,7 +788,7 @@ fn test_cross_compile_python_windows() { let mut cmd = Command::new(get_wasmer_path()); cmd.arg("create-exe"); - cmd.arg(create_exe_python_wasmer()); + cmd.arg(fixtures::python()); cmd.arg("--target"); cmd.arg(t); cmd.arg("-o"); From d06b67c0d49813c5149a838554eb30b6d2d8124f Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 14:09:35 +0800 Subject: [PATCH 11/17] Updated the caching tests to be more robust and not have false-positives because it uses the global cache --- .../src/runtime/module_cache/filesystem.rs | 1 + lib/wasix/src/runtime/resolver/web_source.rs | 2 +- tests/integration/cli/tests/publish.rs | 2 +- tests/integration/cli/tests/run.rs | 112 +++++++++++------- 4 files changed, 71 insertions(+), 46 deletions(-) diff --git a/lib/wasix/src/runtime/module_cache/filesystem.rs b/lib/wasix/src/runtime/module_cache/filesystem.rs index 47f95f837a1..7ac89de9584 100644 --- a/lib/wasix/src/runtime/module_cache/filesystem.rs +++ b/lib/wasix/src/runtime/module_cache/filesystem.rs @@ -111,6 +111,7 @@ impl ModuleCache for FileSystemCache { } temp.persist(&path).map_err(CacheError::other)?; + tracing::debug!(path=%path.display(), "Saved to disk"); Ok(()) } diff --git a/lib/wasix/src/runtime/resolver/web_source.rs b/lib/wasix/src/runtime/resolver/web_source.rs index 275edf6eaf9..c5234368114 100644 --- a/lib/wasix/src/runtime/resolver/web_source.rs +++ b/lib/wasix/src/runtime/resolver/web_source.rs @@ -76,7 +76,7 @@ impl WebSource { // Next we check if we definitely got a cache hit let state = match classify_cache_using_mtime(cache_info, self.retry_period) { Ok(path) => { - tracing::debug!(path=%path.display(), "Cache hit"); + tracing::debug!(path=%path.display(), "Cache hit!"); return Ok(path); } Err(s) => s, diff --git a/tests/integration/cli/tests/publish.rs b/tests/integration/cli/tests/publish.rs index 075eef023b7..7fa05eca45d 100644 --- a/tests/integration/cli/tests/publish.rs +++ b/tests/integration/cli/tests/publish.rs @@ -1,4 +1,4 @@ -use std::{path::PathBuf, process::Stdio}; +use std::process::Stdio; use wasmer_integration_tests_cli::{fixtures, get_wasmer_path}; #[test] diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 4acf3e41271..a97e5af7251 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -2,7 +2,7 @@ use std::{ io::{ErrorKind, Read}, - path::{Path, PathBuf}, + path::Path, process::{Child, Command, Stdio}, time::{Duration, Instant}, }; @@ -32,6 +32,17 @@ static RUST_LOG: Lazy = Lazy::new(|| { } }); +/// A version of `$RUST_LOG` used for checking cache messages. +static CACHE_RUST_LOG: Lazy = Lazy::new(|| { + [ + "wasmer_wasix::runtime::resolver::wapm_source=debug", + "wasmer_wasix::runtime::resolver::web_source=debug", + "wasmer_wasix::runtime::package_loader::builtin_loader=debug", + "wasmer_wasix::runtime::module_cache::filesystem=debug", + ] + .join(",") +}); + /// Ignored on Windows because running vendored packages does not work /// since Windows does not allow `::` characters in filenames (every other OS does) /// @@ -267,104 +278,117 @@ fn run_wasi_works_non_existent() -> anyhow::Result<()> { Ok(()) } -// FIXME: Re-enable. See https://github.com/wasmerio/wasmer/issues/3717 -#[ignore] #[test] fn run_test_caching_works_for_packages() { // we're testing the cache, so we don't want to reuse the current user's // $WASMER_DIR let wasmer_dir = TempDir::new().unwrap(); - let rust_log = [ - "wasmer_wasix::runtime::resolver::wapm_source=debug", - "wasmer_wasix::runtime::package_loader::builtin_loader=debug", - ] - .join(","); let assert = Command::new(get_wasmer_path()) .arg("python/python") - .arg(format!("--mapdir=.:{}", asset_path().display())) + .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("--registry=wasmer.io") - .arg("test.py") - .env("WASMER_DIR", wasmer_dir.path()) - .env("RUST_LOG", &rust_log) + .arg("/app/test.py") + .env("WASMER_CACHE_DIR", wasmer_dir.path()) + .env("RUST_LOG", &*CACHE_RUST_LOG) .assert(); assert .success() - .stderr("Downloading a webc") - .stderr("Querying the GraphQL API"); + .stderr(contains("wapm_source: Querying the GraphQL API")) + .stderr(contains("builtin_loader: Downloading a webc file")) + .stderr(contains("module_cache::filesystem: Saved to disk")); let assert = Command::new(get_wasmer_path()) .arg("python/python") - .arg(format!("--mapdir=.:{}", asset_path().display())) + .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("--registry=wasmer.io") - .arg("test.py") - .env("WASMER_DIR", wasmer_dir.path()) - .env("RUST_LOG", &rust_log) - .assert(); + .arg("/app/test.py") + .env("WASMER_CACHE_DIR", wasmer_dir.path()) + .env("RUST_LOG", &*CACHE_RUST_LOG) + .assert() + .success(); - assert.success().stderr("asdf"); + assert + .stderr(contains("wapm_source: Cache hit!")) + .stderr(contains("builtin_loader: Cache hit!")) + .stderr(contains("module_cache::filesystem: Cache hit!")); } #[test] fn run_test_caching_works_for_packages_with_versions() { + let wasmer_dir = TempDir::new().unwrap(); + let assert = Command::new(get_wasmer_path()) .arg("python/python@0.1.0") .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("/app/test.py") + .env("RUST_LOG", &*CACHE_RUST_LOG) + .env("WASMER_CACHE_DIR", wasmer_dir.path()) .assert() .success(); - assert.stdout("hello\n"); + assert + .success() + .stderr(contains("wapm_source: Querying the GraphQL API")) + .stderr(contains("builtin_loader: Downloading a webc file")) + .stderr(contains("module_cache::filesystem: Saved to disk")); let assert = Command::new(get_wasmer_path()) .arg("python/python@0.1.0") .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("--registry=wasmer.io") .arg("/app/test.py") - .env( - "RUST_LOG", - "wasmer_wasix::runtime::package_loader::builtin_loader=debug", - ) + .env("RUST_LOG", &*CACHE_RUST_LOG) + .env("WASMER_CACHE_DIR", wasmer_dir.path()) .assert(); assert .success() - // it should have ran like normal - .stdout("hello\n") - // we hit the cache while fetching the package - .stderr(contains( - "builtin_loader: Cache hit! pkg.name=\"python\" pkg.version=0.1.0", - )); + .stderr(contains("wapm_source: Cache hit!")) + .stderr(contains("builtin_loader: Cache hit!")) + .stderr(contains("module_cache::filesystem: Cache hit!")); } -// FIXME: Re-enable. See https://github.com/wasmerio/wasmer/issues/3717 -#[ignore] #[test] fn run_test_caching_works_for_urls() { + let wasmer_dir = TempDir::new().unwrap(); + let assert = Command::new(get_wasmer_path()) + .arg("run") .arg("https://wapm.io/python/python") - .arg(format!("--mapdir=.:{}", asset_path().display())) - .arg("test.py") + .arg(format!("--mapdir=/app:{}", asset_path().display())) + .arg("/app/test.py") + .env("RUST_LOG", &*CACHE_RUST_LOG) + .env("WASMER_CACHE_DIR", wasmer_dir.path()) .assert() .success(); - assert.stdout("hello\n"); - - let time = std::time::Instant::now(); + assert + .success() + .stderr(contains("builtin_loader: Downloading a webc file")) + .stderr(contains("module_cache::filesystem: Saved to disk")); let assert = Command::new(get_wasmer_path()) + .arg("run") .arg("https://wapm.io/python/python") - .arg(format!("--mapdir=.:{}", asset_path().display())) - .arg("test.py") + .arg(format!("--mapdir=/app:{}", asset_path().display())) + .arg("/app/test.py") + .env("RUST_LOG", &*CACHE_RUST_LOG) + .env("WASMER_CACHE_DIR", wasmer_dir.path()) .assert() .success(); - assert.stdout("hello\n"); - - // package should be cached - assert!(std::time::Instant::now() - time < std::time::Duration::from_secs(1)); + assert + // Got a cache hit downloading the *.webc file's metadata + .stderr(contains("web_source: Cache hit")) + // Cache hit downloading the *.webc file + .stderr(contains( + r#"builtin_loader: Cache hit! pkg.name="python" pkg.version=0.1.0"#, + )) + // Cache hit compiling the module + .stderr(contains("module_cache::filesystem: Cache hit!")); } // This test verifies that "wasmer run --invoke _start module.wat" From a9c8ec5a620010fcf158dd4ee78549c11d53b34f Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 14:41:02 +0800 Subject: [PATCH 12/17] Update the "wasmer run" integration tests to use wasmer.io and wasmer.wtf --- tests/integration/cli/tests/run.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index a97e5af7251..a67816c2a05 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -70,7 +70,7 @@ fn test_run_customlambda() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.io/ciuser/customlambda") + .arg("https://wasmer.io/ciuser/customlambda") // TODO: this argument should not be necessary later // see https://github.com/wasmerio/wasmer/issues/3514 .arg("customlambda.py") @@ -82,7 +82,7 @@ fn test_run_customlambda() { // Run again to verify the caching let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.io/ciuser/customlambda") + .arg("https://wasmer.io/ciuser/customlambda") // TODO: this argument should not be necessary later // see https://github.com/wasmerio/wasmer/issues/3514 .arg("customlambda.py") @@ -108,14 +108,15 @@ fn run_whoami_works() { let assert = Command::new(get_wasmer_path()) .arg("whoami") - .arg("--registry=wapm.dev") + .arg("--registry=wasmer.wtf") .arg("--token") .arg(&ciuser_token) .assert() .success(); - assert - .stdout("logged into registry \"https://registry.wapm.dev/graphql\" as user \"ciuser\"\n"); + assert.stdout( + "logged into registry \"https://registry.wasmer.wtf/graphql\" as user \"ciuser\"\n", + ); } #[test] @@ -158,7 +159,7 @@ fn test_wasmer_run_pirita_works() { fn test_wasmer_run_pirita_url_works() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.dev/syrusakbary/python") + .arg("https://wasmer.wtf/syrusakbary/python") .arg("--") .arg("-c") .arg("print(\"hello\")") @@ -208,7 +209,7 @@ fn test_wasmer_run_works_with_dir() { #[test] fn test_wasmer_run_works() { let assert = Command::new(get_wasmer_path()) - .arg("https://wapm.io/python/python") + .arg("https://wasmer.io/python/python") .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("test.py") .assert() @@ -219,7 +220,7 @@ fn test_wasmer_run_works() { // same test again, but this time with "wasmer run ..." let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.io/python/python") + .arg("https://wasmer.io/python/python") .arg(format!("--mapdir=.:{}", asset_path().display())) .arg("test.py") .assert() @@ -357,7 +358,7 @@ fn run_test_caching_works_for_urls() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.io/python/python") + .arg("https://wasmer.io/python/python") .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("/app/test.py") .env("RUST_LOG", &*CACHE_RUST_LOG) @@ -372,7 +373,7 @@ fn run_test_caching_works_for_urls() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.io/python/python") + .arg("https://wasmer.io/python/python") .arg(format!("--mapdir=/app:{}", asset_path().display())) .arg("/app/test.py") .env("RUST_LOG", &*CACHE_RUST_LOG) @@ -850,7 +851,7 @@ fn run_quickjs_via_package_name() { .arg("run") .arg("saghul/quickjs") .arg("--entrypoint=quickjs") - .arg("--registry=wapm.io") + .arg("--registry=wasmer.io") .arg("--") .arg("--eval") .arg("console.log('Hello, World!')") @@ -868,7 +869,7 @@ fn run_quickjs_via_package_name() { fn run_quickjs_via_url() { let assert = Command::new(get_wasmer_path()) .arg("run") - .arg("https://wapm.io/saghul/quickjs") + .arg("https://wasmer.io/saghul/quickjs") .arg("--entrypoint=quickjs") .arg("--") .arg("--eval") @@ -894,7 +895,7 @@ fn run_bash_using_coreutils() { .arg("sharrattj/bash") .arg("--entrypoint=bash") .arg("--use=sharrattj/coreutils") - .arg("--registry=wapm.io") + .arg("--registry=wasmer.io") .arg("--") .arg("-c") .arg("ls /bin") From e24c3bafe7addec31e5f8a5b0be8ce1fba04bf38 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 16:03:34 +0800 Subject: [PATCH 13/17] Rework the whoami and login tests to use wasmer.wtf --- tests/integration/cli/tests/login.rs | 68 ++++++++++++++++------------ tests/integration/cli/tests/run.rs | 26 ----------- 2 files changed, 38 insertions(+), 56 deletions(-) diff --git a/tests/integration/cli/tests/login.rs b/tests/integration/cli/tests/login.rs index e06951fd5c8..1dd58b5d51f 100644 --- a/tests/integration/cli/tests/login.rs +++ b/tests/integration/cli/tests/login.rs @@ -1,53 +1,61 @@ -use anyhow::bail; +use assert_cmd::prelude::OutputAssertExt; +use predicates::str::contains; +use tempfile::TempDir; use std::process::Command; use wasmer_integration_tests_cli::get_wasmer_path; #[test] -fn login_works() -> anyhow::Result<()> { +fn login_works() { + let wasmer_dir = TempDir::new().unwrap(); + // running test locally: should always pass since // developers don't have access to WAPM_DEV_TOKEN if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); + return; } let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").expect("WAPM_DEV_TOKEN env var not set"); // Special case: GitHub secrets aren't visible to outside collaborators if wapm_dev_token.is_empty() { - return Ok(()); + return; } - // FIXME: Change the registry to wasmer.wtf and all the associated terms with WAPM - let output = Command::new(get_wasmer_path()) + let assert = Command::new(get_wasmer_path()) .arg("login") - .arg("--registry") - .arg("wapm.dev") + .arg("--registry=wasmer.wtf") .arg(wapm_dev_token) - .output()?; + .env("WASMER_DIR", wasmer_dir.path()) + .assert(); - let stdout = std::str::from_utf8(&output.stdout) - .expect("stdout is not utf8! need to handle arbitrary bytes"); + assert + .success() + .stdout(contains(r#"Login for Wasmer user "ciuser" saved"#)); +} - let stderr = std::str::from_utf8(&output.stderr) - .expect("stderr is not utf8! need to handle arbitrary bytes"); +#[test] +fn run_whoami_works() { + let wasmer_dir = TempDir::new().unwrap(); - if !output.status.success() { - bail!( - "wasmer login failed with: stdout: {}\n\nstderr: {}", - stdout, - stderr - ); + // running test locally: should always pass since + // developers don't have access to WAPM_DEV_TOKEN + if std::env::var("GITHUB_TOKEN").is_err() { + return; } - let stdout_output = std::str::from_utf8(&output.stdout).unwrap(); - let expected = "Done!\n✅ Login for Wasmer user \"ciuser\" saved\n"; - if stdout_output != expected { - println!("expected:"); - println!("{expected}"); - println!("got:"); - println!("{stdout}"); - println!("-----"); - println!("{stderr}"); - panic!("stdout incorrect"); + let ciuser_token = std::env::var("WAPM_DEV_TOKEN").expect("no CIUSER / WAPM_DEV_TOKEN token"); + // Special case: GitHub secrets aren't visible to outside collaborators + if ciuser_token.is_empty() { + return; } - Ok(()) + let assert = Command::new(get_wasmer_path()) + .arg("whoami") + .arg("--registry=wasmer.wtf") + .env("WASMER_TOKEN", &ciuser_token) + .env("WASMER_DIR", wasmer_dir.path()) + .assert() + .success(); + + assert.stdout( + "logged into registry \"https://registry.wasmer.wtf/graphql\" as user \"ciuser\"\n", + ); } diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index a67816c2a05..5265ce416ee 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -92,32 +92,6 @@ fn test_run_customlambda() { assert.stdout("139583862445\n"); } -#[test] -fn run_whoami_works() { - // running test locally: should always pass since - // developers don't have access to WAPM_DEV_TOKEN - if std::env::var("GITHUB_TOKEN").is_err() { - return; - } - - let ciuser_token = std::env::var("WAPM_DEV_TOKEN").expect("no CIUSER / WAPM_DEV_TOKEN token"); - // Special case: GitHub secrets aren't visible to outside collaborators - if ciuser_token.is_empty() { - return; - } - - let assert = Command::new(get_wasmer_path()) - .arg("whoami") - .arg("--registry=wasmer.wtf") - .arg("--token") - .arg(&ciuser_token) - .assert() - .success(); - - assert.stdout( - "logged into registry \"https://registry.wasmer.wtf/graphql\" as user \"ciuser\"\n", - ); -} #[test] fn run_wasi_works() { From 81fdc64c200fcd013f6942a45234c6efcb9d9e2d Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Tue, 27 Jun 2023 16:13:20 +0800 Subject: [PATCH 14/17] Rustfmt --- tests/integration/cli/tests/run.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 5265ce416ee..616c32af455 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -92,7 +92,6 @@ fn test_run_customlambda() { assert.stdout("139583862445\n"); } - #[test] fn run_wasi_works() { let assert = Command::new(get_wasmer_path()) From 6365e023af07728dc8ac4598a6e8da92d174ee4d Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Wed, 28 Jun 2023 13:00:25 +0800 Subject: [PATCH 15/17] Fixed a bug in "wasmer whoami" where we wouldn't respect the --token flag --- lib/cli/src/commands/whoami.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cli/src/commands/whoami.rs b/lib/cli/src/commands/whoami.rs index e6ec1dc2a1c..81bc962ac20 100644 --- a/lib/cli/src/commands/whoami.rs +++ b/lib/cli/src/commands/whoami.rs @@ -12,8 +12,9 @@ impl Whoami { /// Execute `wasmer whoami` pub fn execute(&self) -> Result<(), anyhow::Error> { let registry = self.env.registry_endpoint()?; + let token = self.env.token(); let (registry, username) = - wasmer_registry::whoami(self.env.dir(), Some(registry.as_str()), None)?; + wasmer_registry::whoami(self.env.dir(), Some(registry.as_str()), token.as_deref())?; println!("logged into registry {registry:?} as user {username:?}"); Ok(()) } From 5b45ab47fa76b3c381cbbde7b0c038b80bd2593a Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Wed, 28 Jun 2023 16:19:26 +0800 Subject: [PATCH 16/17] Fixed some unhygienic publish and config tests --- Cargo.lock | 1 + tests/integration/cli/Cargo.toml | 1 + tests/integration/cli/src/assets.rs | 23 +++ tests/integration/cli/tests/config.rs | 270 ++++++++++++------------- tests/integration/cli/tests/publish.rs | 136 +++++-------- 5 files changed, 203 insertions(+), 228 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88bfeb4eb54..b4cda4db232 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5864,6 +5864,7 @@ dependencies = [ "target-lexicon 0.12.10", "tempfile", "tokio", + "wasmer-registry 5.2.0", ] [[package]] diff --git a/tests/integration/cli/Cargo.toml b/tests/integration/cli/Cargo.toml index 363562af66c..4fbe40f9b6b 100644 --- a/tests/integration/cli/Cargo.toml +++ b/tests/integration/cli/Cargo.toml @@ -33,6 +33,7 @@ tar = "0.4.38" flate2 = "1.0.24" dirs = "4.0.0" derivative = { version = "^2" } +wasmer-registry = { path = "../../../lib/registry", default-features = false } [features] default = ["webc_runner"] diff --git a/tests/integration/cli/src/assets.rs b/tests/integration/cli/src/assets.rs index c3882c0c8ed..f6692636d82 100644 --- a/tests/integration/cli/src/assets.rs +++ b/tests/integration/cli/src/assets.rs @@ -150,3 +150,26 @@ pub fn get_repo_root_path() -> Option { } result } + +pub fn get_wasmer_dir() -> Result { + if let Ok(s) = std::env::var("WASMER_DIR") { + Ok(Path::new(&s).to_path_buf()) + } else if let Some(root_dir) = get_repo_root_path().and_then(|root| { + if root.join("package").exists() { + Some(root.join("package")) + } else { + None + } + }) { + Ok(root_dir) + } else { + let home_dir = dirs::home_dir() + .ok_or(anyhow::anyhow!("no home dir"))? + .join(".wasmer"); + if home_dir.exists() { + Ok(home_dir) + } else { + Err(anyhow::anyhow!("no .wasmer home dir")) + } + } +} diff --git a/tests/integration/cli/tests/config.rs b/tests/integration/cli/tests/config.rs index 994382fef23..491ae4b2589 100644 --- a/tests/integration/cli/tests/config.rs +++ b/tests/integration/cli/tests/config.rs @@ -1,58 +1,55 @@ +use std::path::Path; + use assert_cmd::Command; -use std::path::{Path, PathBuf}; -use wasmer_integration_tests_cli::{get_repo_root_path, get_wasmer_path}; - -fn get_wasmer_dir() -> Result { - if let Ok(s) = std::env::var("WASMER_DIR") { - Ok(Path::new(&s).to_path_buf()) - } else if let Some(root_dir) = get_repo_root_path().and_then(|root| { - if root.join("package").exists() { - Some(root.join("package")) - } else { - None - } - }) { - Ok(root_dir) - } else { - let home_dir = dirs::home_dir() - .ok_or(anyhow::anyhow!("no home dir"))? - .join(".wasmer"); - if home_dir.exists() { - Ok(home_dir) - } else { - Err(anyhow::anyhow!("no .wasmer home dir")) - } - } +use predicates::str::contains; +use tempfile::TempDir; +use wasmer_integration_tests_cli::get_wasmer_path; +use wasmer_registry::WasmerConfig; + +fn setup_wasmer_dir() -> TempDir { + let temp = TempDir::new().unwrap(); + + let config_path = WasmerConfig::get_file_location(temp.path()); + WasmerConfig::default().save(&config_path).unwrap(); + + temp +} + +fn contains_path(path: impl AsRef) -> predicates::str::ContainsPredicate { + let expected = path.as_ref().display().to_string(); + contains(expected) +} + +fn wasmer_cmd(temp: &TempDir) -> Command { + let mut cmd = Command::new(get_wasmer_path()); + cmd.env("WASMER_DIR", temp.path()); + cmd } #[test] fn wasmer_config_multiget() { - let wasmer_dir = get_wasmer_dir().unwrap(); + let temp = setup_wasmer_dir(); + let wasmer_dir = temp.path(); + let bin_path = wasmer_dir.join("bin"); let include_path = wasmer_dir.join("include"); - let bin = format!("{}", bin_path.display()); + let bin = bin_path.display().to_string(); let include = format!("-I{}", include_path.display()); - let assert = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--bindir") .arg("--cflags") - .assert(); - - assert + .env("WASMER_DIR", wasmer_dir) + .assert() .success() - .stdout(predicates::str::contains(&bin)) - .stdout(predicates::str::contains(&include)); + .stdout(contains(bin)) + .stdout(contains(include)); } #[test] -fn wasmer_config_error() { - let assert = Command::new(get_wasmer_path()) - .arg("config") - .arg("--bindir") - .arg("--cflags") - .arg("--pkg-config") - .assert(); +fn wasmer_config_conflicting_flags() { + let temp = setup_wasmer_dir(); let expected_1 = if cfg!(windows) { "Usage: wasmer.exe config --bindir --cflags" @@ -60,129 +57,112 @@ fn wasmer_config_error() { "Usage: wasmer config --bindir --cflags" }; - assert - .stderr(predicates::str::contains( + wasmer_cmd(&temp) + .arg("config") + .arg("--bindir") + .arg("--cflags") + .arg("--pkg-config") + .assert() + .stderr(contains( "error: the argument '--bindir' cannot be used with '--pkg-config'", )) - .stderr(predicates::str::contains(expected_1)) - .stderr(predicates::str::contains( - "For more information, try '--help'.", - )); + .stderr(contains(expected_1)) + .stderr(contains("For more information, try '--help'.")); } #[test] -fn config_works() -> anyhow::Result<()> { - let bindir = Command::new(get_wasmer_path()) +fn c_flags() { + let temp = setup_wasmer_dir(); + let wasmer_dir = temp.path(); + + wasmer_cmd(&temp) .arg("config") .arg("--bindir") - .output()?; - - let bin_path = get_wasmer_dir()?.join("bin"); - assert_eq!( - String::from_utf8(bindir.stdout).unwrap(), - format!("{}\n", bin_path.display()) - ); + .assert() + .success() + .stdout(contains_path(temp.path().join("bin"))); - let bindir = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--cflags") - .output()?; - - let include_path = get_wasmer_dir()?.join("include"); - assert_eq!( - String::from_utf8(bindir.stdout).unwrap(), - format!("-I{}\n", include_path.display()) - ); + .assert() + .success() + .stdout(contains(format!( + "-I{}\n", + wasmer_dir.join("include").display() + ))); - let bindir = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--includedir") - .output()?; - - let include_path = get_wasmer_dir()?.join("include"); - assert_eq!( - String::from_utf8(bindir.stdout).unwrap(), - format!("{}\n", include_path.display()) - ); + .assert() + .success() + .stdout(contains_path(wasmer_dir.join("include"))); - let bindir = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--libdir") - .output()?; - - let lib_path = get_wasmer_dir()?.join("lib"); - assert_eq!( - String::from_utf8(bindir.stdout).unwrap(), - format!("{}\n", lib_path.display()) - ); + .assert() + .success() + .stdout(contains_path(wasmer_dir.join("lib"))); - let bindir = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--libs") - .output()?; + .assert() + .stdout(contains(format!( + "-L{} -lwasmer\n", + wasmer_dir.join("lib").display() + ))); - let lib_path = get_wasmer_dir()?.join("lib"); - assert_eq!( - String::from_utf8(bindir.stdout).unwrap(), - format!("-L{} -lwasmer\n", lib_path.display()) - ); - - let bindir = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--prefix") - .output()?; - - let wasmer_dir = get_wasmer_dir()?; - assert_eq!( - String::from_utf8(bindir.stdout).unwrap(), - format!("{}\n", wasmer_dir.display()) - ); + .assert() + .success() + .stdout(contains_path(wasmer_dir)); - let bindir = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("--pkg-config") - .output()?; - - let bin_path = format!("{}", bin_path.display()); - let include_path = format!("{}", include_path.display()); - let lib_path = format!("{}", lib_path.display()); - let wasmer_dir = format!("{}", wasmer_dir.display()); - - let args = vec![ - format!("prefix={wasmer_dir}"), - format!("exec_prefix={bin_path}"), - format!("includedir={include_path}"), - format!("libdir={lib_path}"), + .output() + .unwrap(); + + let pkg_config = vec![ + format!("prefix={}", wasmer_dir.display()), + format!("exec_prefix={}", wasmer_dir.join("bin").display()), + format!("includedir={}", wasmer_dir.join("include").display()), + format!("libdir={}", wasmer_dir.join("lib").display()), format!(""), format!("Name: wasmer"), format!("Description: The Wasmer library for running WebAssembly"), format!("Version: {}", env!("CARGO_PKG_VERSION")), - format!("Cflags: -I{include_path}"), - format!("Libs: -L{lib_path} -lwasmer"), - ]; + format!("Cflags: -I{}", wasmer_dir.join("include").display()), + format!("Libs: -L{} -lwasmer", wasmer_dir.join("lib").display()), + ] + .join("\n"); - let lines = String::from_utf8(bindir.stdout) + assert!(output.status.success()); + let stderr = std::str::from_utf8(&output.stdout) .unwrap() - .lines() - .map(|s| s.trim().to_string()) - .collect::>(); - - assert_eq!(lines, args); + .replace("\r\n", "\n"); + assert_eq!(stderr.trim(), pkg_config.trim()); - let output = Command::new(get_wasmer_path()) + wasmer_cmd(&temp) .arg("config") .arg("--config-path") - .output()?; + .assert() + .success() + .stdout(contains_path(temp.path().join("wasmer.toml"))); +} - let config_path = get_wasmer_dir()?.join("wasmer.toml"); - assert_eq!( - String::from_utf8_lossy(&output.stdout), - format!("{}\n", config_path.display()) - ); +#[test] +fn get_and_set_config_fields() -> anyhow::Result<()> { + let temp = setup_wasmer_dir(); // ---- config get - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("registry.token") @@ -190,7 +170,7 @@ fn config_works() -> anyhow::Result<()> { let original_token = String::from_utf8_lossy(&output.stdout); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("registry.token") @@ -199,7 +179,7 @@ fn config_works() -> anyhow::Result<()> { assert_eq!(String::from_utf8_lossy(&output.stdout), "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("registry.token") @@ -210,7 +190,7 @@ fn config_works() -> anyhow::Result<()> { "abc123\n".to_string() ); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("registry.token") @@ -219,7 +199,7 @@ fn config_works() -> anyhow::Result<()> { assert_eq!(String::from_utf8_lossy(&output.stdout), "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("registry.token") @@ -230,7 +210,7 @@ fn config_works() -> anyhow::Result<()> { format!("{}\n", original_token.to_string().trim()) ); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("registry.url") @@ -238,18 +218,18 @@ fn config_works() -> anyhow::Result<()> { let original_url = String::from_utf8_lossy(&output.stdout); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("registry.url") - .arg("wapm.dev") + .arg("wasmer.wtf") .output()?; let output_str = String::from_utf8_lossy(&output.stdout); assert_eq!(output_str, "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("registry.url") @@ -258,10 +238,10 @@ fn config_works() -> anyhow::Result<()> { let output_str = String::from_utf8_lossy(&output.stdout); assert_eq!( output_str, - "https://registry.wapm.dev/graphql\n".to_string() + "https://registry.wasmer.wtf/graphql\n".to_string() ); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("registry.url") @@ -271,7 +251,7 @@ fn config_works() -> anyhow::Result<()> { let output_str = String::from_utf8_lossy(&output.stdout); assert_eq!(output_str, "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("registry.url") @@ -280,7 +260,7 @@ fn config_works() -> anyhow::Result<()> { let output_str = String::from_utf8_lossy(&output.stdout); assert_eq!(output_str, original_url.to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("telemetry.enabled") @@ -288,7 +268,7 @@ fn config_works() -> anyhow::Result<()> { let original_output = String::from_utf8_lossy(&output.stdout); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("telemetry.enabled") @@ -297,7 +277,7 @@ fn config_works() -> anyhow::Result<()> { assert_eq!(String::from_utf8_lossy(&output.stdout), "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("telemetry.enabled") @@ -308,7 +288,7 @@ fn config_works() -> anyhow::Result<()> { "true\n".to_string() ); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("telemetry.enabled") @@ -317,7 +297,7 @@ fn config_works() -> anyhow::Result<()> { assert_eq!(String::from_utf8_lossy(&output.stdout), "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("telemetry.enabled") @@ -328,7 +308,7 @@ fn config_works() -> anyhow::Result<()> { original_output.to_string() ); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("update-notifications.enabled") @@ -336,7 +316,7 @@ fn config_works() -> anyhow::Result<()> { let original_output = String::from_utf8_lossy(&output.stdout); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("update-notifications.enabled") @@ -345,7 +325,7 @@ fn config_works() -> anyhow::Result<()> { assert_eq!(String::from_utf8_lossy(&output.stdout), "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("update-notifications.enabled") @@ -356,7 +336,7 @@ fn config_works() -> anyhow::Result<()> { "true\n".to_string() ); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("set") .arg("update-notifications.enabled") @@ -365,7 +345,7 @@ fn config_works() -> anyhow::Result<()> { assert_eq!(String::from_utf8_lossy(&output.stdout), "".to_string()); - let output = Command::new(get_wasmer_path()) + let output = wasmer_cmd(&temp) .arg("config") .arg("get") .arg("update-notifications.enabled") diff --git a/tests/integration/cli/tests/publish.rs b/tests/integration/cli/tests/publish.rs index 7fa05eca45d..1b583467c51 100644 --- a/tests/integration/cli/tests/publish.rs +++ b/tests/integration/cli/tests/publish.rs @@ -1,15 +1,15 @@ -use std::process::Stdio; +use assert_cmd::prelude::OutputAssertExt; use wasmer_integration_tests_cli::{fixtures, get_wasmer_path}; #[test] -fn wasmer_publish() -> anyhow::Result<()> { +fn wasmer_publish() { // Only run this test in the CI if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); + return; } let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); - let tempdir = tempfile::tempdir()?; + let tempdir = tempfile::tempdir().unwrap(); let path = tempdir.path(); let username = "ciuser"; @@ -25,47 +25,39 @@ fn wasmer_publish() -> anyhow::Result<()> { .replace("RANDOMVERSION1", &random1) .replace("RANDOMVERSION2", &random2) .replace("RANDOMVERSION3", &random3), - )?; + ) + .unwrap(); let mut cmd = std::process::Command::new(get_wasmer_path()); - cmd.arg("publish"); - cmd.arg("--quiet"); - cmd.arg("--registry"); - cmd.arg("wapm.dev"); - cmd.arg(path); + cmd.arg("publish") + .arg("--quiet") + .arg("--registry=wasmer.wtf") + .arg(path); if let Some(token) = wapm_dev_token { // Special case: GitHub secrets aren't visible to outside collaborators if token.is_empty() { - return Ok(()); + return; } - cmd.arg("--token"); - cmd.arg(token); + cmd.arg("--token").arg(token); } - let output = cmd.stdin(Stdio::null()).output().unwrap(); - - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(stdout, format!("Successfully published package `{username}/largewasmfile@{random1}.{random2}.{random3}`\n"), "failed to publish: {cmd:?}: {stderr}"); - - println!("wasmer publish ok! test done."); - - Ok(()) + cmd.assert().success().stdout(format!( + "Successfully published package `{username}/largewasmfile@{random1}.{random2}.{random3}`\n" + )); } // Runs a full integration test to test that the flow wasmer init - cargo build - // wasmer publish is working #[test] -fn wasmer_init_publish() -> anyhow::Result<()> { +fn wasmer_init_publish() { // Only run this test in the CI if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); + return; } let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); - let tempdir = tempfile::tempdir()?; + let tempdir = tempfile::tempdir().unwrap(); let path = tempdir.path(); let username = "ciuser"; @@ -73,48 +65,33 @@ fn wasmer_init_publish() -> anyhow::Result<()> { let random2 = format!("{}", rand::random::()); let random3 = format!("{}", rand::random::()); - let mut cmd = std::process::Command::new("cargo"); - cmd.arg("init"); - cmd.arg("--bin"); - cmd.arg(path.join("randomversion")); - - let _ = cmd - .stdin(Stdio::null()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .output() - .unwrap(); - - let mut cmd = std::process::Command::new("cargo"); - cmd.arg("build"); - cmd.arg("--release"); - cmd.arg("--target"); - cmd.arg("wasm32-wasi"); - cmd.arg("--manifest-path"); - cmd.arg(path.join("randomversion").join("Cargo.toml")); - - let _ = cmd - .stdin(Stdio::null()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .output() - .unwrap(); + // Create a new Rust project and build it + std::process::Command::new("cargo") + .arg("init") + .arg("--bin") + .arg(path.join("randomversion")) + .assert() + .success(); + std::process::Command::new("cargo") + .arg("build") + .arg("--release") + .arg("--target") + .arg("wasm32-wasi") + .arg("--manifest-path") + .arg(path.join("randomversion").join("Cargo.toml")) + .assert() + .success(); // generate the wasmer.toml - let mut cmd = std::process::Command::new(get_wasmer_path()); - cmd.arg("init"); - cmd.arg("--namespace"); - cmd.arg(username); - cmd.arg("--version"); - cmd.arg(format!("{random1}.{random2}.{random3}")); - cmd.arg(path.join("randomversion")); - - let _ = cmd - .stdin(Stdio::null()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .output() - .unwrap(); + std::process::Command::new(get_wasmer_path()) + .arg("init") + .arg("--namespace") + .arg(username) + .arg("--version") + .arg(format!("{random1}.{random2}.{random3}")) + .arg(path.join("randomversion")) + .assert() + .success(); let s = std::fs::read_to_string(path.join("randomversion").join("wasmer.toml")).unwrap(); @@ -122,29 +99,22 @@ fn wasmer_init_publish() -> anyhow::Result<()> { // publish let mut cmd = std::process::Command::new(get_wasmer_path()); - cmd.arg("publish"); - cmd.arg("--quiet"); - cmd.arg("--registry"); - cmd.arg("wapm.dev"); - cmd.arg(path.join("randomversion")); + cmd.arg("publish") + .arg("--quiet") + .arg("--registry=wasmer.wtf") + .arg(path.join("randomversion")); if let Some(token) = wapm_dev_token { // Special case: GitHub secrets aren't visible to outside collaborators if token.is_empty() { - return Ok(()); + return; } - cmd.arg("--token"); - cmd.arg(token); + cmd.arg("--token").arg(token); } - let output = cmd.stdin(Stdio::null()).output().unwrap(); - - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(stdout, format!("Successfully published package `{username}/randomversion@{random1}.{random2}.{random3}`\n"), "failed to publish: {cmd:?}: {stderr}"); - - println!("wasmer init publish ok! test done."); + let assert = cmd.assert(); - Ok(()) + assert.success().stdout(format!( + "Successfully published package `{username}/randomversion@{random1}.{random2}.{random3}`\n" + )); } From 771a6e9496bce76760ed03d0d1fd7501b28142b3 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Mon, 24 Jul 2023 15:34:28 +0800 Subject: [PATCH 17/17] Add more context to wasi-web errors --- lib/wasi-web/src/common.rs | 64 +++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/lib/wasi-web/src/common.rs b/lib/wasi-web/src/common.rs index c4f787295f3..798076aa5f8 100644 --- a/lib/wasi-web/src/common.rs +++ b/lib/wasi-web/src/common.rs @@ -1,5 +1,6 @@ use std::cell::Cell; +use anyhow::Context; use js_sys::Function; #[allow(unused_imports, dead_code)] use tracing::{debug, error, info, trace, warn}; @@ -157,22 +158,24 @@ pub async fn fetch( } let request = { - let request = Request::new_with_str_and_init(&url, &opts) - .map_err(|_| anyhow::anyhow!("Could not construct request object"))?; + let request = Request::new_with_str_and_init(url, &opts) + .map_err(js_error) + .context("Could not construct request object")?; let set_headers = request.headers(); for (name, val) in headers.iter() { let val = String::from_utf8_lossy(val.as_bytes()); - set_headers.set(name.as_str(), &val).map_err(|_| { - anyhow::anyhow!("could not apply request header: '{name}': '{val}'") - })?; + set_headers + .set(name.as_str(), &val) + .map_err(js_error) + .with_context(|| format!("could not apply request header: '{name}': '{val}'"))?; } request }; - let resp_value = match fetch_internal(&request).await.ok() { - Some(a) => a, - None => { + let resp_value = match fetch_internal(&request).await { + Ok(a) => a, + Err(e) => { // If the request failed it may be because of CORS so if a cors proxy // is configured then try again with the cors proxy let url_store; @@ -180,25 +183,28 @@ pub async fn fetch( url_store = format!("https://{}/{}", cors_proxy, url); url_store.as_str() } else { - // TODO: more descriptive error. - return Err(anyhow::anyhow!("Could not fetch '{url}'")); + return Err(js_error(e).context(format!("Could not fetch '{url}'"))); }; let request = Request::new_with_str_and_init(url, &opts) - .map_err(|_| anyhow::anyhow!("Could not construct request for url '{url}'"))?; + .map_err(js_error) + .with_context(|| format!("Could not construct request for url '{url}'"))?; let set_headers = request.headers(); for (name, val) in headers.iter() { let value = String::from_utf8_lossy(val.as_bytes()); - set_headers.set(name.as_str(), &value).map_err(|_| { - anyhow::anyhow!("Could not apply request header: '{name}': '{value}'") - })?; + set_headers + .set(name.as_str(), &value) + .map_err(js_error) + .with_context(|| { + anyhow::anyhow!("Could not apply request header: '{name}': '{value}'") + })?; } - fetch_internal(&request).await.map_err(|_| { - // TODO: more descriptive error. - anyhow::anyhow!("Could not fetch '{url}'") - })? + fetch_internal(&request) + .await + .map_err(js_error) + .with_context(|| anyhow::anyhow!("Could not fetch '{url}'"))? } }; assert!(resp_value.is_instance_of::()); @@ -215,6 +221,20 @@ pub async fn fetch( Ok(resp) } +/// Try to extract the most appropriate error message from a [`JsValue`], +/// falling back to a generic error message. +fn js_error(value: JsValue) -> anyhow::Error { + if let Some(e) = value.dyn_ref::() { + anyhow::Error::msg(String::from(e.message())) + } else if let Some(obj) = value.dyn_ref::() { + return anyhow::Error::msg(String::from(obj.to_string())); + } else if let Some(s) = value.dyn_ref::() { + return anyhow::Error::msg(String::from(s)); + } else { + anyhow::Error::msg("An unknown error occurred") + } +} + /* pub async fn fetch_data( url: &str, @@ -231,10 +251,10 @@ pub async fn fetch_data( pub async fn get_response_data(resp: Response) -> Result, anyhow::Error> { let resp = { JsFuture::from(resp.array_buffer().unwrap()) }; - let arrbuff_value = resp.await.map_err(|_| { - // TODO: forward error message - anyhow::anyhow!("Could not retrieve response body") - })?; + let arrbuff_value = resp + .await + .map_err(js_error) + .with_context(|| format!("Could not retrieve response body"))?; assert!(arrbuff_value.is_instance_of::()); //let arrbuff: js_sys::ArrayBuffer = arrbuff_value.dyn_into().unwrap();