Skip to content

Commit b43c699

Browse files
committed
run the echo server
1 parent c837c06 commit b43c699

File tree

2 files changed

+122
-6
lines changed

2 files changed

+122
-6
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ url.workspace = true
2121
wasi.workspace = true
2222

2323
[dev-dependencies]
24+
anyhow.workspace = true
2425
test-program-suite.workspace = true
2526
wasmtime.workspace = true
27+
wasmtime-wasi.workspace = true
28+
wasmtime-wasi-http.workspace = true
2629

2730
[workspace]
2831
members = [
@@ -36,6 +39,7 @@ edition = "2021"
3639
license = "MIT OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception"
3740

3841
[workspace.dependencies]
42+
anyhow = "1"
3943
cargo_metadata = "0.18.1"
4044
heck = "0.5"
4145
slab = "0.4.9"
@@ -45,3 +49,5 @@ url = "2.5.0"
4549
wasi = "0.13.1"
4650
wstd = { path = "." }
4751
wasmtime = "26"
52+
wasmtime-wasi = "26"
53+
wasmtime-wasi-http = "26"

tests/test-programs.rs

Lines changed: 116 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,119 @@
1-
use wasmtime::{component::Component, Config, Engine};
1+
use anyhow::{anyhow, Context, Result};
2+
use wasmtime::{
3+
component::{Component, Linker, ResourceTable},
4+
Config, Engine, Store,
5+
};
6+
use wasmtime_wasi::{StdoutStream, WasiCtx, WasiView};
7+
use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView};
28

3-
#[test]
4-
fn tcp_echo_server() {
5-
let wasm = std::fs::read(test_program_suite::TCP_ECHO_SERVER).unwrap();
9+
struct Ctx {
10+
table: ResourceTable,
11+
wasi: WasiCtx,
12+
http: WasiHttpCtx,
13+
}
14+
15+
impl WasiView for Ctx {
16+
fn table(&mut self) -> &mut ResourceTable {
17+
&mut self.table
18+
}
19+
fn ctx(&mut self) -> &mut WasiCtx {
20+
&mut self.wasi
21+
}
22+
}
23+
24+
impl WasiHttpView for Ctx {
25+
fn table(&mut self) -> &mut ResourceTable {
26+
&mut self.table
27+
}
28+
fn ctx(&mut self) -> &mut WasiHttpCtx {
29+
&mut self.http
30+
}
31+
}
32+
33+
fn run_in_wasmtime(wasm: &[u8], stdout: impl StdoutStream + 'static) -> Result<()> {
634
let config = Config::default();
7-
let engine = Engine::new(&config).unwrap();
8-
let _component = Component::new(&engine, wasm).unwrap();
35+
let engine = Engine::new(&config).context("creating engine")?;
36+
let component = Component::new(&engine, wasm).context("loading component")?;
37+
38+
let mut linker: Linker<Ctx> = Linker::new(&engine);
39+
wasmtime_wasi::add_to_linker_sync(&mut linker).context("add wasi to linker")?;
40+
wasmtime_wasi_http::add_only_http_to_linker_sync(&mut linker)
41+
.context("add wasi-http to linker")?;
42+
43+
let mut store = Store::new(
44+
&engine,
45+
Ctx {
46+
table: ResourceTable::new(),
47+
wasi: WasiCtx::builder()
48+
.stdout(stdout)
49+
.inherit_stderr()
50+
.inherit_network()
51+
.build(),
52+
http: WasiHttpCtx::new(),
53+
},
54+
);
55+
56+
let instance = linker.instantiate(&mut store, &component)?;
57+
let run_interface = instance
58+
.get_export(&mut store, None, "wasi:cli/[email protected]")
59+
.ok_or_else(|| anyhow!("wasi:cli/run missing?"))?;
60+
let run_func_export = instance
61+
.get_export(&mut store, Some(&run_interface), "run")
62+
.ok_or_else(|| anyhow!("run export missing?"))?;
63+
let run_func = instance
64+
.get_typed_func::<(), (Result<(), ()>,)>(&mut store, &run_func_export)
65+
.context("run as typed func")?;
66+
67+
println!("entering wasm...");
68+
let (runtime_result,) = run_func.call(&mut store, ())?;
69+
runtime_result.map_err(|()| anyhow!("run returned an error"))?;
70+
println!("done");
71+
72+
Ok(())
73+
}
74+
75+
#[test]
76+
fn tcp_echo_server() -> Result<()> {
77+
use std::io::{Read, Write};
78+
use std::net::TcpStream;
79+
use std::thread::sleep;
80+
use std::time::Duration;
81+
82+
println!("testing {}", test_program_suite::TCP_ECHO_SERVER);
83+
let wasm = std::fs::read(test_program_suite::TCP_ECHO_SERVER).context("read wasm")?;
84+
85+
let pipe = wasmtime_wasi::pipe::MemoryOutputPipe::new(1024 * 1024);
86+
let write_end = pipe.clone();
87+
let wasmtime_thread = std::thread::spawn(move || run_in_wasmtime(&wasm, write_end));
88+
89+
'wait: loop {
90+
sleep(Duration::from_millis(100));
91+
for line in pipe.contents().split(|c| *c == b'\n') {
92+
if line.starts_with(b"Listening on") {
93+
break 'wait;
94+
}
95+
}
96+
}
97+
98+
let mut tcpstream =
99+
TcpStream::connect("127.0.0.1:8080").context("connect to wasm echo server")?;
100+
println!("connected to wasm echo server");
101+
102+
const MESSAGE: &[u8] = b"hello, echoserver!\n";
103+
104+
tcpstream.write_all(MESSAGE).context("write to socket")?;
105+
println!("wrote to echo server");
106+
107+
let mut readback = Vec::new();
108+
tcpstream
109+
.read_to_end(&mut readback)
110+
.context("read from socket")?;
111+
112+
println!("read from wasm server");
113+
assert_eq!(MESSAGE, readback);
114+
115+
if wasmtime_thread.is_finished() {
116+
wasmtime_thread.join().expect("wasmtime panicked")?;
117+
}
118+
Ok(())
9119
}

0 commit comments

Comments
 (0)