Skip to content

Commit

Permalink
Tests: initial "wasm-wasi-component" test
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-zelenkov committed Jun 26, 2024
1 parent 8e254a4 commit b8a62b6
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 1 deletion.
18 changes: 18 additions & 0 deletions test/test_wasm_component.py
Original file line number Diff line number Diff line change
@@ -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'
60 changes: 60 additions & 0 deletions test/unit/applications/lang/wasm_component.py
Original file line number Diff line number Diff line change
@@ -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,
)
4 changes: 4 additions & 0 deletions test/unit/check/cargo_component.py
Original file line number Diff line number Diff line change
@@ -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
4 changes: 3 additions & 1 deletion test/unit/check/discover_available.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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])
Expand All @@ -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()
34 changes: 34 additions & 0 deletions test/wasm_component/hello_world/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions test/wasm_component/hello_world/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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]
109 changes: 109 additions & 0 deletions test/wasm_component/hello_world/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -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();
}
31 changes: 31 additions & 0 deletions test/wasm_component/hello_world/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
6 changes: 6 additions & 0 deletions test/wasm_component/hello_world/wit/world.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package component:test-wasi-component;

/// An example world for the component to target.
world example {
export hello-world: func() -> string;
}

0 comments on commit b8a62b6

Please sign in to comment.