Skip to content

Commit 9441f82

Browse files
committed
Add an HTTP server test.
1 parent 7f23b8f commit 9441f82

File tree

6 files changed

+116
-1
lines changed

6 files changed

+116
-1
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ authors = [
4949
[workspace.dependencies]
5050
anyhow = "1"
5151
cargo_metadata = "0.18.1"
52+
clap = { version = "4.5.23", features = ["derive"] }
5253
futures-core = "0.3.19"
5354
futures-lite = "1.12.0"
5455
heck = "0.5"
@@ -62,8 +63,10 @@ syn = "2.0"
6263
test-log = { version = "0.2", features = ["trace"] }
6364
test-programs = { path = "test-programs" }
6465
test-programs-artifacts = { path = "test-programs/artifacts" }
66+
ureq = "2.12.1"
6567
wasi = "0.13.1"
6668
wasmtime = "26"
69+
wasmtime-cli = "26"
6770
wasmtime-wasi = "26"
6871
wasmtime-wasi-http = "26"
6972
wstd = { path = "." }

examples/http_server.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use wstd::http::body::{BodyForthcoming, IncomingBody, OutgoingBody};
22
use wstd::http::server::{Finished, Responder};
33
use wstd::http::{IntoBody, Request, Response};
4-
use wstd::io::{copy, AsyncWrite};
4+
use wstd::io::{copy, empty, AsyncWrite};
55

66
#[wstd::http_server]
77
async fn main(request: Request<IncomingBody>, responder: Responder) -> Finished {
88
match request.uri().path_and_query().unwrap().as_str() {
99
"/wait" => http_wait(request, responder).await,
1010
"/echo" => http_echo(request, responder).await,
11+
"/echo-headers" => http_echo_headers(request, responder).await,
12+
"/echo-trailers" => http_echo_trailers(request, responder).await,
1113
"/fail" => http_fail(request, responder).await,
1214
"/bigfail" => http_bigfail(request, responder).await,
1315
"/" | _ => http_home(request, responder).await,
@@ -67,3 +69,19 @@ async fn http_bigfail(_request: Request<IncomingBody>, responder: Responder) ->
6769
let _ = write_body(&mut body).await;
6870
Finished::fail(body)
6971
}
72+
73+
async fn http_echo_headers(request: Request<IncomingBody>, responder: Responder) -> Finished {
74+
let mut response = Response::builder();
75+
*response.headers_mut().unwrap() = request.headers().clone();
76+
let response = response.body(empty()).unwrap();
77+
responder.respond(response).await
78+
}
79+
80+
async fn http_echo_trailers(request: Request<IncomingBody>, responder: Responder) -> Finished {
81+
let body = responder.start_response(Response::new(BodyForthcoming));
82+
let (trailers, result) = match request.into_body().finish().await {
83+
Ok(trailers) => (trailers, Ok(())),
84+
Err(err) => (Default::default(), Err(std::io::Error::other(err))),
85+
};
86+
Finished::finish(body, result, trailers)
87+
}

test-programs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ publish = false
88
futures-lite.workspace = true
99
serde_json.workspace = true
1010
wstd.workspace = true
11+
wasi.workspace = true

test-programs/artifacts/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ publish = false
99

1010
[dev-dependencies]
1111
anyhow.workspace = true
12+
clap.workspace = true
1213
test-log.workspace = true
1314
test-programs-artifacts.workspace = true
15+
ureq.workspace = true
1416
wasmtime.workspace = true
17+
wasmtime-cli.workspace = true
1518
wasmtime-wasi.workspace = true
1619
wasmtime-wasi-http.workspace = true
1720

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use anyhow::Result;
2+
3+
fn run_in_wasmtime(wasm: &str) -> Result<()> {
4+
use clap::Parser;
5+
use wasmtime_cli::commands::ServeCommand;
6+
7+
// Run wasmtime serve.
8+
// Enable -Scli because we build with the default adapter rather than the
9+
// proxy adapter.
10+
// Disable logging so that Wasmtime's tracing_subscriber registration
11+
// doesn't conflict with the test harness' registration.
12+
let serve =
13+
match ServeCommand::try_parse_from(["serve", "-Scli", "-Dlogging=n", wasm].into_iter()) {
14+
Ok(serve) => serve,
15+
Err(e) => {
16+
dbg!(&e);
17+
return Err(e.into());
18+
}
19+
};
20+
21+
serve.execute()
22+
}
23+
24+
#[test_log::test]
25+
fn http_server() -> Result<()> {
26+
use std::net::TcpStream;
27+
use std::thread::sleep;
28+
use std::time::Duration;
29+
30+
// Start a `wasmtime serve` server.
31+
let wasmtime_thread =
32+
std::thread::spawn(move || run_in_wasmtime(test_programs_artifacts::HTTP_SERVER));
33+
34+
// Clumsily wait for the server to accept connections.
35+
'wait: loop {
36+
sleep(Duration::from_millis(100));
37+
if TcpStream::connect("127.0.0.1:8080").is_ok() {
38+
break 'wait;
39+
}
40+
}
41+
42+
// Do some tests!
43+
44+
let body: String = ureq::get("http://127.0.0.1:8080").call()?.into_string()?;
45+
assert_eq!(body, "Hello, wasi:http/proxy world!\n");
46+
47+
match ureq::get("http://127.0.0.1:8080/fail").call() {
48+
Ok(body) => {
49+
unreachable!("unexpected success from /fail: {:?}", body);
50+
}
51+
Err(ureq::Error::Transport(_transport)) => {}
52+
Err(other) => {
53+
unreachable!("unexpected error: {:?}", other);
54+
}
55+
}
56+
57+
const MESSAGE: &[u8] = b"hello, echoserver!\n";
58+
59+
let body: String = ureq::get("http://127.0.0.1:8080/echo")
60+
.send(MESSAGE)?
61+
.into_string()?;
62+
assert_eq!(body.as_bytes(), MESSAGE);
63+
64+
let test_headers = [
65+
("Red", "Rhubarb"),
66+
("Orange", "Carrots"),
67+
("Yellow", "Bananas"),
68+
("Green", "Broccoli"),
69+
("Blue", "Blueberries"),
70+
("Purple", "Beets"),
71+
];
72+
73+
let mut response = ureq::get("http://127.0.0.1:8080/echo-headers");
74+
for (name, value) in test_headers {
75+
response = response.set(name, value);
76+
}
77+
let response = response.call()?;
78+
79+
assert!(response.headers_names().len() >= test_headers.len());
80+
for (name, value) in test_headers {
81+
assert_eq!(response.header(name), Some(value));
82+
}
83+
84+
if wasmtime_thread.is_finished() {
85+
wasmtime_thread.join().expect("wasmtime panicked")?;
86+
}
87+
88+
Ok(())
89+
}

test-programs/src/bin/http_server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include!("../../../examples/http_server.rs");

0 commit comments

Comments
 (0)