diff --git a/Cargo.lock b/Cargo.lock index c8c56ec17aae..946b4a90c5b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1320,7 +1320,7 @@ checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.13", "winapi", ] @@ -1499,9 +1499,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -1943,6 +1943,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "maybe-owned" version = "0.3.4" @@ -2170,16 +2179,6 @@ dependencies = [ "pretty_env_logger", ] -[[package]] -name = "os_pipe" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb233f06c2307e1f5ce2ecad9f8121cffbbee2c95428f44ea85222e460d0d213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "os_str_bytes" version = "6.0.0" @@ -2217,7 +2216,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.13", "smallvec", "winapi", ] @@ -2600,6 +2599,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -2607,7 +2615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom 0.2.6", - "redox_syscall", + "redox_syscall 0.2.13", "thiserror", ] @@ -2641,6 +2649,9 @@ name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] [[package]] name = "regex-syntax" @@ -2660,15 +2671,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "ring" version = "0.16.20" @@ -3066,16 +3068,15 @@ checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" [[package]] name = "tempfile" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", ] [[package]] @@ -3097,6 +3098,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "test-log" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.92", +] + [[package]] name = "test-programs" version = "0.0.0" @@ -3105,21 +3117,23 @@ dependencies = [ "cap-std", "cargo_metadata", "cfg-if", + "heck", "http", "http-body", "http-body-util", "hyper", - "os_pipe", - "target-lexicon", + "lazy_static", "tempfile", + "test-log", "tokio", + "tracing", "tracing-subscriber", "wasi-cap-std-sync", "wasi-common", "wasmtime", "wasmtime-wasi", "wasmtime-wasi-http", - "wat", + "wit-component 0.9.0", ] [[package]] @@ -3284,8 +3298,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" dependencies = [ + "lazy_static", + "matchers", + "regex", "sharded-slab", "thread_local", + "tracing", "tracing-core", ] @@ -3536,6 +3554,14 @@ dependencies = [ "zeroize", ] +[[package]] +name = "wasi-http-tests" +version = "0.0.0" +dependencies = [ + "anyhow", + "wit-bindgen", +] + [[package]] name = "wasi-preview1-component-adapter" version = "10.0.0" @@ -3547,6 +3573,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasi-tests" +version = "0.0.0" +dependencies = [ + "libc", + "once_cell", + "wasi 0.11.0+wasi-snapshot-preview1", +] + [[package]] name = "wasi-tokio" version = "10.0.0" @@ -3658,6 +3693,19 @@ dependencies = [ "wasmparser 0.104.0", ] +[[package]] +name = "wasm-metadata" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e6532071b112df81d756fabafab8cc882b84ae3d6ce9b90f3d90c80e4abe05" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "wasm-encoder 0.27.0", + "wasmparser 0.105.0", +] + [[package]] name = "wasm-mutate" version = "0.2.25" @@ -4672,7 +4720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bc1b5a6e87f16491f2297f75312dc0fb354f8c88c8bece53ea0d3167fc98867" dependencies = [ "anyhow", - "wit-component", + "wit-component 0.8.2", "wit-parser", ] @@ -4683,10 +4731,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7946a66f1132d3322c29de9d28097bd263f67e1e0909054f91253aa103cdf8be" dependencies = [ "heck", - "wasm-metadata", + "wasm-metadata 0.5.0", "wit-bindgen-core", "wit-bindgen-rust-lib", - "wit-component", + "wit-component 0.8.2", ] [[package]] @@ -4710,7 +4758,7 @@ dependencies = [ "syn 2.0.16", "wit-bindgen-core", "wit-bindgen-rust", - "wit-component", + "wit-component 0.8.2", ] [[package]] @@ -4725,11 +4773,28 @@ dependencies = [ "log", "url", "wasm-encoder 0.26.0", - "wasm-metadata", + "wasm-metadata 0.5.0", "wasmparser 0.104.0", "wit-parser", ] +[[package]] +name = "wit-component" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3cc435c15009f80d5e114d0dd3792959171f1fc28be2418e0f570d83b925a33" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "indexmap", + "log", + "url", + "wasm-encoder 0.27.0", + "wasm-metadata 0.6.0", + "wasmparser 0.105.0", + "wit-parser", +] + [[package]] name = "wit-parser" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index 4a60137e7269..bf442d483428 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,8 +54,8 @@ rustix = { workspace = true, features = ["mm", "param"] } wasmtime = { workspace = true, features = ['component-model', 'async', 'default', 'winch'] } env_logger = { workspace = true } log = { workspace = true } -filecheck = "0.5.0" -tempfile = "3.1.0" +filecheck = { workspace = true } +tempfile = { workspace = true } test-programs = { path = "crates/test-programs" } wasmtime-runtime = { workspace = true } tokio = { version = "1.8.0", features = ["rt", "time", "macros", "rt-multi-thread"] } @@ -97,6 +97,8 @@ members = [ "crates/cli-flags", "crates/environ/fuzz", "crates/jit-icache-coherence", + "crates/test-programs/wasi-tests", + "crates/test-programs/wasi-http-tests", "crates/wasi-preview1-component-adapter", "crates/wasi-preview1-component-adapter/verify", "crates/winch", @@ -179,8 +181,21 @@ winch-test-macros = { path = "winch/test-macros" } wasi-preview1-component-adapter = { path = "crates/wasi-preview1-component-adapter" } byte-array-literals = { path = "crates/wasi-preview1-component-adapter/byte-array-literals" } +# Bytecode Alliance maintained dependencies: +# --------------------------- +regalloc2 = "0.8.1" + +# cap-std family: target-lexicon = { version = "0.12.3", default-features = false, features = ["std"] } -anyhow = "1.0.22" +cap-std = "1.0.0" +cap-rand = "1.0.0" +io-lifetimes = { version = "1.0.0", default-features = false } +rustix = "0.37.13" + +# wit-bindgen: +wit-bindgen = "0.6.0" + +# wasm-tools family: wasmparser = "0.105.0" wat = "1.0.64" wast = "58.0.0" @@ -189,20 +204,21 @@ wasm-encoder = "0.27.0" wasm-smith = "0.12.8" wasm-mutate = "0.2.25" wit-parser = "0.7.1" +wit-component = "0.9.0" + +# Non-Bytecode Alliance maintained dependencies: +# -------------------------- +object = { version = "0.30.3", default-features = false, features = ['read_core', 'elf', 'std'] } +gimli = { version = "0.27.0", default-features = false, features = ['read', 'std'] } +anyhow = "1.0.22" windows-sys = "0.48.0" env_logger = "0.10" -rustix = "0.37.13" log = { version = "0.4.8", default-features = false } -object = { version = "0.30.3", default-features = false, features = ['read_core', 'elf', 'std'] } -gimli = { version = "0.27.0", default-features = false, features = ['read', 'std'] } clap = { version = "3.2.0", features = ["color", "suggestions", "derive"] } hashbrown = "0.13.2" -cap-std = "1.0.0" -cap-rand = "1.0.0" capstone = "0.9.0" once_cell = "1.12.0" smallvec = { version = "1.6.1", features = ["union"] } -io-lifetimes = { version = "1.0.0", default-features = false } tracing = "0.1.26" bitflags = "1.2" thiserror = "1.0.15" @@ -214,8 +230,10 @@ serde = "1.0.94" serde_json = "1.0.80" glob = "0.3.0" libfuzzer-sys = "0.4.0" -regalloc2 = "0.8.1" walkdir = "2.3.3" +cfg-if = "1.0" +tempfile = "3.1.0" +filecheck = "0.5.0" [features] default = [ diff --git a/ci/run-tests.sh b/ci/run-tests.sh index 67e53eb87b51..f748b0d8571f 100755 --- a/ci/run-tests.sh +++ b/ci/run-tests.sh @@ -2,9 +2,10 @@ cargo test \ --features "test-programs/test_programs" \ - --features "test-programs/test_programs_http" \ --features wasi-threads \ --workspace \ --exclude 'wasmtime-wasi-*' \ --exclude wasi-crypto \ + --exclude wasi-tests \ + --exclude wasi-http-tests \ $@ diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index c94f0f40f501..03bcba84929a 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -19,7 +19,7 @@ path = "tests/filetests.rs" harness = false [dependencies] -cfg-if = "1.0" +cfg-if = { workspace = true } cranelift-codegen = { workspace = true, features = ["disas"] } cranelift-entity = { workspace = true } cranelift-interpreter = { workspace = true } @@ -32,7 +32,7 @@ cranelift-module = { workspace = true } cranelift-object = { workspace = true } cranelift-jit = { workspace = true } cranelift = { workspace = true } -filecheck = "0.5.0" +filecheck = { workspace = true } log = { workspace = true } termcolor = "1.1.2" capstone = { workspace = true, optional = true } diff --git a/cranelift/filetests/Cargo.toml b/cranelift/filetests/Cargo.toml index 789dfa5c66a1..4ff5037bdf7f 100644 --- a/cranelift/filetests/Cargo.toml +++ b/cranelift/filetests/Cargo.toml @@ -19,7 +19,7 @@ cranelift-jit = { workspace = true, features = ["selinux-fix"] } cranelift-module = { workspace = true } cranelift-control = { workspace = true } file-per-thread-logger = "0.1.2" -filecheck = "0.5.0" +filecheck = { workspace = true } gimli = { workspace = true } log = { workspace = true } num_cpus = "1.8.0" diff --git a/crates/asm-macros/Cargo.toml b/crates/asm-macros/Cargo.toml index b8b667573f05..8b9d96cc9ae3 100644 --- a/crates/asm-macros/Cargo.toml +++ b/crates/asm-macros/Cargo.toml @@ -10,4 +10,4 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cfg-if = "1" +cfg-if = { workspace = true } diff --git a/crates/fiber/Cargo.toml b/crates/fiber/Cargo.toml index 1ba28127520e..e2acc6c0f444 100644 --- a/crates/fiber/Cargo.toml +++ b/crates/fiber/Cargo.toml @@ -14,7 +14,7 @@ edition.workspace = true links = "wasmtime-fiber-shims" [dependencies] -cfg-if = "1.0" +cfg-if = { workspace = true } [target.'cfg(unix)'.dependencies] rustix = { workspace = true, features = ["mm", "param"] } diff --git a/crates/jit-icache-coherence/Cargo.toml b/crates/jit-icache-coherence/Cargo.toml index 3347556171e2..8500c7924a77 100644 --- a/crates/jit-icache-coherence/Cargo.toml +++ b/crates/jit-icache-coherence/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/bytecodealliance/wasmtime" edition.workspace = true [dependencies] -cfg-if = "1.0" +cfg-if = { workspace = true } [target.'cfg(target_os = "windows")'.dependencies.windows-sys] workspace = true diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 90a11f87e55a..a90737b47fcd 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -16,7 +16,7 @@ wasmtime-jit-debug = { workspace = true, features = ["perf_jitdump"], optional = wasmtime-runtime = { workspace = true } target-lexicon = { workspace = true } anyhow = { workspace = true } -cfg-if = "1.0" +cfg-if = { workspace = true } gimli = { workspace = true } object = { workspace = true } serde = { version = "1.0.94", features = ["derive"] } diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 0ff570f4cba4..279bc0b72e3b 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -19,7 +19,7 @@ libc = { version = "0.2.112", default-features = false } log = { workspace = true } memoffset = "0.8.0" indexmap = "1.0.2" -cfg-if = "1.0" +cfg-if = { workspace = true } rand = { version = "0.8.3", features = ['small_rng'] } anyhow = { workspace = true } memfd = "0.6.2" diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index a45cb7587944..d26664790c44 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -8,22 +8,26 @@ publish = false license = "Apache-2.0 WITH LLVM-exception" [build-dependencies] -cfg-if = "1.0" +cfg-if = { workspace = true } cargo_metadata = "0.15.3" +wit-component = { workspace = true } +heck = { workspace = true } [dev-dependencies] +anyhow = { workspace = true } +tempfile = { workspace = true } +test-log = { version = "0.2", default-features = false, features = ["trace"] } +tracing = { workspace = true } +tracing-subscriber = { version = "0.3.1", default-features = false, features = ['fmt', 'env-filter'] } +lazy_static = "1" +wasmtime = { workspace = true, features = ['cranelift', 'component-model'] } + wasi-common = { workspace = true } wasi-cap-std-sync = { workspace = true } -wasmtime = { workspace = true, features = ['cranelift'] } wasmtime-wasi = { workspace = true, features = ["tokio"] } -target-lexicon = { workspace = true } -tracing-subscriber = { version = "0.3.1", default-features = false, features = ['fmt'] } -tempfile = "3.1.0" -os_pipe = "0.9" -anyhow = { workspace = true } -wat = { workspace = true } cap-std = { workspace = true } -tokio = { version = "1.8.0", features = ["net", "rt-multi-thread"] } +tokio = { version = "1.8.0", features = ["net", "rt-multi-thread", "macros"] } + wasmtime-wasi-http = { workspace = true } hyper = { version = "1.0.0-rc.3", features = ["full"] } http = { version = "0.2.9" } diff --git a/crates/test-programs/build.rs b/crates/test-programs/build.rs index 60c010aa01bd..e96e754a2df8 100644 --- a/crates/test-programs/build.rs +++ b/crates/test-programs/build.rs @@ -1,365 +1,239 @@ -#![allow(dead_code, unused_imports)] -//! Build program to generate a program which runs all the testsuites. -//! -//! By generating a separate `#[test]` test for each file, we allow cargo test -//! to automatically run the files in parallel. -use std::fs::{read_dir, File}; -use std::io::{self, Write}; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +#![cfg_attr(not(feature = "test_programs"), allow(dead_code))] + +use heck::ToSnakeCase; +use std::env; +use std::fs; +use std::path::PathBuf; +use std::process::Command; +use wit_component::ComponentEncoder; fn main() { #[cfg(feature = "test_programs")] - wasi_tests::build_and_generate_tests(); - #[cfg(feature = "test_programs_http")] - wasi_http_tests::build_and_generate_tests(); + build_and_generate_tests(); } -fn build_tests(testsuite: &str, out_dir: &Path) -> io::Result> { - let mut cmd = Command::new("cargo"); - cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "1"); - cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); - cmd.args(&[ - "build", - "--release", - "--target=wasm32-wasi", - "--target-dir", - out_dir.to_str().unwrap(), - ]) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .current_dir(testsuite); - let output = cmd.output()?; +fn build_and_generate_tests() { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // Not needed yet, but will be shortly: + //let reactor_adapter = build_adapter("reactor", &[]); + + let command_adapter = build_adapter( + &out_dir, + "command", + &["--no-default-features", "--features=command"], + ); + + println!("cargo:rerun-if-changed=./wasi-tests"); + println!("cargo:rerun-if-changed=./wasi-http-tests"); + + // Build the test programs: + let mut cmd = Command::new("rustup"); + cmd.arg("run") + .arg("stable") + .arg("cargo") + .arg("build") + .arg("--target=wasm32-wasi") + .arg("--package=wasi-tests") + .arg("--package=wasi-http-tests") + .env("CARGO_TARGET_DIR", &out_dir) + .env("CARGO_PROFILE_DEV_DEBUG", "1") + .env_remove("CARGO_ENCODED_RUSTFLAGS"); + let status = cmd.status().unwrap(); + assert!(status.success()); + + let meta = cargo_metadata::MetadataCommand::new().exec().unwrap(); + + modules_rs(&meta, "wasi-tests", "bin", &out_dir); + components_rs(&meta, "wasi-tests", "bin", &command_adapter, &out_dir); + + modules_rs(&meta, "wasi-http-tests", "bin", &out_dir); + // FIXME Unsure why this is broken at the moment: + //components_rs(&meta, "wasi-http-tests", "bin", &command_adapter, &out_dir); +} - let status = output.status; - if !status.success() { - panic!( - "Building tests failed: exit code: {}", - status.code().unwrap() +// Creates an `${out_dir}/${package}_modules.rs` file that exposes a `get_module(&str) -> Module`, +// and a contains a `use self::{module} as _;` for each module that ensures that the user defines +// a symbol (ideally a #[test]) corresponding to each module. +fn modules_rs(meta: &cargo_metadata::Metadata, package: &str, kind: &str, out_dir: &PathBuf) { + let modules = targets_in_package(meta, package, kind) + .into_iter() + .map(|stem| { + ( + stem.clone(), + out_dir + .join("wasm32-wasi") + .join("debug") + .join(format!("{stem}.wasm")) + .as_os_str() + .to_str() + .unwrap() + .to_string(), + ) + }) + .collect::>(); + + let mut decls = String::new(); + let mut cases = String::new(); + let mut uses = String::new(); + for (stem, file) in modules { + let global = format!("{}_MODULE", stem.to_uppercase()); + // Load the module from disk only once, in case it is used many times: + decls += &format!( + " + lazy_static::lazy_static!{{ + static ref {global}: wasmtime::Module = {{ + wasmtime::Module::from_file(&ENGINE, {file:?}).unwrap() + }}; + }} + " ); + // Match the stem str literal to the module. Cloning is just a ref count incr. + cases += &format!("{stem:?} => {global}.clone(),\n"); + // Statically ensure that the user defines a function (ideally a #[test]) for each stem. + uses += &format!("#[allow(unused_imports)] use self::{stem} as _;\n"); } - let meta = cargo_metadata::MetadataCommand::new() - .manifest_path(PathBuf::from(testsuite).join("Cargo.toml")) - .exec() - .expect("cargo metadata"); - - Ok(meta - .packages - .iter() - .find(|p| p.name == testsuite) - .unwrap() - .targets - .iter() - .filter(|t| t.kind == ["bin"]) - .map(|t| t.name.clone()) - .collect::>()) + std::fs::write( + out_dir.join(&format!("{}_modules.rs", package.to_snake_case())), + format!( + " + {decls} + pub fn get_module(s: &str) -> wasmtime::Module {{ + match s {{ + {cases} + _ => panic!(\"no such module: {{}}\", s), + }} + }} + {uses} + " + ), + ) + .unwrap(); } -#[allow(dead_code)] -fn test_directory( - out: &mut File, - test_binaries: &[String], - testsuite: &str, - runtime: &str, - out_dir: &Path, - mut write_testsuite_tests: impl FnMut(&mut File, &Path, &str) -> io::Result<()>, -) -> io::Result<()> { - writeln!( - out, - "mod {} {{", - Path::new(testsuite) - .file_stem() - .expect("testsuite filename should have a stem") - .to_str() - .expect("testsuite filename should be representable as a string") - .replace("-", "_") - )?; - writeln!( - out, - " use super::{{runtime::{} as runtime, utils, setup_log}};", - runtime - )?; - for test_binary in test_binaries { - let binary_path = out_dir - .join("wasm32-wasi") - .join("release") - .join(format!("{}.wasm", test_binary.replace("-", "_"))); - write_testsuite_tests(out, &binary_path, testsuite)?; +// Build the WASI Preview 1 adapter, and get the binary: +fn build_adapter(out_dir: &PathBuf, name: &str, features: &[&str]) -> Vec { + println!("cargo:rerun-if-changed=../wasi-preview1-component-adapter"); + let mut cmd = Command::new("cargo"); + cmd.arg("build") + .arg("--release") + .arg("--package=wasi-preview1-component-adapter") + .arg("--target=wasm32-unknown-unknown") + .env("CARGO_TARGET_DIR", out_dir) + .env_remove("CARGO_ENCODED_RUSTFLAGS"); + for f in features { + cmd.arg(f); } - writeln!(out, "}}")?; - Ok(()) -} + let status = cmd.status().unwrap(); + assert!(status.success()); -#[cfg(feature = "test_programs")] -mod wasi_tests { - use super::*; - use std::env; + let adapter = out_dir.join(format!("wasi_preview1_component_adapter.{name}.wasm")); + std::fs::copy( + out_dir + .join("wasm32-unknown-unknown") + .join("release") + .join("wasi_preview1_component_adapter.wasm"), + &adapter, + ) + .unwrap(); + println!("wasi {name} adapter: {:?}", &adapter); + fs::read(&adapter).unwrap() +} - pub(super) fn build_and_generate_tests() { - // Validate if any of test sources are present and if they changed - // This should always work since there is no submodule to init anymore - let bin_tests = read_dir("wasi-tests/src/bin").unwrap(); - for test in bin_tests { - if let Ok(test_file) = test { - let test_file_path = test_file - .path() - .into_os_string() - .into_string() - .expect("test file path"); - println!("cargo:rerun-if-changed={}", test_file_path); - } - } - println!("cargo:rerun-if-changed=wasi-tests/Cargo.toml"); - println!("cargo:rerun-if-changed=wasi-tests/src/lib.rs"); - // Build tests to OUT_DIR (target/*/build/wasi-common-*/out/wasm32-wasi/release/*.wasm) - let out_dir = PathBuf::from( - env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"), +// Builds components out of modules, and creates an `${out_dir}/${package}_component.rs` file that +// exposes a `get_component(&str) -> Component` +// and a contains a `use self::{component} as _;` for each module that ensures that the user defines +// a symbol (ideally a #[test]) corresponding to each component. +fn components_rs( + meta: &cargo_metadata::Metadata, + package: &str, + kind: &str, + adapter: &[u8], + out_dir: &PathBuf, +) { + let mut decls = String::new(); + let mut cases = String::new(); + let mut uses = String::new(); + for target_name in targets_in_package(&meta, package, kind) { + let stem = target_name.to_snake_case(); + let file = compile_component(&stem, out_dir, adapter); + + let global = format!("{}_COMPONENT", stem.to_uppercase()); + decls += &format!( + " + lazy_static::lazy_static!{{ + static ref {global}: wasmtime::component::Component = {{ + wasmtime::component::Component::from_file(&ENGINE, {file:?}).unwrap() + }}; + }} + " ); - let mut out = - File::create(out_dir.join("wasi_tests.rs")).expect("error generating test source file"); - let test_binaries = build_tests("wasi-tests", &out_dir).expect("building tests"); - test_directory( - &mut out, - &test_binaries, - "wasi-cap-std-sync", - "cap_std_sync", - &out_dir, - write_testsuite_tests, - ) - .expect("generating wasi-cap-std-sync tests"); - test_directory( - &mut out, - &test_binaries, - "wasi-tokio", - "tokio", - &out_dir, - write_testsuite_tests, - ) - .expect("generating wasi-tokio tests"); - } - - fn write_testsuite_tests(out: &mut File, path: &Path, testsuite: &str) -> io::Result<()> { - let stemstr = path - .file_stem() - .expect("file_stem") - .to_str() - .expect("to_str"); - - writeln!(out, " #[test]")?; - let test_fn_name = stemstr.replace("-", "_"); - if ignore(testsuite, &test_fn_name) { - writeln!(out, " #[ignore]")?; - } - writeln!(out, " fn r#{}() -> anyhow::Result<()> {{", test_fn_name,)?; - writeln!(out, " setup_log();")?; - writeln!( - out, - " let path = std::path::Path::new(r#\"{}\"#);", - path.display() - )?; - writeln!(out, " let data = wat::parse_file(path)?;")?; - writeln!( - out, - " let bin_name = utils::extract_exec_name_from_path(path)?;" - )?; - let workspace = if no_preopens(testsuite, stemstr) { - "None" - } else { - writeln!( - out, - " let workspace = utils::prepare_workspace(&bin_name)?;" - )?; - "Some(workspace.path())" - }; - writeln!( - out, - " runtime::{}(&data, &bin_name, {})", - if inherit_stdio(testsuite, stemstr) { - "instantiate_inherit_stdio" - } else { - "instantiate" - }, - workspace, - )?; - writeln!(out, " }}")?; - writeln!(out)?; - Ok(()) - } - - fn ignore(testsuite: &str, name: &str) -> bool { - match testsuite { - "wasi-cap-std-sync" => cap_std_sync_ignore(name), - "wasi-virtfs" => virtfs_ignore(name), - "wasi-tokio" => tokio_ignore(name), - _ => panic!("unknown test suite: {}", testsuite), - } - } - - #[cfg(not(windows))] - /// Ignore tests that aren't supported yet. - fn cap_std_sync_ignore(name: &str) -> bool { - [ - // Trailing slash related bugs: - "path_rename_file_trailing_slashes", - "remove_directory_trailing_slashes", - ] - .contains(&name) + cases += &format!("{stem:?} => {global}.clone(),\n"); + uses += &format!("use self::{stem} as _;\n"); } - #[cfg(windows)] - /// Ignore tests that aren't supported yet. - fn cap_std_sync_ignore(name: &str) -> bool { - [ - // Trailing slash related bugs - "interesting_paths", - "path_rename_file_trailing_slashes", - "remove_directory_trailing_slashes", - ] - .contains(&name) - } - - /// Tokio should support the same things as cap_std_sync - fn tokio_ignore(name: &str) -> bool { - cap_std_sync_ignore(name) - } - /// Virtfs barely works at all and is not suitable for any purpose - fn virtfs_ignore(name: &str) -> bool { - [ - "dangling_fd", - "dangling_symlink", - "directory_seek", - "fd_advise", - "fd_filestat_set", - "fd_flags_set", - "fd_readdir", - "file_allocate", - "file_pread_pwrite", - "file_seek_tell", - "file_truncation", - "file_unbuffered_write", - "interesting_paths", - "isatty", - "nofollow_errors", - "path_filestat", - "path_link", - "path_open_create_existing", - "path_open_dirfd_not_dir", - "path_open_read_without_rights", - "path_rename", - "path_rename_dir_trailing_slashes", - "path_rename_file_trailing_slashes", - "path_symlink_trailing_slashes", - "poll_oneoff", - "poll_oneoff_stdio", - "readlink", - "remove_directory_trailing_slashes", - "remove_nonempty_directory", - "renumber", - "symlink_create", - "symlink_filestat", - "symlink_loop", - "truncation_rights", - "unlink_file_trailing_slashes", - ] - .contains(&name) - } - - /// Mark tests which do not require preopens - fn no_preopens(testsuite: &str, name: &str) -> bool { - if testsuite.starts_with("wasi-") { - match name { - "big_random_buf" => true, - "clock_time_get" => true, - "sched_yield" => true, - "poll_oneoff_stdio" => true, - _ => false, - } - } else { - panic!("unknown test suite {}", testsuite) - } - } - - /// Mark tests which require inheriting parent process stdio - fn inherit_stdio(testsuite: &str, name: &str) -> bool { - match testsuite { - "wasi-cap-std-sync" | "wasi-tokio" => match name { - "poll_oneoff_stdio" => true, - _ => false, - }, - "wasi-virtfs" => false, - _ => panic!("unknown test suite {}", testsuite), - } - } + std::fs::write( + out_dir.join(&format!("{}_components.rs", package.to_snake_case())), + format!( + " + {decls} + pub fn get_component(s: &str) -> wasmtime::component::Component {{ + match s {{ + {cases} + _ => panic!(\"no such component: {{}}\", s), + }} + }} + {uses} + " + ), + ) + .unwrap(); } -#[cfg(feature = "test_programs_http")] -mod wasi_http_tests { - use super::*; - use std::env; - - pub(super) fn build_and_generate_tests() { - // Validate if any of test sources are present and if they changed - // This should always work since there is no submodule to init anymore - let bin_tests = read_dir("wasi-http-tests/src/bin").unwrap(); - for test in bin_tests { - if let Ok(test_file) = test { - let test_file_path = test_file - .path() - .into_os_string() - .into_string() - .expect("test file path"); - println!("cargo:rerun-if-changed={}", test_file_path); - } - } - println!("cargo:rerun-if-changed=wasi-http-tests/Cargo.toml"); - println!("cargo:rerun-if-changed=wasi-http-tests/src/lib.rs"); - // Build tests to OUT_DIR (target/*/build/wasi-common-*/out/wasm32-wasi/release/*.wasm) - let out_dir = PathBuf::from( - env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"), - ); - let mut out = File::create(out_dir.join("wasi_http_tests.rs")) - .expect("error generating test source file"); - - let test_binaries = build_tests("wasi-http-tests", &out_dir).expect("building tests"); - test_directory( - &mut out, - &test_binaries, - "wasi-http-tests", - "wasi_http_tests", - &out_dir, - write_testsuite_tests, - ) - .expect("generating wasi-cap-std-sync tests"); - } - - fn write_testsuite_tests(out: &mut File, path: &Path, _testsuite: &str) -> io::Result<()> { - let stemstr = path - .file_stem() - .expect("file_stem") - .to_str() - .expect("to_str"); +// Compile a component, return the path of the binary: +fn compile_component(stem: &str, out_dir: &PathBuf, adapter: &[u8]) -> PathBuf { + let file = out_dir + .join("wasm32-wasi") + .join("debug") + .join(format!("{stem}.wasm")); + let module = fs::read(&file).expect("read wasm module"); + let component = ComponentEncoder::default() + .module(module.as_slice()) + .unwrap() + .validate(true) + .adapter("wasi_snapshot_preview1", adapter) + .unwrap() + .encode() + .expect(&format!( + "module {:?} can be translated to a component", + file + )); + let component_path = out_dir.join(format!("{}.component.wasm", &stem)); + fs::write(&component_path, component).expect("write component to disk"); + component_path +} - writeln!(out, " #[test]")?; - let test_fn_name = stemstr.replace("-", "_"); - writeln!(out, " fn r#{}() -> anyhow::Result<()> {{", test_fn_name,)?; - writeln!(out, " setup_log();")?; - writeln!( - out, - " let path = std::path::Path::new(r#\"{}\"#);", - path.display() - )?; - writeln!(out, " let data = wat::parse_file(path)?;")?; - writeln!( - out, - " let bin_name = utils::extract_exec_name_from_path(path)?;" - )?; - writeln!( - out, - " runtime::instantiate_inherit_stdio(&data, &bin_name, None)", - )?; - writeln!(out, " }}")?; - writeln!(out)?; - Ok(()) +// Get all targets in a given package with a given kind +// kind is "bin" for test program crates that expose a `fn main`, and +// "cdylib" for crates that implement a reactor. +fn targets_in_package<'a>( + meta: &'a cargo_metadata::Metadata, + package: &'a str, + kind: &'a str, +) -> Vec { + let targets = meta + .packages + .iter() + .find(|p| p.name == package) + .unwrap() + .targets + .iter() + .filter(move |t| t.kind == &[kind]) + .map(|t| t.name.to_snake_case()) + .collect::>(); + if targets.is_empty() { + panic!("no targets for package {package:?} of kind {kind:?}") } + targets } diff --git a/crates/test-programs/tests/http_tests/main.rs b/crates/test-programs/tests/http_tests/main.rs deleted file mode 100644 index 28a8c956d9f4..000000000000 --- a/crates/test-programs/tests/http_tests/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![cfg(feature = "test_programs_http")] -use std::sync::Once; -mod runtime; -mod utils; - -static LOG_INIT: Once = Once::new(); - -fn setup_log() { - LOG_INIT.call_once(tracing_subscriber::fmt::init) -} - -include!(concat!(env!("OUT_DIR"), "/wasi_http_tests.rs")); diff --git a/crates/test-programs/tests/http_tests/runtime/mod.rs b/crates/test-programs/tests/http_tests/runtime/mod.rs deleted file mode 100644 index 5af38c5cb518..000000000000 --- a/crates/test-programs/tests/http_tests/runtime/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod wasi_http_tests; diff --git a/crates/test-programs/tests/http_tests/utils.rs b/crates/test-programs/tests/http_tests/utils.rs deleted file mode 100644 index d455b96590c3..000000000000 --- a/crates/test-programs/tests/http_tests/utils.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::path::Path; - -pub fn extract_exec_name_from_path(path: &Path) -> anyhow::Result { - path.file_stem() - .and_then(|s| s.to_str()) - .map(String::from) - .ok_or_else(|| { - anyhow::anyhow!( - "couldn't extract the file stem from path {}", - path.display() - ) - }) -} diff --git a/crates/test-programs/tests/wasi-cap-std-sync.rs b/crates/test-programs/tests/wasi-cap-std-sync.rs new file mode 100644 index 000000000000..c81e26539b65 --- /dev/null +++ b/crates/test-programs/tests/wasi-cap-std-sync.rs @@ -0,0 +1,299 @@ +#![cfg(feature = "test_programs")] +use anyhow::Result; +use tempfile::TempDir; +use wasi_common::pipe::WritePipe; +use wasmtime::{Config, Engine, Linker, Store}; + +lazy_static::lazy_static! { + static ref ENGINE: Engine = { + let mut config = Config::new(); + config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); + config.wasm_component_model(false); + config.async_support(false); + + let engine = Engine::new(&config).unwrap(); + engine + }; +} +// uses ENGINE, creates a fn get_module(&str) -> Module +include!(concat!(env!("OUT_DIR"), "/wasi_tests_modules.rs")); + +pub fn prepare_workspace(exe_name: &str) -> Result { + let prefix = format!("wasi_cap_std_sync_{}_", exe_name); + let tempdir = tempfile::Builder::new().prefix(&prefix).tempdir()?; + Ok(tempdir) +} + +pub fn test_suite_environment() -> &'static [(&'static str, &'static str)] { + #[cfg(windows)] + { + &[ + ("ERRNO_MODE_WINDOWS", "1"), + // Windows does not support dangling links or symlinks in the filesystem. + ("NO_DANGLING_FILESYSTEM", "1"), + // Windows does not support renaming a directory to an empty directory - + // empty directory must be deleted. + ("NO_RENAME_DIR_TO_EMPTY_DIR", "1"), + // cap-std-sync does not support the sync family of fdflags + ("NO_FDFLAGS_SYNC_SUPPORT", "1"), + ] + } + #[cfg(all(unix, not(target_os = "macos")))] + { + &[ + ("ERRNO_MODE_UNIX", "1"), + // cap-std-sync does not support the sync family of fdflags + ("NO_FDFLAGS_SYNC_SUPPORT", "1"), + ] + } + #[cfg(target_os = "macos")] + { + &[ + ("ERRNO_MODE_MACOS", "1"), + // cap-std-sync does not support the sync family of fdflags + ("NO_FDFLAGS_SYNC_SUPPORT", "1"), + ] + } +} + +use wasmtime_wasi::sync::{add_to_linker, WasiCtxBuilder}; +fn run(name: &str, inherit_stdio: bool) -> Result<()> { + let workspace = prepare_workspace(name)?; + let stdout = WritePipe::new_in_memory(); + let stderr = WritePipe::new_in_memory(); + let r = { + let mut linker = Linker::new(&ENGINE); + add_to_linker(&mut linker, |cx| cx)?; + + // Create our wasi context. + // Additionally register any preopened directories if we have them. + let mut builder = WasiCtxBuilder::new(); + + if inherit_stdio { + builder = builder.inherit_stdio(); + } else { + builder = builder + .stdout(Box::new(stdout.clone())) + .stderr(Box::new(stderr.clone())); + } + builder = builder.arg(name)?.arg(".")?; + println!("preopen: {:?}", workspace); + let preopen_dir = + cap_std::fs::Dir::open_ambient_dir(workspace.path(), cap_std::ambient_authority())?; + builder = builder.preopened_dir(preopen_dir, ".")?; + for (var, val) in test_suite_environment() { + builder = builder.env(var, val)?; + } + + let mut store = Store::new(&ENGINE, builder.build()); + let instance = linker.instantiate(&mut store, &get_module(name))?; + let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; + start.call(&mut store, ())?; + Ok(()) + }; + + r.map_err(move |trap: anyhow::Error| { + let stdout = stdout + .try_into_inner() + .expect("sole ref to stdout") + .into_inner(); + if !stdout.is_empty() { + println!("guest stdout:\n{}\n===", String::from_utf8_lossy(&stdout)); + } + let stderr = stderr + .try_into_inner() + .expect("sole ref to stderr") + .into_inner(); + if !stderr.is_empty() { + println!("guest stderr:\n{}\n===", String::from_utf8_lossy(&stderr)); + } + trap.context(format!( + "error while testing wasi-tests {} with cap-std-sync", + name + )) + })?; + Ok(()) +} + +// Below here is mechanical: there should be one test for every binary in +// wasi-tests. The only differences should be should_panic annotations for +// tests which fail. +#[test_log::test] +fn big_random_buf() { + run("big_random_buf", true).unwrap() +} +#[test_log::test] +fn clock_time_get() { + run("clock_time_get", true).unwrap() +} +#[test_log::test] +fn close_preopen() { + run("close_preopen", true).unwrap() +} +#[test_log::test] +fn dangling_fd() { + run("dangling_fd", true).unwrap() +} +#[test_log::test] +fn dangling_symlink() { + run("dangling_symlink", true).unwrap() +} +#[test_log::test] +fn directory_seek() { + run("directory_seek", true).unwrap() +} +#[test_log::test] +fn dir_fd_op_failures() { + run("dir_fd_op_failures", true).unwrap() +} +#[test_log::test] +fn fd_advise() { + run("fd_advise", true).unwrap() +} +#[test_log::test] +fn fd_filestat_get() { + run("fd_filestat_get", true).unwrap() +} +#[test_log::test] +fn fd_filestat_set() { + run("fd_filestat_set", true).unwrap() +} +#[test_log::test] +fn fd_flags_set() { + run("fd_flags_set", true).unwrap() +} +#[test_log::test] +fn fd_readdir() { + run("fd_readdir", true).unwrap() +} +#[test_log::test] +fn file_allocate() { + run("file_allocate", true).unwrap() +} +#[test_log::test] +fn file_pread_pwrite() { + run("file_pread_pwrite", true).unwrap() +} +#[test_log::test] +fn file_seek_tell() { + run("file_seek_tell", true).unwrap() +} +#[test_log::test] +fn file_truncation() { + run("file_truncation", true).unwrap() +} +#[test_log::test] +fn file_unbuffered_write() { + run("file_unbuffered_write", true).unwrap() +} +#[test_log::test] +#[cfg_attr(windows, should_panic)] +fn interesting_paths() { + run("interesting_paths", true).unwrap() +} +#[test_log::test] +fn isatty() { + run("isatty", true).unwrap() +} +#[test_log::test] +fn nofollow_errors() { + run("nofollow_errors", true).unwrap() +} +#[test_log::test] +fn overwrite_preopen() { + run("overwrite_preopen", true).unwrap() +} +#[test_log::test] +fn path_exists() { + run("path_exists", true).unwrap() +} +#[test_log::test] +fn path_filestat() { + run("path_filestat", true).unwrap() +} +#[test_log::test] +fn path_link() { + run("path_link", true).unwrap() +} +#[test_log::test] +fn path_open_create_existing() { + run("path_open_create_existing", true).unwrap() +} +#[test_log::test] +fn path_open_dirfd_not_dir() { + run("path_open_dirfd_not_dir", true).unwrap() +} +#[test_log::test] +fn path_open_missing() { + run("path_open_missing", true).unwrap() +} +#[test_log::test] +fn path_open_nonblock() { + run("path_open_nonblock", true).unwrap() +} +#[test_log::test] +fn path_rename_dir_trailing_slashes() { + run("path_rename_dir_trailing_slashes", true).unwrap() +} +#[test_log::test] +#[should_panic] +fn path_rename_file_trailing_slashes() { + run("path_rename_file_trailing_slashes", false).unwrap() +} +#[test_log::test] +fn path_rename() { + run("path_rename", true).unwrap() +} +#[test_log::test] +fn path_symlink_trailing_slashes() { + run("path_symlink_trailing_slashes", true).unwrap() +} +#[test_log::test] +fn poll_oneoff_files() { + run("poll_oneoff_files", false).unwrap() +} +#[test_log::test] +fn poll_oneoff_stdio() { + run("poll_oneoff_stdio", true).unwrap() +} +#[test_log::test] +fn readlink() { + run("readlink", true).unwrap() +} +#[test_log::test] +#[should_panic] +fn remove_directory_trailing_slashes() { + run("remove_directory_trailing_slashes", false).unwrap() +} +#[test_log::test] +fn remove_nonempty_directory() { + run("remove_nonempty_directory", true).unwrap() +} +#[test_log::test] +fn renumber() { + run("renumber", true).unwrap() +} +#[test_log::test] +fn sched_yield() { + run("sched_yield", true).unwrap() +} +#[test_log::test] +fn stdio() { + run("stdio", true).unwrap() +} +#[test_log::test] +fn symlink_create() { + run("symlink_create", true).unwrap() +} +#[test_log::test] +fn symlink_filestat() { + run("symlink_filestat", true).unwrap() +} +#[test_log::test] +fn symlink_loop() { + run("symlink_loop", true).unwrap() +} +#[test_log::test] +fn unlink_file_trailing_slashes() { + run("unlink_file_trailing_slashes", true).unwrap() +} diff --git a/crates/test-programs/tests/http_tests/runtime/wasi_http_tests.rs b/crates/test-programs/tests/wasi-http.rs similarity index 73% rename from crates/test-programs/tests/http_tests/runtime/wasi_http_tests.rs rename to crates/test-programs/tests/wasi-http.rs index ad5cd21c313e..78c99dc939af 100644 --- a/crates/test-programs/tests/http_tests/runtime/wasi_http_tests.rs +++ b/crates/test-programs/tests/wasi-http.rs @@ -1,6 +1,5 @@ -use anyhow::Context; -use std::path::Path; -use wasmtime::{Config, Engine, Linker, Module, Store}; +#![cfg(feature = "test_programs")] +use wasmtime::{Config, Engine, Linker, Store}; use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx}; use wasmtime_wasi_http::WasiHttp; @@ -11,6 +10,17 @@ use hyper::{body::Bytes, service::service_fn, Request, Response}; use std::{error::Error, net::SocketAddr}; use tokio::net::TcpListener; +lazy_static::lazy_static! { + static ref ENGINE: Engine = { + let mut config = Config::new(); + config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); + let engine = Engine::new(&config).unwrap(); + engine + }; +} +// uses ENGINE, creates a fn get_module(&str) -> Module +include!(concat!(env!("OUT_DIR"), "/wasi_http_tests_modules.rs")); + async fn test( req: Request, ) -> http::Result>> { @@ -49,19 +59,13 @@ fn run_server() -> Result<(), Box> { Ok(()) } -pub fn instantiate_inherit_stdio( - data: &[u8], - bin_name: &str, - _workspace: Option<&Path>, -) -> anyhow::Result<()> { +pub fn run(name: &str) -> anyhow::Result<()> { let _thread = std::thread::spawn(|| { run_server().unwrap(); }); - let config = Config::new(); - let engine = Engine::new(&config)?; - let module = Module::new(&engine, &data).context("failed to create wasm module")?; - let mut linker = Linker::new(&engine); + let module = get_module(name); + let mut linker = Linker::new(&ENGINE); struct Ctx { wasi: WasiCtx, @@ -72,10 +76,10 @@ pub fn instantiate_inherit_stdio( wasmtime_wasi_http::add_to_linker(&mut linker, |cx: &mut Ctx| &mut cx.http)?; // Create our wasi context. - let builder = WasiCtxBuilder::new().inherit_stdio().arg(bin_name)?; + let builder = WasiCtxBuilder::new().inherit_stdio().arg(name)?; let mut store = Store::new( - &engine, + &ENGINE, Ctx { wasi: builder.build(), http: WasiHttp::new(), @@ -86,3 +90,8 @@ pub fn instantiate_inherit_stdio( let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; start.call(&mut store, ()) } + +#[test_log::test] +fn outbound_request() { + run("outbound_request").unwrap() +} diff --git a/crates/test-programs/tests/wasi-tokio.rs b/crates/test-programs/tests/wasi-tokio.rs new file mode 100644 index 000000000000..1746dc594d8e --- /dev/null +++ b/crates/test-programs/tests/wasi-tokio.rs @@ -0,0 +1,305 @@ +#![cfg(feature = "test_programs")] +use anyhow::Result; +use tempfile::TempDir; +use wasi_common::pipe::WritePipe; +use wasmtime::{Config, Engine, Linker, Store}; +use wasmtime_wasi::tokio::{add_to_linker, WasiCtxBuilder}; + +lazy_static::lazy_static! { + static ref ENGINE: Engine = { + let mut config = Config::new(); + config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); + config.wasm_component_model(false); + config.async_support(true); + + let engine = Engine::new(&config).unwrap(); + engine + }; +} +// uses ENGINE, creates a fn get_module(&str) -> Module +include!(concat!(env!("OUT_DIR"), "/wasi_tests_modules.rs")); + +pub fn prepare_workspace(exe_name: &str) -> Result { + let prefix = format!("wasi_cap_std_sync_{}_", exe_name); + let tempdir = tempfile::Builder::new().prefix(&prefix).tempdir()?; + Ok(tempdir) +} + +pub fn test_suite_environment() -> &'static [(&'static str, &'static str)] { + #[cfg(windows)] + { + &[ + ("ERRNO_MODE_WINDOWS", "1"), + // Windows does not support dangling links or symlinks in the filesystem. + ("NO_DANGLING_FILESYSTEM", "1"), + // Windows does not support renaming a directory to an empty directory - + // empty directory must be deleted. + ("NO_RENAME_DIR_TO_EMPTY_DIR", "1"), + // cap-std-sync does not support the sync family of fdflags + ("NO_FDFLAGS_SYNC_SUPPORT", "1"), + ] + } + #[cfg(all(unix, not(target_os = "macos")))] + { + &[ + ("ERRNO_MODE_UNIX", "1"), + // cap-std-sync does not support the sync family of fdflags + ("NO_FDFLAGS_SYNC_SUPPORT", "1"), + ] + } + #[cfg(target_os = "macos")] + { + &[ + ("ERRNO_MODE_MACOS", "1"), + // cap-std-sync does not support the sync family of fdflags + ("NO_FDFLAGS_SYNC_SUPPORT", "1"), + ] + } +} + +async fn run(name: &str, inherit_stdio: bool) -> Result<()> { + let workspace = prepare_workspace(name)?; + let stdout = WritePipe::new_in_memory(); + let stderr = WritePipe::new_in_memory(); + let r = { + let mut linker = Linker::new(&ENGINE); + add_to_linker(&mut linker, |cx| cx)?; + + // Create our wasi context. + // Additionally register any preopened directories if we have them. + let mut builder = WasiCtxBuilder::new(); + + if inherit_stdio { + builder = builder.inherit_stdio(); + } else { + builder = builder + .stdout(Box::new(stdout.clone())) + .stderr(Box::new(stderr.clone())); + } + builder = builder.arg(name)?.arg(".")?; + println!("preopen: {:?}", workspace); + let preopen_dir = + cap_std::fs::Dir::open_ambient_dir(workspace.path(), cap_std::ambient_authority())?; + builder = builder.preopened_dir(preopen_dir, ".")?; + for (var, val) in test_suite_environment() { + builder = builder.env(var, val)?; + } + + let mut store = Store::new(&ENGINE, builder.build()); + let instance = linker + .instantiate_async(&mut store, &get_module(name)) + .await?; + let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; + start.call_async(&mut store, ()).await?; + Ok(()) + }; + + r.map_err(move |trap: anyhow::Error| { + let stdout = stdout + .try_into_inner() + .expect("sole ref to stdout") + .into_inner(); + if !stdout.is_empty() { + println!("guest stdout:\n{}\n===", String::from_utf8_lossy(&stdout)); + } + let stderr = stderr + .try_into_inner() + .expect("sole ref to stderr") + .into_inner(); + if !stderr.is_empty() { + println!("guest stderr:\n{}\n===", String::from_utf8_lossy(&stderr)); + } + trap.context(format!( + "error while testing wasi-tests {} with cap-std-sync", + name + )) + })?; + Ok(()) +} + +// Below here is mechanical: there should be one test for every binary in +// wasi-tests. The only differences should be should_panic annotations for +// tests which fail. +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn big_random_buf() { + run("big_random_buf", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn clock_time_get() { + run("clock_time_get", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn close_preopen() { + run("close_preopen", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn dangling_fd() { + run("dangling_fd", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn dangling_symlink() { + run("dangling_symlink", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn directory_seek() { + run("directory_seek", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn dir_fd_op_failures() { + run("dir_fd_op_failures", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn fd_advise() { + run("fd_advise", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn fd_filestat_get() { + run("fd_filestat_get", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn fd_filestat_set() { + run("fd_filestat_set", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn fd_flags_set() { + run("fd_flags_set", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn fd_readdir() { + run("fd_readdir", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn file_allocate() { + run("file_allocate", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn file_pread_pwrite() { + run("file_pread_pwrite", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn file_seek_tell() { + run("file_seek_tell", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn file_truncation() { + run("file_truncation", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn file_unbuffered_write() { + run("file_unbuffered_write", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +#[cfg_attr(windows, should_panic)] +async fn interesting_paths() { + run("interesting_paths", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn isatty() { + run("isatty", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn nofollow_errors() { + run("nofollow_errors", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn overwrite_preopen() { + run("overwrite_preopen", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_exists() { + run("path_exists", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_filestat() { + run("path_filestat", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_link() { + run("path_link", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_open_create_existing() { + run("path_open_create_existing", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_open_dirfd_not_dir() { + run("path_open_dirfd_not_dir", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_open_missing() { + run("path_open_missing", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_open_nonblock() { + run("path_open_nonblock", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_rename_dir_trailing_slashes() { + run("path_rename_dir_trailing_slashes", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +#[should_panic] +async fn path_rename_file_trailing_slashes() { + run("path_rename_file_trailing_slashes", false) + .await + .unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_rename() { + run("path_rename", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn path_symlink_trailing_slashes() { + run("path_symlink_trailing_slashes", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn poll_oneoff_files() { + run("poll_oneoff_files", false).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn poll_oneoff_stdio() { + run("poll_oneoff_stdio", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn readlink() { + run("readlink", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +#[should_panic] +async fn remove_directory_trailing_slashes() { + run("remove_directory_trailing_slashes", false) + .await + .unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn remove_nonempty_directory() { + run("remove_nonempty_directory", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn renumber() { + run("renumber", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn sched_yield() { + run("sched_yield", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn stdio() { + run("stdio", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn symlink_create() { + run("symlink_create", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn symlink_filestat() { + run("symlink_filestat", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn symlink_loop() { + run("symlink_loop", true).await.unwrap() +} +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn unlink_file_trailing_slashes() { + run("unlink_file_trailing_slashes", true).await.unwrap() +} diff --git a/crates/test-programs/tests/wasm_tests/main.rs b/crates/test-programs/tests/wasm_tests/main.rs deleted file mode 100644 index 44fb127db852..000000000000 --- a/crates/test-programs/tests/wasm_tests/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![cfg(feature = "test_programs")] -mod runtime; -mod utils; - -use std::sync::Once; - -static LOG_INIT: Once = Once::new(); - -fn setup_log() { - LOG_INIT.call_once(tracing_subscriber::fmt::init) -} - -include!(concat!(env!("OUT_DIR"), "/wasi_tests.rs")); diff --git a/crates/test-programs/tests/wasm_tests/runtime/cap_std_sync.rs b/crates/test-programs/tests/wasm_tests/runtime/cap_std_sync.rs deleted file mode 100644 index 939b0bdb9278..000000000000 --- a/crates/test-programs/tests/wasm_tests/runtime/cap_std_sync.rs +++ /dev/null @@ -1,86 +0,0 @@ -use anyhow::Context; -use std::path::Path; -use wasi_common::pipe::WritePipe; -use wasmtime::{Engine, Linker, Module, Store}; -use wasmtime_wasi::sync::{add_to_linker, WasiCtxBuilder}; - -pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> anyhow::Result<()> { - run(data, bin_name, workspace, false) -} -pub fn instantiate_inherit_stdio( - data: &[u8], - bin_name: &str, - workspace: Option<&Path>, -) -> anyhow::Result<()> { - run(data, bin_name, workspace, true) -} - -fn run( - data: &[u8], - bin_name: &str, - workspace: Option<&Path>, - inherit_stdio: bool, -) -> anyhow::Result<()> { - let stdout = WritePipe::new_in_memory(); - let stderr = WritePipe::new_in_memory(); - - let r = { - let engine = Engine::default(); - let module = Module::new(&engine, &data).context("failed to create wasm module")?; - let mut linker = Linker::new(&engine); - add_to_linker(&mut linker, |cx| cx)?; - - // Create our wasi context. - // Additionally register any preopened directories if we have them. - let mut builder = WasiCtxBuilder::new(); - - if inherit_stdio { - builder = builder.inherit_stdio(); - } else { - builder = builder - .stdout(Box::new(stdout.clone())) - .stderr(Box::new(stderr.clone())); - } - - builder = builder.arg(bin_name)?.arg(".")?; - - if let Some(workspace) = workspace { - println!("preopen: {:?}", workspace); - let preopen_dir = - cap_std::fs::Dir::open_ambient_dir(workspace, cap_std::ambient_authority())?; - builder = builder.preopened_dir(preopen_dir, ".")?; - } - for (var, val) in super::test_suite_environment() { - builder = builder.env(var, val)?; - } - - // cap-std-sync does not yet support the sync family of fdflags - builder = builder.env("NO_FDFLAGS_SYNC_SUPPORT", "1")?; - - let mut store = Store::new(&engine, builder.build()); - let instance = linker.instantiate(&mut store, &module)?; - let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; - start.call(&mut store, ()).map_err(anyhow::Error::from) - }; - - match r { - Ok(()) => Ok(()), - Err(trap) => { - let stdout = stdout - .try_into_inner() - .expect("sole ref to stdout") - .into_inner(); - if !stdout.is_empty() { - println!("guest stdout:\n{}\n===", String::from_utf8_lossy(&stdout)); - } - let stderr = stderr - .try_into_inner() - .expect("sole ref to stderr") - .into_inner(); - if !stderr.is_empty() { - println!("guest stderr:\n{}\n===", String::from_utf8_lossy(&stderr)); - } - Err(trap.context(format!("error while testing Wasm module '{}'", bin_name,))) - } - } -} diff --git a/crates/test-programs/tests/wasm_tests/runtime/mod.rs b/crates/test-programs/tests/wasm_tests/runtime/mod.rs deleted file mode 100644 index 2ea46982da81..000000000000 --- a/crates/test-programs/tests/wasm_tests/runtime/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -pub mod cap_std_sync; -pub mod tokio; - -// Configure the test suite environment. -// Test programs use these environment variables to determine what behavior -// is expected: different errnos are expected on windows, mac, and other unixes, -// and other filesystem operations are supported or not. -pub fn test_suite_environment() -> &'static [(&'static str, &'static str)] { - #[cfg(windows)] - { - &[ - ("ERRNO_MODE_WINDOWS", "1"), - // Windows does not support dangling links or symlinks in the filesystem. - ("NO_DANGLING_FILESYSTEM", "1"), - // Windows does not support renaming a directory to an empty directory - - // empty directory must be deleted. - ("NO_RENAME_DIR_TO_EMPTY_DIR", "1"), - ] - } - #[cfg(all(unix, not(target_os = "macos")))] - { - &[("ERRNO_MODE_UNIX", "1")] - } - #[cfg(target_os = "macos")] - { - &[("ERRNO_MODE_MACOS", "1")] - } -} diff --git a/crates/test-programs/tests/wasm_tests/runtime/tokio.rs b/crates/test-programs/tests/wasm_tests/runtime/tokio.rs deleted file mode 100644 index 565dc088d662..000000000000 --- a/crates/test-programs/tests/wasm_tests/runtime/tokio.rs +++ /dev/null @@ -1,97 +0,0 @@ -use anyhow::Context; -use std::path::Path; -use wasi_common::pipe::WritePipe; -use wasmtime::{Config, Engine, Linker, Module, Store}; -use wasmtime_wasi::tokio::{add_to_linker, WasiCtxBuilder}; - -pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> anyhow::Result<()> { - run(data, bin_name, workspace, false) -} -pub fn instantiate_inherit_stdio( - data: &[u8], - bin_name: &str, - workspace: Option<&Path>, -) -> anyhow::Result<()> { - run(data, bin_name, workspace, true) -} - -fn run( - data: &[u8], - bin_name: &str, - workspace: Option<&Path>, - inherit_stdio: bool, -) -> anyhow::Result<()> { - let stdout = WritePipe::new_in_memory(); - let stdout_ = stdout.clone(); - let stderr = WritePipe::new_in_memory(); - let stderr_ = stderr.clone(); - - let r = tokio::runtime::Runtime::new() - .expect("create runtime") - .block_on(async move { - let mut config = Config::new(); - config.async_support(true); - let engine = Engine::new(&config)?; - let module = Module::new(&engine, &data).context("failed to create wasm module")?; - let mut linker = Linker::new(&engine); - add_to_linker(&mut linker, |cx| cx)?; - - // Create our wasi context. - let mut builder = WasiCtxBuilder::new(); - - if inherit_stdio { - builder = builder.inherit_stdio(); - } else { - builder = builder - .stdout(Box::new(stdout_.clone())) - .stderr(Box::new(stderr_.clone())); - } - - builder = builder.arg(bin_name)?.arg(".")?; - - if let Some(workspace) = workspace { - println!("preopen: {:?}", workspace); - let preopen_dir = - cap_std::fs::Dir::open_ambient_dir(workspace, cap_std::ambient_authority())?; - builder = builder.preopened_dir(preopen_dir, ".")?; - } - - for (var, val) in super::test_suite_environment() { - builder = builder.env(var, val)?; - } - - // tokio does not yet support the sync family of fdflags, because cap-std-sync - // does not. - builder = builder.env("NO_FDFLAGS_SYNC_SUPPORT", "1")?; - - let mut store = Store::new(&engine, builder.build()); - - let instance = linker.instantiate_async(&mut store, &module).await?; - let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; - start - .call_async(&mut store, ()) - .await - .map_err(anyhow::Error::from) - }); - - match r { - Ok(()) => Ok(()), - Err(trap) => { - let stdout = stdout - .try_into_inner() - .expect("sole ref to stdout") - .into_inner(); - if !stdout.is_empty() { - println!("guest stdout:\n{}\n===", String::from_utf8_lossy(&stdout)); - } - let stderr = stderr - .try_into_inner() - .expect("sole ref to stderr") - .into_inner(); - if !stderr.is_empty() { - println!("guest stderr:\n{}\n===", String::from_utf8_lossy(&stderr)); - } - Err(trap.context(format!("error while testing Wasm module '{}'", bin_name,))) - } - } -} diff --git a/crates/test-programs/tests/wasm_tests/utils.rs b/crates/test-programs/tests/wasm_tests/utils.rs deleted file mode 100644 index c8b35f92d9bf..000000000000 --- a/crates/test-programs/tests/wasm_tests/utils.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::path::Path; -use tempfile::{Builder, TempDir}; - -pub fn prepare_workspace(exe_name: &str) -> anyhow::Result { - let prefix = format!("wasi_common_{}", exe_name); - let tempdir = Builder::new().prefix(&prefix).tempdir()?; - Ok(tempdir) -} - -pub fn extract_exec_name_from_path(path: &Path) -> anyhow::Result { - path.file_stem() - .and_then(|s| s.to_str()) - .map(String::from) - .ok_or_else(|| { - anyhow::anyhow!( - "couldn't extract the file stem from path {}", - path.display() - ) - }) -} diff --git a/crates/test-programs/wasi-http-tests/Cargo.lock b/crates/test-programs/wasi-http-tests/Cargo.lock deleted file mode 100644 index b8d40a06d521..000000000000 --- a/crates/test-programs/wasi-http-tests/Cargo.lock +++ /dev/null @@ -1,380 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", - "serde", -] - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "proc-macro2" -version = "1.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "serde" -version = "1.0.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.9", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi-http-tests" -version = "0.0.0" -dependencies = [ - "anyhow", - "wit-bindgen", -] - -[[package]] -name = "wasm-encoder" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eff853c4f09eec94d76af527eddad4e9de13b11d6286a1ef7134bc30135a2b7" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6956efd8a1a2c48a707e9a1b2da729834a0f8e4c58117493b0d9d089cee468" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.102.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b" -dependencies = [ - "indexmap", - "url", -] - -[[package]] -name = "wit-bindgen" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7cf57f8786216c5652e1228b25203af2ff523808b5e9d3671894eee2bf7264" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef177b73007d86c720931d0e2ea7e30eb8c9776e58361717743fc1e83cfacfe5" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efdf5b00935b7b52d0e56cae1960f8ac13019a285f5aa762ff6bd7139a5c28a2" -dependencies = [ - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-bindgen-rust-lib", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-lib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0a8f4b5fb1820b9d232beb122936425f72ec8fe6acb56e5d8782cfe55083da" -dependencies = [ - "heck", - "wit-bindgen-core", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadf1adf12ed25629b06272c16b335ef8c5a240d0ca64ab508a955ac3b46172c" -dependencies = [ - "anyhow", - "proc-macro2", - "syn 1.0.109", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed04310239706efc71cc8b995cb0226089c5b5fd260c3bd800a71486bd3cec97" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "url", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f887c3da527a51b321076ebe6a7513026a4757b6d4d144259946552d6fc728b3" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "pulldown-cmark", - "unicode-xid", - "url", -] diff --git a/crates/test-programs/wasi-http-tests/Cargo.toml b/crates/test-programs/wasi-http-tests/Cargo.toml index 0c04ce6987ba..d6f90599f783 100644 --- a/crates/test-programs/wasi-http-tests/Cargo.toml +++ b/crates/test-programs/wasi-http-tests/Cargo.toml @@ -6,10 +6,5 @@ edition = "2021" publish = false [dependencies] -anyhow = "1" -wit-bindgen = "0.4.0" - -# This crate is built with the wasm32-wasi target, so it's separate -# from the main Wasmtime build, so use this directive to exclude it -# from the parent directory's workspace. -[workspace] +anyhow = { workspace = true } +wit-bindgen = { workspace = true } diff --git a/crates/test-programs/wasi-http-tests/src/bin/outbound_request.rs b/crates/test-programs/wasi-http-tests/src/bin/outbound_request.rs index 8bcca28a4a91..0c087d889c61 100644 --- a/crates/test-programs/wasi-http-tests/src/bin/outbound_request.rs +++ b/crates/test-programs/wasi-http-tests/src/bin/outbound_request.rs @@ -30,8 +30,8 @@ impl Response { } fn request( - method: types::MethodParam<'_>, - scheme: types::SchemeParam<'_>, + method: types::Method, + scheme: types::Scheme, authority: &str, path: &str, query: &str, @@ -43,7 +43,7 @@ fn request( ]); let request = - types::new_outgoing_request(method, path, query, Some(scheme), authority, headers); + types::new_outgoing_request(&method, path, query, Some(&scheme), authority, headers); let request_body = types::outgoing_request_write(request) .map_err(|_| anyhow!("outgoing request write failed"))?; @@ -103,8 +103,8 @@ fn request( fn main() -> Result<()> { let r1 = request( - types::MethodParam::Get, - types::SchemeParam::Http, + types::Method::Get, + types::Scheme::Http, "localhost:3000", "/get", "?some=arg?goes=here", @@ -121,8 +121,8 @@ fn main() -> Result<()> { assert_eq!(r1.body, b""); let r2 = request( - types::MethodParam::Post, - types::SchemeParam::Http, + types::Method::Post, + types::Scheme::Http, "localhost:3000", "/post", "", @@ -137,8 +137,8 @@ fn main() -> Result<()> { assert_eq!(r2.body, b"{\"foo\": \"bar\"}"); let r3 = request( - types::MethodParam::Put, - types::SchemeParam::Http, + types::Method::Put, + types::Scheme::Http, "localhost:3000", "/put", "", @@ -153,8 +153,8 @@ fn main() -> Result<()> { assert_eq!(r3.body, b""); let r4 = request( - types::MethodParam::Other("OTHER"), - types::SchemeParam::Http, + types::Method::Other("OTHER".to_owned()), + types::Scheme::Http, "localhost:3000", "/", "", @@ -164,12 +164,12 @@ fn main() -> Result<()> { let error = r4.unwrap_err(); assert_eq!( error.to_string(), - "ErrorResult::UnexpectedError(\"unknown method OTHER\")" + "Error::UnexpectedError(\"unknown method OTHER\")" ); let r5 = request( - types::MethodParam::Get, - types::SchemeParam::Other("WS"), + types::Method::Get, + types::Scheme::Other("WS".to_owned()), "localhost:3000", "/", "", @@ -179,7 +179,7 @@ fn main() -> Result<()> { let error = r5.unwrap_err(); assert_eq!( error.to_string(), - "ErrorResult::UnexpectedError(\"unsupported scheme WS\")" + "Error::UnexpectedError(\"unsupported scheme WS\")" ); Ok(()) diff --git a/crates/test-programs/wasi-tests/Cargo.lock b/crates/test-programs/wasi-tests/Cargo.lock deleted file mode 100644 index d1d241ba804b..000000000000 --- a/crates/test-programs/wasi-tests/Cargo.lock +++ /dev/null @@ -1,30 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "libc" -version = "0.2.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701" - -[[package]] -name = "once_cell" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi-tests" -version = "0.0.0" -dependencies = [ - "libc", - "once_cell", - "wasi", -] diff --git a/crates/test-programs/wasi-tests/Cargo.toml b/crates/test-programs/wasi-tests/Cargo.toml index 64a5ca3db63f..1cf5c4949bcd 100644 --- a/crates/test-programs/wasi-tests/Cargo.toml +++ b/crates/test-programs/wasi-tests/Cargo.toml @@ -9,8 +9,3 @@ publish = false libc = "0.2.65" wasi = "0.11.0" once_cell = "1.12" - -# This crate is built with the wasm32-wasi target, so it's separate -# from the main Wasmtime build, so use this directive to exclude it -# from the parent directory's workspace. -[workspace] diff --git a/crates/test-programs/wasi-tests/src/bin/overwrite_preopen.rs b/crates/test-programs/wasi-tests/src/bin/overwrite_preopen.rs index 7b509c503f1a..0721d18ab1bd 100644 --- a/crates/test-programs/wasi-tests/src/bin/overwrite_preopen.rs +++ b/crates/test-programs/wasi-tests/src/bin/overwrite_preopen.rs @@ -9,8 +9,7 @@ unsafe fn test_overwrite_preopen(dir_fd: wasi::Fd) { let old_dir_filestat = wasi::fd_filestat_get(dir_fd).expect("failed fd_filestat_get"); // Try to renumber over a preopened directory handle. - wasi::fd_renumber(dir_fd, pre_fd) - .expect("renumbering over a preopened file descriptor"); + wasi::fd_renumber(dir_fd, pre_fd).expect("renumbering over a preopened file descriptor"); // Ensure that pre_fd is still open. let new_dir_filestat = wasi::fd_filestat_get(pre_fd).expect("failed fd_filestat_get"); diff --git a/crates/test-programs/wasi-tests/src/bin/path_open_nonblock.rs b/crates/test-programs/wasi-tests/src/bin/path_open_nonblock.rs index 35c02ce2d8b4..3ca99418117b 100644 --- a/crates/test-programs/wasi-tests/src/bin/path_open_nonblock.rs +++ b/crates/test-programs/wasi-tests/src/bin/path_open_nonblock.rs @@ -1,8 +1,9 @@ use std::{env, process}; -use wasi_tests::{open_scratch_directory}; +use wasi_tests::open_scratch_directory; unsafe fn try_path_open(dir_fd: wasi::Fd) { - let fd = wasi::path_open(dir_fd, 0, ".", 0, 0, 0, wasi::FDFLAGS_NONBLOCK).expect("opening the dir"); + let _fd = + wasi::path_open(dir_fd, 0, ".", 0, 0, 0, wasi::FDFLAGS_NONBLOCK).expect("opening the dir"); } fn main() { diff --git a/crates/test-programs/wasi-tests/src/bin/readlink.rs b/crates/test-programs/wasi-tests/src/bin/readlink.rs index 615647247a2a..eb8b8aa5f734 100644 --- a/crates/test-programs/wasi-tests/src/bin/readlink.rs +++ b/crates/test-programs/wasi-tests/src/bin/readlink.rs @@ -1,5 +1,5 @@ use std::{env, process}; -use wasi_tests::{assert_errno, create_file, open_scratch_directory}; +use wasi_tests::{create_file, open_scratch_directory}; unsafe fn test_readlink(dir_fd: wasi::Fd) { // Create a file in the scratch directory. diff --git a/crates/test-programs/wasi-tests/src/lib.rs b/crates/test-programs/wasi-tests/src/lib.rs index 31174f12031d..3a701ad86335 100644 --- a/crates/test-programs/wasi-tests/src/lib.rs +++ b/crates/test-programs/wasi-tests/src/lib.rs @@ -39,10 +39,7 @@ pub fn open_scratch_directory(path: &str) -> Result { pub unsafe fn create_file(dir_fd: wasi::Fd, filename: &str) { let file_fd = wasi::path_open(dir_fd, 0, filename, wasi::OFLAGS_CREAT, 0, 0, 0).expect("creating a file"); - assert!( - file_fd > libc::STDERR_FILENO as wasi::Fd, - "file descriptor range check", - ); + assert!(file_fd > STDERR_FD, "file descriptor range check",); wasi::fd_close(file_fd).expect("closing a file"); } diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 0ebab2787c3a..26d89b0344b3 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -31,7 +31,7 @@ target-lexicon = { workspace = true } wasmparser = { workspace = true } anyhow = { workspace = true } libc = "0.2" -cfg-if = "1.0" +cfg-if = { workspace = true } log = { workspace = true } wat = { workspace = true, optional = true } serde = { version = "1.0.94", features = ["derive"] } diff --git a/deny.toml b/deny.toml index 5feba83d8973..0c1303cfda8a 100644 --- a/deny.toml +++ b/deny.toml @@ -37,6 +37,13 @@ wildcards = "allow" deny = [] skip-tree = [ + # wit-bindgen and wasmtime both depend on the wasm-tools crates, and + # wit-bindgen's latest release may sometimes lag behind when we bump + # wasmtime's dependencies on wasm-tools. wit-bindgen is only used for + # building component-based test programs, so we are going to ignore + # the multiple-versions errors it will introduce. + { name = "wit-bindgen", depth = 20 }, + # Criterion 0.3 is pretty old at this point and has had an upcoming 0.4 for # a long time. This is a dev-dependency so we don't really mind its # dependency tree, so skip it entirely. diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 657d02dc5d1a..08c49595e950 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -241,6 +241,13 @@ I am employed by a member of the Bytecode Alliance and plan to continue doing so and will actively maintain this crate over time. """ +[[wildcard-audits.wit-component]] +who = "Nick Fitzgerald " +criteria = "safe-to-deploy" +user-id = 696 +start = "2019-03-16" +end = "2024-03-10" + [[wildcard-audits.wit-parser]] who = "Alex Crichton " criteria = "safe-to-deploy" @@ -983,6 +990,11 @@ criteria = "safe-to-deploy" version = "0.3.3" notes = "I am the author of this crate." +[[audits.matchers]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +version = "0.1.0" + [[audits.memfd]] who = "Alex Crichton " criteria = "safe-to-deploy" @@ -1341,6 +1353,16 @@ criteria = "safe-to-deploy" delta = "0.25.6 -> 0.25.7" notes = "This is a minor bug-fix update." +[[audits.tempfile]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +delta = "3.3.0 -> 3.5.0" + +[[audits.test-log]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +version = "0.2.11" + [[audits.tinyvec]] who = "Alex Crichton " criteria = "safe-to-deploy" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index ac785564bd2b..bf17a372adff 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -320,7 +320,7 @@ version = "0.10.0" criteria = "safe-to-deploy" [[exemptions.h2]] -version = "0.3.16" +version = "0.3.19" criteria = "safe-to-deploy" notes = "we are exempting tokio, hyper, and their tightly coupled dependencies by the same authors, expecting that the authors at aws will publish attestions we can import at some point soon" @@ -497,10 +497,6 @@ criteria = "safe-to-deploy" version = "0.4.1" criteria = "safe-to-deploy" -[[exemptions.os_pipe]] -version = "0.9.2" -criteria = "safe-to-run" - [[exemptions.os_str_bytes]] version = "6.0.0" criteria = "safe-to-deploy" @@ -641,6 +637,10 @@ criteria = "safe-to-deploy" version = "0.2.13" criteria = "safe-to-deploy" +[[exemptions.redox_syscall]] +version = "0.3.5" +criteria = "safe-to-deploy" + [[exemptions.redox_users]] version = "0.4.3" criteria = "safe-to-deploy" @@ -661,10 +661,6 @@ criteria = "safe-to-deploy" version = "2.2.0" criteria = "safe-to-deploy" -[[exemptions.remove_dir_all]] -version = "0.5.3" -criteria = "safe-to-deploy" - [[exemptions.ring]] version = "0.16.20" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 76f004fe2b6d..b23cb2a39b8a 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -64,6 +64,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wasm-metadata]] +version = "0.3.1" +when = "2023-03-06" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[publisher.wasm-metadata]] version = "0.5.0" when = "2023-04-27" @@ -71,9 +78,9 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wasm-mutate]] -version = "0.2.23" -when = "2023-04-13" +[[publisher.wasm-metadata]] +version = "0.6.0" +when = "2023-05-15" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" @@ -92,13 +99,6 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wasm-smith]] -version = "0.12.6" -when = "2023-04-13" -user-id = 1 -user-login = "alexcrichton" -user-name = "Alex Crichton" - [[publisher.wasm-smith]] version = "0.12.7" when = "2023-04-27" @@ -113,13 +113,6 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wasmparser]] -version = "0.103.0" -when = "2023-04-13" -user-id = 1 -user-login = "alexcrichton" -user-name = "Alex Crichton" - [[publisher.wasmparser]] version = "0.104.0" when = "2023-04-27" @@ -134,13 +127,6 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wasmprinter]] -version = "0.2.55" -when = "2023-04-13" -user-id = 1 -user-login = "alexcrichton" -user-name = "Alex Crichton" - [[publisher.wasmprinter]] version = "0.2.56" when = "2023-04-27" @@ -155,13 +141,6 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wast]] -version = "56.0.0" -when = "2023-04-13" -user-id = 1 -user-login = "alexcrichton" -user-name = "Alex Crichton" - [[publisher.wast]] version = "57.0.0" when = "2023-04-27" @@ -176,13 +155,6 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wat]] -version = "1.0.62" -when = "2023-04-13" -user-id = 1 -user-login = "alexcrichton" -user-name = "Alex Crichton" - [[publisher.wat]] version = "1.0.63" when = "2023-04-27" @@ -232,6 +204,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wit-component]] +version = "0.7.4" +when = "2023-03-10" +user-id = 696 +user-login = "fitzgen" +user-name = "Nick Fitzgerald" + [[publisher.wit-component]] version = "0.8.2" when = "2023-04-27" @@ -239,6 +218,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wit-component]] +version = "0.9.0" +when = "2023-05-16" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[publisher.wit-parser]] version = "0.7.1" when = "2023-04-27"