Path: blob/main/crates/misc/component-async-tests/tests/scenario/round_trip_direct.rs
3120 views
use super::util::{config, make_component};1use component_async_tests::Ctx;2use component_async_tests::util::yield_times;3use futures::stream::{FuturesUnordered, TryStreamExt};4use wasmtime::component::{Linker, ResourceTable, Val};5use wasmtime::{Engine, Result, Store, format_err};6use wasmtime_wasi::WasiCtxBuilder;78#[tokio::test]9pub async fn async_round_trip_direct_stackless() -> Result<()> {10test_round_trip_direct_uncomposed(11test_programs_artifacts::ASYNC_ROUND_TRIP_DIRECT_STACKLESS_COMPONENT,12)13.await14}1516async fn test_round_trip_direct_uncomposed(component: &str) -> Result<()> {17test_round_trip_direct(18&[component],19"hello, world!",20"hello, world! - entered guest - entered host - exited host - exited guest",21)22.await23}2425async fn test_round_trip_direct(26components: &[&str],27input: &str,28expected_output: &str,29) -> Result<()> {30let engine = Engine::new(&config())?;3132let make_store = || {33Store::new(34&engine,35Ctx {36wasi: WasiCtxBuilder::new().inherit_stdio().build(),37table: ResourceTable::default(),38continue_: false,39},40)41};4243let component = make_component(&engine, components).await?;4445// First, test the `wasmtime-wit-bindgen` static API:46{47let mut linker = Linker::new(&engine);4849wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;50component_async_tests::round_trip_direct::bindings::RoundTripDirect::add_to_linker_imports::<51_,52Ctx,53>(&mut linker, |ctx| ctx)?;5455let mut store = make_store();5657let round_trip =58component_async_tests::round_trip_direct::bindings::RoundTripDirect::instantiate_async(59&mut store, &component, &linker,60)61.await?;6263store64.run_concurrent({65let input = input.to_owned();66let expected_output = expected_output.to_owned();67async move |accessor| {68// Start three concurrent calls and then join them all:69let mut futures = FuturesUnordered::new();70for _ in 0..3 {71futures.push(round_trip.call_foo(accessor, input.clone()));72}7374while let Some(value) = futures.try_next().await? {75assert_eq!(expected_output, value);76}7778wasmtime::error::Ok(())79}80})81.await??;82}8384// Now do it again using the dynamic API (except for WASI, where we stick with the static API):85{86let mut linker = Linker::new(&engine);8788wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;89linker90.root()91.func_new_concurrent("foo", |_, _, params, results| {92Box::pin(async move {93yield_times(10).await;94let Some(Val::String(s)) = params.into_iter().next() else {95unreachable!()96};97results[0] = Val::String(format!("{s} - entered host - exited host"));98Ok(())99})100})?;101102let mut store = make_store();103104let instance = linker.instantiate_async(&mut store, &component).await?;105let foo_function = instance106.get_export_index(&mut store, None, "foo")107.ok_or_else(|| format_err!("can't find `foo` in instance"))?;108let foo_function = instance109.get_func(&mut store, foo_function)110.ok_or_else(|| format_err!("can't find `foo` in instance"))?;111112// Start three concurrent calls and then join them all:113store114.run_concurrent(async |store| -> wasmtime::Result<_> {115let mut futures = FuturesUnordered::new();116for _ in 0..3 {117futures.push(async move {118let mut results = vec![Val::Bool(false)];119foo_function120.call_concurrent(store, &[Val::String(input.to_owned())], &mut results)121.await?;122wasmtime::error::Ok(results)123});124}125126while let Some(value) = futures.try_next().await? {127let Some(Val::String(value)) = value.into_iter().next() else {128unreachable!()129};130assert_eq!(expected_output, &value);131}132Ok(())133})134.await??;135}136137Ok(())138}139140141