From b3490a3fb2a4d52198ae08eb3d6e86f81c77afe8 Mon Sep 17 00:00:00 2001 From: Xinzhao Xu Date: Fri, 7 Jun 2024 19:05:49 +0800 Subject: [PATCH] Add server tests --- .gitignore | 2 + test-programs/artifacts/build.rs | 19 ++-- .../wasi_snapshot_preview1.proxy.wasm | Bin 0 -> 28530 bytes .../bin/{get_chunk.rs => client_get_chunk.rs} | 0 ...with_query.rs => client_get_with_query.rs} | 0 ..._data.rs => client_post_with_form_data.rs} | 0 ..._data.rs => client_post_with_json_data.rs} | 0 ...> client_post_with_multipart_form_data.rs} | 0 test-programs/src/bin/server_hello.rs | 19 ++++ waki/Cargo.toml | 7 ++ waki/tests/client.rs | 35 +++---- waki/tests/common/mod.rs | 97 ++++++++++++++++++ waki/tests/server.rs | 23 +++++ 13 files changed, 176 insertions(+), 26 deletions(-) create mode 100644 test-programs/artifacts/wasi_snapshot_preview1.proxy.wasm rename test-programs/src/bin/{get_chunk.rs => client_get_chunk.rs} (100%) rename test-programs/src/bin/{get_with_query.rs => client_get_with_query.rs} (100%) rename test-programs/src/bin/{post_with_form_data.rs => client_post_with_form_data.rs} (100%) rename test-programs/src/bin/{post_with_json_data.rs => client_post_with_json_data.rs} (100%) rename test-programs/src/bin/{post_with_multipart_form_data.rs => client_post_with_multipart_form_data.rs} (100%) create mode 100644 test-programs/src/bin/server_hello.rs create mode 100644 waki/tests/common/mod.rs create mode 100644 waki/tests/server.rs diff --git a/.gitignore b/.gitignore index 6985cf1..7aa7025 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ Cargo.lock # MSVC Windows builds of rustc generate these, which store debugging information *.pdb + +.idea diff --git a/test-programs/artifacts/build.rs b/test-programs/artifacts/build.rs index 974de28..3f679ff 100644 --- a/test-programs/artifacts/build.rs +++ b/test-programs/artifacts/build.rs @@ -41,7 +41,17 @@ fn main() -> Result<()> { .join("debug") .join(format!("{target}.wasm")); - let path = compile_component(&wasm)?; + let adapter = match target.as_str() { + s if s.starts_with("client_") => { + include_bytes!("wasi_snapshot_preview1.command.wasm").to_vec() + } + s if s.starts_with("server_") => { + include_bytes!("wasi_snapshot_preview1.proxy.wasm").to_vec() + } + other => panic!("unknown type {other}"), + }; + + let path = compile_component(&wasm, &adapter)?; generated_code += &format!("pub const {camel}_COMPONENT: &str = {path:?};\n"); } @@ -51,15 +61,12 @@ fn main() -> Result<()> { } // Compile a component, return the path of the binary -fn compile_component(wasm: &Path) -> Result { +fn compile_component(wasm: &Path, adapter: &[u8]) -> Result { let module = fs::read(wasm)?; let component = ComponentEncoder::default() .module(module.as_slice())? .validate(true) - .adapter( - "wasi_snapshot_preview1", - include_bytes!("wasi_snapshot_preview1.command.wasm"), - )? + .adapter("wasi_snapshot_preview1", adapter)? .encode()?; let out_dir = wasm.parent().unwrap(); let stem = wasm.file_stem().unwrap().to_str().unwrap(); diff --git a/test-programs/artifacts/wasi_snapshot_preview1.proxy.wasm b/test-programs/artifacts/wasi_snapshot_preview1.proxy.wasm new file mode 100644 index 0000000000000000000000000000000000000000..149ec03a1cabd2112a293546f8c52fbf18cfba56 GIT binary patch literal 28530 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 Result { + let query = req.query(); + Response::builder() + .body( + format!( + "Hello, {}!", + query.get("name").unwrap_or(&"WASI".to_string()) + ) + .as_bytes(), + ) + .build() +} + +// Technically this should not be here for a proxy, but given the current +// framework for tests it's required since this file is built as a `bin` +fn main() {} diff --git a/waki/Cargo.toml b/waki/Cargo.toml index 32694a7..f3737e6 100644 --- a/waki/Cargo.toml +++ b/waki/Cargo.toml @@ -33,3 +33,10 @@ wit-deps = "0.3.1" [dev-dependencies] test-programs-artifacts = { path = "../test-programs/artifacts" } + +wasmtime = "21.0.1" +wasmtime-wasi = "21.0.1" +wasmtime-wasi-http = "21.0.1" +hyper = "1.3.1" +http-body-util = "0.1.1" +tokio = { version = "1.38.0", features = ["macros"] } diff --git a/waki/tests/client.rs b/waki/tests/client.rs index aade62f..92ba1be 100644 --- a/waki/tests/client.rs +++ b/waki/tests/client.rs @@ -7,50 +7,45 @@ fn wasmtime() -> Command { } #[test] -fn get_chunk() { - let mut cmd = wasmtime(); - let status = cmd - .arg(test_programs_artifacts::GET_CHUNK_COMPONENT) +fn client_get_chunk() { + let status = wasmtime() + .arg(test_programs_artifacts::CLIENT_GET_CHUNK_COMPONENT) .status() .unwrap(); assert!(status.success()); } #[test] -fn get_with_query() { - let mut cmd = wasmtime(); - let status = cmd - .arg(test_programs_artifacts::GET_WITH_QUERY_COMPONENT) +fn client_get_with_query() { + let status = wasmtime() + .arg(test_programs_artifacts::CLIENT_GET_WITH_QUERY_COMPONENT) .status() .unwrap(); assert!(status.success()); } #[test] -fn post_with_form_data() { - let mut cmd = wasmtime(); - let status = cmd - .arg(test_programs_artifacts::POST_WITH_FORM_DATA_COMPONENT) +fn client_post_with_form_data() { + let status = wasmtime() + .arg(test_programs_artifacts::CLIENT_POST_WITH_FORM_DATA_COMPONENT) .status() .unwrap(); assert!(status.success()); } #[test] -fn post_with_json_data() { - let mut cmd = wasmtime(); - let status = cmd - .arg(test_programs_artifacts::POST_WITH_JSON_DATA_COMPONENT) +fn client_post_with_json_data() { + let status = wasmtime() + .arg(test_programs_artifacts::CLIENT_POST_WITH_JSON_DATA_COMPONENT) .status() .unwrap(); assert!(status.success()); } #[test] -fn post_with_multipart_form_data() { - let mut cmd = wasmtime(); - let status = cmd - .arg(test_programs_artifacts::POST_WITH_MULTIPART_FORM_DATA_COMPONENT) +fn client_post_with_multipart_form_data() { + let status = wasmtime() + .arg(test_programs_artifacts::CLIENT_POST_WITH_MULTIPART_FORM_DATA_COMPONENT) .status() .unwrap(); assert!(status.success()); diff --git a/waki/tests/common/mod.rs b/waki/tests/common/mod.rs new file mode 100644 index 0000000..c3de5fa --- /dev/null +++ b/waki/tests/common/mod.rs @@ -0,0 +1,97 @@ +use anyhow::{Context, Result}; +use http_body_util::Collected; +use hyper::body::Bytes; +use wasmtime::{ + component::{Component, Linker, ResourceTable}, + Config, Engine, Store, +}; +use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiView}; +use wasmtime_wasi_http::{ + bindings::http::types::ErrorCode, body::HyperIncomingBody, WasiHttpCtx, WasiHttpView, +}; + +struct Ctx { + table: ResourceTable, + wasi: WasiCtx, + http: WasiHttpCtx, +} + +impl WasiView for Ctx { + fn table(&mut self) -> &mut ResourceTable { + &mut self.table + } + fn ctx(&mut self) -> &mut WasiCtx { + &mut self.wasi + } +} + +impl WasiHttpView for Ctx { + fn ctx(&mut self) -> &mut WasiHttpCtx { + &mut self.http + } + + fn table(&mut self) -> &mut ResourceTable { + &mut self.table + } +} + +// ref: https://github.com/bytecodealliance/wasmtime/blob/af59c4d568d487b7efbb49d7d31a861e7c3933a6/crates/wasi-http/tests/all/main.rs#L129 +pub async fn run_wasi_http( + component_filename: &str, + req: hyper::Request, +) -> Result>, ErrorCode>> { + let mut config = Config::new(); + config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); + config.wasm_component_model(true); + config.async_support(true); + + let engine = Engine::new(&config)?; + let component = Component::from_file(&engine, component_filename)?; + + let ctx = Ctx { + table: ResourceTable::new(), + wasi: WasiCtxBuilder::new().build(), + http: WasiHttpCtx::new(), + }; + + let mut store = Store::new(&engine, ctx); + let mut linker = Linker::new(&engine); + wasmtime_wasi_http::proxy::add_to_linker(&mut linker)?; + let (proxy, _) = + wasmtime_wasi_http::proxy::Proxy::instantiate_async(&mut store, &component, &linker) + .await?; + + let req = store.data_mut().new_incoming_request(req)?; + + let (sender, receiver) = tokio::sync::oneshot::channel(); + let out = store.data_mut().new_response_outparam(sender)?; + + let handle = wasmtime_wasi::runtime::spawn(async move { + proxy + .wasi_http_incoming_handler() + .call_handle(&mut store, req, out) + .await?; + + Ok::<_, anyhow::Error>(()) + }); + + let resp = match receiver.await { + Ok(Ok(resp)) => { + use http_body_util::BodyExt; + let (parts, body) = resp.into_parts(); + let collected = BodyExt::collect(body).await?; + Some(Ok(hyper::Response::from_parts(parts, collected))) + } + Ok(Err(e)) => Some(Err(e)), + + // Fall through below to the `resp.expect(...)` which will hopefully + // return a more specific error from `handle.await`. + Err(_) => None, + }; + + // Now that the response has been processed, we can wait on the wasm to + // finish without deadlocking. + handle.await.context("Component execution")?; + + Ok(resp.expect("wasm never called set-response-outparam")) +} diff --git a/waki/tests/server.rs b/waki/tests/server.rs new file mode 100644 index 0000000..9dcb40c --- /dev/null +++ b/waki/tests/server.rs @@ -0,0 +1,23 @@ +mod common; + +use crate::common::run_wasi_http; + +use anyhow::Result; +use wasmtime_wasi_http::body::HyperIncomingBody; + +#[tokio::test] +async fn server_hello_query() -> Result<()> { + let req = hyper::Request::builder() + .uri("http://localhost?name=ia") + .body(HyperIncomingBody::default())?; + + match run_wasi_http(test_programs_artifacts::SERVER_HELLO_COMPONENT, req).await? { + Ok(resp) => { + let body = resp.into_body().to_bytes(); + let body = std::str::from_utf8(&body)?; + assert_eq!(body, "Hello, ia!") + } + Err(e) => panic!("Error given in response: {e:?}"), + }; + Ok(()) +}