Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/misc/component-async-tests/tests/scenario/round_trip_direct.rs
1693 views
1
use std::sync::{Arc, Mutex};
2
use std::time::Duration;
3
4
use super::util::{config, make_component};
5
use anyhow::{Result, anyhow};
6
use component_async_tests::Ctx;
7
use component_async_tests::util::sleep;
8
use futures::stream::{FuturesUnordered, TryStreamExt};
9
use wasmtime::component::{Linker, ResourceTable, Val};
10
use wasmtime::{Engine, Store};
11
use wasmtime_wasi::WasiCtxBuilder;
12
13
#[tokio::test]
14
pub async fn async_round_trip_direct_stackless() -> Result<()> {
15
test_round_trip_direct_uncomposed(
16
test_programs_artifacts::ASYNC_ROUND_TRIP_DIRECT_STACKLESS_COMPONENT,
17
)
18
.await
19
}
20
21
async fn test_round_trip_direct_uncomposed(component: &str) -> Result<()> {
22
test_round_trip_direct(
23
&[component],
24
"hello, world!",
25
"hello, world! - entered guest - entered host - exited host - exited guest",
26
)
27
.await
28
}
29
30
async fn test_round_trip_direct(
31
components: &[&str],
32
input: &str,
33
expected_output: &str,
34
) -> Result<()> {
35
let engine = Engine::new(&config())?;
36
37
let make_store = || {
38
Store::new(
39
&engine,
40
Ctx {
41
wasi: WasiCtxBuilder::new().inherit_stdio().build(),
42
table: ResourceTable::default(),
43
continue_: false,
44
wakers: Arc::new(Mutex::new(None)),
45
},
46
)
47
};
48
49
let component = make_component(&engine, components).await?;
50
51
// First, test the `wasmtime-wit-bindgen` static API:
52
{
53
let mut linker = Linker::new(&engine);
54
55
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
56
component_async_tests::round_trip_direct::bindings::RoundTripDirect::add_to_linker_imports::<
57
_,
58
Ctx,
59
>(&mut linker, |ctx| ctx)?;
60
61
let mut store = make_store();
62
63
let instance = linker.instantiate_async(&mut store, &component).await?;
64
let round_trip = component_async_tests::round_trip_direct::bindings::RoundTripDirect::new(
65
&mut store, &instance,
66
)?;
67
68
instance
69
.run_concurrent(&mut store, {
70
let input = input.to_owned();
71
let expected_output = expected_output.to_owned();
72
async move |accessor| {
73
// Start three concurrent calls and then join them all:
74
let mut futures = FuturesUnordered::new();
75
for _ in 0..3 {
76
futures.push(round_trip.call_foo(accessor, input.clone()));
77
}
78
79
while let Some(value) = futures.try_next().await? {
80
assert_eq!(expected_output, value);
81
}
82
83
anyhow::Ok(())
84
}
85
})
86
.await??;
87
}
88
89
// Now do it again using the dynamic API (except for WASI, where we stick with the static API):
90
{
91
let mut linker = Linker::new(&engine);
92
93
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
94
linker
95
.root()
96
.func_new_concurrent("[async]foo", |_, params, results| {
97
Box::pin(async move {
98
sleep(Duration::from_millis(10)).await;
99
let Some(Val::String(s)) = params.into_iter().next() else {
100
unreachable!()
101
};
102
results[0] = Val::String(format!("{s} - entered host - exited host"));
103
Ok(())
104
})
105
})?;
106
107
let mut store = make_store();
108
109
let instance = linker.instantiate_async(&mut store, &component).await?;
110
let foo_function = instance
111
.get_export_index(&mut store, None, "[async]foo")
112
.ok_or_else(|| anyhow!("can't find `foo` in instance"))?;
113
let foo_function = instance
114
.get_func(&mut store, foo_function)
115
.ok_or_else(|| anyhow!("can't find `foo` in instance"))?;
116
117
// Start three concurrent calls and then join them all:
118
instance
119
.run_concurrent(&mut store, async |store| -> wasmtime::Result<_> {
120
let mut futures = FuturesUnordered::new();
121
for _ in 0..3 {
122
futures.push(async move {
123
let mut results = vec![Val::Bool(false)];
124
foo_function
125
.call_concurrent(store, &[Val::String(input.to_owned())], &mut results)
126
.await?;
127
anyhow::Ok(results)
128
});
129
}
130
131
while let Some(value) = futures.try_next().await? {
132
let Some(Val::String(value)) = value.into_iter().next() else {
133
unreachable!()
134
};
135
assert_eq!(expected_output, &value);
136
}
137
Ok(())
138
})
139
.await??;
140
}
141
142
Ok(())
143
}
144
145