summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrei Zeliankou <zelenkov@nginx.com>2024-05-17 17:42:11 +0100
committerAva Hahn <110854134+avahahn@users.noreply.github.com>2024-08-20 11:38:51 -0700
commitcad6aed526b38d52f13266120f9a4381f9a22cad (patch)
tree8108d85b8c56f01504fdf329de787b56c5b7d0a8
parent593564fdd10da2bf4e76587a0482af72a9f1461b (diff)
downloadunit-cad6aed526b38d52f13266120f9a4381f9a22cad.tar.gz
unit-cad6aed526b38d52f13266120f9a4381f9a22cad.tar.bz2
Tests: initial "wasm-wasi-component" test
-rw-r--r--test/test_wasm_component.py18
-rw-r--r--test/unit/applications/lang/wasm_component.py60
-rw-r--r--test/unit/check/cargo_component.py4
-rw-r--r--test/unit/check/discover_available.py4
-rw-r--r--test/wasm_component/hello_world/Cargo.lock34
-rw-r--r--test/wasm_component/hello_world/Cargo.toml18
-rw-r--r--test/wasm_component/hello_world/src/bindings.rs109
-rw-r--r--test/wasm_component/hello_world/src/lib.rs31
-rw-r--r--test/wasm_component/hello_world/wit/world.wit6
9 files changed, 283 insertions, 1 deletions
diff --git a/test/test_wasm_component.py b/test/test_wasm_component.py
new file mode 100644
index 00000000..6d3bc485
--- /dev/null
+++ b/test/test_wasm_component.py
@@ -0,0 +1,18 @@
+import pytest
+from unit.applications.lang.wasm_component import ApplicationWasmComponent
+
+prerequisites = {
+ 'modules': {'wasm-wasi-component': 'any'},
+ 'features': {'cargo_component': True},
+}
+
+client = ApplicationWasmComponent()
+
+
+def test_wasm_component():
+ client.load('hello_world')
+
+ req = client.get()
+
+ assert client.get()['status'] == 200
+ assert req['body'] == 'Hello'
diff --git a/test/unit/applications/lang/wasm_component.py b/test/unit/applications/lang/wasm_component.py
new file mode 100644
index 00000000..6f7b5518
--- /dev/null
+++ b/test/unit/applications/lang/wasm_component.py
@@ -0,0 +1,60 @@
+from pathlib import Path
+import shutil
+import subprocess
+from urllib.parse import quote
+
+from unit.applications.proto import ApplicationProto
+from unit.option import option
+
+
+class ApplicationWasmComponent(ApplicationProto):
+ @staticmethod
+ def prepare_env(script):
+ try:
+ subprocess.check_output(['cargo', 'component', '--help'])
+ except (subprocess.CalledProcessError, FileNotFoundError):
+ return None
+
+ temp_dir = Path(f'{option.temp_dir}/wasm_component/')
+
+ if not temp_dir.exists():
+ temp_dir.mkdir()
+
+ app_path = f'{temp_dir}/{script}'
+
+ shutil.copytree(f'{option.test_dir}/wasm_component/{script}', app_path)
+
+ try:
+ output = subprocess.check_output(
+ ['cargo', 'component', 'build', '--release'],
+ cwd=app_path,
+ stderr=subprocess.STDOUT,
+ )
+ except KeyboardInterrupt:
+ raise
+
+ except subprocess.CalledProcessError:
+ return None
+
+ return output
+
+ def load(self, script, **kwargs):
+ self.prepare_env(script)
+
+ component_path = f'{option.temp_dir}/wasm_component/{script}/target/wasm32-wasi/release/test_wasi_component.wasm'
+
+ self._load_conf(
+ {
+ "listeners": {
+ "*:8080": {"pass": f"applications/{quote(script, '')}"}
+ },
+ "applications": {
+ script: {
+ "type": "wasm-wasi-component",
+ "processes": {"spare": 0},
+ "component": component_path,
+ }
+ },
+ },
+ **kwargs,
+ )
diff --git a/test/unit/check/cargo_component.py b/test/unit/check/cargo_component.py
new file mode 100644
index 00000000..1c194bfc
--- /dev/null
+++ b/test/unit/check/cargo_component.py
@@ -0,0 +1,4 @@
+from unit.applications.lang.wasm_component import ApplicationWasmComponent
+
+def check_cargo_component():
+ return ApplicationWasmComponent.prepare_env('hello_world') is not None
diff --git a/test/unit/check/discover_available.py b/test/unit/check/discover_available.py
index 1383a0c3..99e63604 100644
--- a/test/unit/check/discover_available.py
+++ b/test/unit/check/discover_available.py
@@ -1,6 +1,7 @@
import subprocess
import sys
+from unit.check.cargo_component import check_cargo_component
from unit.check.chroot import check_chroot
from unit.check.go import check_go
from unit.check.isolation import check_isolation
@@ -28,7 +29,7 @@ def discover_available(unit):
# discover modules from log file
- for module in Log.findall(r'module: ([a-zA-Z]+) (.*) ".*"$'):
+ for module in Log.findall(r'module: ([a-zA-Z\-]+) (.*) ".*"$'):
versions = option.available['modules'].setdefault(module[0], [])
if module[1] not in versions:
versions.append(module[1])
@@ -44,6 +45,7 @@ def discover_available(unit):
# Discover features using check. Features should be discovered after
# modules since some features can require modules.
+ option.available['features']['cargo_component'] = check_cargo_component()
option.available['features']['chroot'] = check_chroot()
option.available['features']['isolation'] = check_isolation()
option.available['features']['unix_abstract'] = check_unix_abstract()
diff --git a/test/wasm_component/hello_world/Cargo.lock b/test/wasm_component/hello_world/Cargo.lock
new file mode 100644
index 00000000..2daeb73d
--- /dev/null
+++ b/test/wasm_component/hello_world/Cargo.lock
@@ -0,0 +1,34 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bitflags"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+
+[[package]]
+name = "test-wasi-component"
+version = "0.1.0"
+dependencies = [
+ "bitflags",
+ "wasi",
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasi"
+version = "0.13.0+wasi-0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "652cd73449d0b957a2743b70c72d79d34a5fa505696488f4ca90b46f6da94118"
+dependencies = [
+ "bitflags",
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "026d24a27f6712541fa534f2954bd9e0eb66172f033c2157c0f31d106255c497"
diff --git a/test/wasm_component/hello_world/Cargo.toml b/test/wasm_component/hello_world/Cargo.toml
new file mode 100644
index 00000000..a87fbeb5
--- /dev/null
+++ b/test/wasm_component/hello_world/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "test-wasi-component"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bitflags = "2.4.2"
+wit-bindgen-rt = "0.21.0"
+wasi = "0.13.0"
+
+[lib]
+crate-type = ["cdylib"]
+
+[package.metadata.component]
+package = "component:test-wasi-component"
+proxy = true
+
+[package.metadata.component.dependencies]
diff --git a/test/wasm_component/hello_world/src/bindings.rs b/test/wasm_component/hello_world/src/bindings.rs
new file mode 100644
index 00000000..a0d74c42
--- /dev/null
+++ b/test/wasm_component/hello_world/src/bindings.rs
@@ -0,0 +1,109 @@
+// Generated by `wit-bindgen` 0.24.0. DO NOT EDIT!
+// Options used:
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub unsafe fn _export_hello_world_cabi<T: Guest>() -> *mut u8 {
+ #[cfg(target_arch = "wasm32")]
+ _rt::run_ctors_once();
+ let result0 = T::hello_world();
+ let ptr1 = _RET_AREA.0.as_mut_ptr().cast::<u8>();
+ let vec2 = (result0.into_bytes()).into_boxed_slice();
+ let ptr2 = vec2.as_ptr().cast::<u8>();
+ let len2 = vec2.len();
+ ::core::mem::forget(vec2);
+ *ptr1.add(4).cast::<usize>() = len2;
+ *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut();
+ ptr1
+}
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub unsafe fn __post_return_hello_world<T: Guest>(arg0: *mut u8) {
+ let l0 = *arg0.add(0).cast::<*mut u8>();
+ let l1 = *arg0.add(4).cast::<usize>();
+ _rt::cabi_dealloc(l0, l1, 1);
+}
+pub trait Guest {
+ fn hello_world() -> _rt::String;
+}
+#[doc(hidden)]
+
+macro_rules! __export_world_example_cabi{
+ ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = {
+
+ #[export_name = "hello-world"]
+ unsafe extern "C" fn export_hello_world() -> *mut u8 {
+ $($path_to_types)*::_export_hello_world_cabi::<$ty>()
+ }
+ #[export_name = "cabi_post_hello-world"]
+ unsafe extern "C" fn _post_return_hello_world(arg0: *mut u8,) {
+ $($path_to_types)*::__post_return_hello_world::<$ty>(arg0)
+ }
+ };);
+}
+#[doc(hidden)]
+pub(crate) use __export_world_example_cabi;
+#[repr(align(4))]
+struct _RetArea([::core::mem::MaybeUninit<u8>; 8]);
+static mut _RET_AREA: _RetArea =
+ _RetArea([::core::mem::MaybeUninit::uninit(); 8]);
+mod _rt {
+
+ #[cfg(target_arch = "wasm32")]
+ pub fn run_ctors_once() {
+ wit_bindgen_rt::run_ctors_once();
+ }
+ pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
+ if size == 0 {
+ return;
+ }
+ let layout = alloc::Layout::from_size_align_unchecked(size, align);
+ alloc::dealloc(ptr as *mut u8, layout);
+ }
+ pub use alloc_crate::alloc;
+ pub use alloc_crate::string::String;
+ extern crate alloc as alloc_crate;
+}
+
+/// Generates `#[no_mangle]` functions to export the specified type as the
+/// root implementation of all generated traits.
+///
+/// For more information see the documentation of `wit_bindgen::generate!`.
+///
+/// ```rust
+/// # macro_rules! export{ ($($t:tt)*) => (); }
+/// # trait Guest {}
+/// struct MyType;
+///
+/// impl Guest for MyType {
+/// // ...
+/// }
+///
+/// export!(MyType);
+/// ```
+#[allow(unused_macros)]
+#[doc(hidden)]
+
+macro_rules! __export_example_impl {
+ ($ty:ident) => (self::export!($ty with_types_in self););
+ ($ty:ident with_types_in $($path_to_types_root:tt)*) => (
+ $($path_to_types_root)*::__export_world_example_cabi!($ty with_types_in $($path_to_types_root)*);
+ )
+}
+#[doc(inline)]
+pub(crate) use __export_example_impl as export;
+
+#[cfg(target_arch = "wasm32")]
+#[link_section = "component-type:wit-bindgen:0.24.0:example:encoded world"]
+#[doc(hidden)]
+pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 194] = *b"\
+\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07E\x01A\x02\x01A\x02\x01\
+@\0\0s\x04\0\x0bhello-world\x01\0\x04\x01%component:test-wasi-component/example\x04\
+\0\x0b\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dw\
+it-component\x070.202.0\x10wit-bindgen-rust\x060.24.0";
+
+#[inline(never)]
+#[doc(hidden)]
+#[cfg(target_arch = "wasm32")]
+pub fn __link_custom_section_describing_imports() {
+ wit_bindgen_rt::maybe_link_cabi_realloc();
+}
diff --git a/test/wasm_component/hello_world/src/lib.rs b/test/wasm_component/hello_world/src/lib.rs
new file mode 100644
index 00000000..a1e40ef6
--- /dev/null
+++ b/test/wasm_component/hello_world/src/lib.rs
@@ -0,0 +1,31 @@
+use wasi::http::types::{
+ Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam,
+};
+
+wasi::http::proxy::export!(Component);
+
+struct Component;
+
+impl wasi::exports::http::incoming_handler::Guest for Component {
+ fn handle(_request: IncomingRequest, response_out: ResponseOutparam) {
+
+ let hdrs = Fields::new();
+ let mesg = String::from("Hello");
+ let _try = hdrs.set(&"Content-Type".to_string(), &[b"plain/text".to_vec()]);
+ let _try = hdrs.set(&"Content-Length".to_string(), &[mesg.len().to_string().as_bytes().to_vec()]);
+
+ let resp = OutgoingResponse::new(hdrs);
+
+ // Add the HTTP Response Status Code
+ resp.set_status_code(200).unwrap();
+
+ let body = resp.body().unwrap();
+ ResponseOutparam::set(response_out, Ok(resp));
+
+ let out = body.write().unwrap();
+ out.blocking_write_and_flush(mesg.as_bytes()).unwrap();
+ drop(out);
+
+ OutgoingBody::finish(body, None).unwrap();
+ }
+}
diff --git a/test/wasm_component/hello_world/wit/world.wit b/test/wasm_component/hello_world/wit/world.wit
new file mode 100644
index 00000000..82c810ef
--- /dev/null
+++ b/test/wasm_component/hello_world/wit/world.wit
@@ -0,0 +1,6 @@
+package component:test-wasi-component;
+
+/// An example world for the component to target.
+world example {
+ export hello-world: func() -> string;
+}