Path: blob/main/crates/misc/component-async-tests/tests/scenario/round_trip_direct.rs
1693 views
use std::sync::{Arc, Mutex};1use std::time::Duration;23use super::util::{config, make_component};4use anyhow::{Result, anyhow};5use component_async_tests::Ctx;6use component_async_tests::util::sleep;7use futures::stream::{FuturesUnordered, TryStreamExt};8use wasmtime::component::{Linker, ResourceTable, Val};9use wasmtime::{Engine, Store};10use wasmtime_wasi::WasiCtxBuilder;1112#[tokio::test]13pub async fn async_round_trip_direct_stackless() -> Result<()> {14test_round_trip_direct_uncomposed(15test_programs_artifacts::ASYNC_ROUND_TRIP_DIRECT_STACKLESS_COMPONENT,16)17.await18}1920async fn test_round_trip_direct_uncomposed(component: &str) -> Result<()> {21test_round_trip_direct(22&[component],23"hello, world!",24"hello, world! - entered guest - entered host - exited host - exited guest",25)26.await27}2829async fn test_round_trip_direct(30components: &[&str],31input: &str,32expected_output: &str,33) -> Result<()> {34let engine = Engine::new(&config())?;3536let make_store = || {37Store::new(38&engine,39Ctx {40wasi: WasiCtxBuilder::new().inherit_stdio().build(),41table: ResourceTable::default(),42continue_: false,43wakers: Arc::new(Mutex::new(None)),44},45)46};4748let component = make_component(&engine, components).await?;4950// First, test the `wasmtime-wit-bindgen` static API:51{52let mut linker = Linker::new(&engine);5354wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;55component_async_tests::round_trip_direct::bindings::RoundTripDirect::add_to_linker_imports::<56_,57Ctx,58>(&mut linker, |ctx| ctx)?;5960let mut store = make_store();6162let instance = linker.instantiate_async(&mut store, &component).await?;63let round_trip = component_async_tests::round_trip_direct::bindings::RoundTripDirect::new(64&mut store, &instance,65)?;6667instance68.run_concurrent(&mut store, {69let input = input.to_owned();70let expected_output = expected_output.to_owned();71async move |accessor| {72// Start three concurrent calls and then join them all:73let mut futures = FuturesUnordered::new();74for _ in 0..3 {75futures.push(round_trip.call_foo(accessor, input.clone()));76}7778while let Some(value) = futures.try_next().await? {79assert_eq!(expected_output, value);80}8182anyhow::Ok(())83}84})85.await??;86}8788// Now do it again using the dynamic API (except for WASI, where we stick with the static API):89{90let mut linker = Linker::new(&engine);9192wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;93linker94.root()95.func_new_concurrent("[async]foo", |_, params, results| {96Box::pin(async move {97sleep(Duration::from_millis(10)).await;98let Some(Val::String(s)) = params.into_iter().next() else {99unreachable!()100};101results[0] = Val::String(format!("{s} - entered host - exited host"));102Ok(())103})104})?;105106let mut store = make_store();107108let instance = linker.instantiate_async(&mut store, &component).await?;109let foo_function = instance110.get_export_index(&mut store, None, "[async]foo")111.ok_or_else(|| anyhow!("can't find `foo` in instance"))?;112let foo_function = instance113.get_func(&mut store, foo_function)114.ok_or_else(|| anyhow!("can't find `foo` in instance"))?;115116// Start three concurrent calls and then join them all:117instance118.run_concurrent(&mut store, async |store| -> wasmtime::Result<_> {119let mut futures = FuturesUnordered::new();120for _ in 0..3 {121futures.push(async move {122let mut results = vec![Val::Bool(false)];123foo_function124.call_concurrent(store, &[Val::String(input.to_owned())], &mut results)125.await?;126anyhow::Ok(results)127});128}129130while let Some(value) = futures.try_next().await? {131let Some(Val::String(value)) = value.into_iter().next() else {132unreachable!()133};134assert_eq!(expected_output, &value);135}136Ok(())137})138.await??;139}140141Ok(())142}143144145