Merge pull request #107 from radu-matei/integration-tests
This commit is contained in:
commit
6651c2ca8d
|
@ -2841,6 +2841,7 @@ dependencies = [
|
|||
"dunce",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"hyper",
|
||||
"path-absolutize",
|
||||
"semver",
|
||||
"serde",
|
||||
|
|
|
@ -31,6 +31,9 @@ tracing = { version = "0.1", features = [ "log" ] }
|
|||
tracing-futures = "0.2"
|
||||
tracing-subscriber = { version = "0.3.7", features = [ "env-filter" ] }
|
||||
|
||||
[dev-dependencies]
|
||||
hyper = { version = "0.14", features = [ "full" ] }
|
||||
|
||||
[workspace]
|
||||
members = [ "crates/config", "crates/engine", "crates/http", "crates/loader", "crates/templates" ]
|
||||
|
||||
|
|
7
build.rs
7
build.rs
|
@ -8,9 +8,11 @@ const HTTP_TEST: &str = "crates/http/tests/rust-http-test";
|
|||
|
||||
const REDIS_WIT: &str = "crates/redis/wit/spin_redis_trigger_v01.wit";
|
||||
const REDIS_TEST_RUST: &str = "crates/redis/tests/rust";
|
||||
|
||||
const WAGI_TEST: &str = "crates/http/tests/wagi-test";
|
||||
|
||||
const RUST_HTTP_INTEGRATION_TEST: &str = "tests/http/simple-spin-rust";
|
||||
const RUST_HTTP_INTEGRATION_ENV_TEST: &str = "tests/http/headers-env-routes-test";
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
|
@ -25,6 +27,9 @@ fn main() {
|
|||
cargo_build(HTTP_TEST);
|
||||
cargo_build(REDIS_TEST_RUST);
|
||||
cargo_build(WAGI_TEST);
|
||||
|
||||
cargo_build(RUST_HTTP_INTEGRATION_TEST);
|
||||
cargo_build(RUST_HTTP_INTEGRATION_ENV_TEST);
|
||||
}
|
||||
|
||||
fn cargo_build(dir: &str) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
apiVersion = "0.1.0"
|
||||
authors = ["Radu Matei <radu@fermyon.com>"]
|
||||
description = "A simple application that returns hello and goodbye."
|
||||
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
||||
description = "A simple application that returns hello."
|
||||
name = "spin-hello-world"
|
||||
trigger = {type = "http", base = "/test"}
|
||||
version = "1.0.0"
|
||||
|
|
|
@ -4,7 +4,7 @@ use spin_http::{Request, Response};
|
|||
// Generate Rust bindings for interface defined in spin-http.wit file
|
||||
wit_bindgen_rust::export!("spin-http.wit");
|
||||
|
||||
struct SpinHttp {}
|
||||
struct SpinHttp;
|
||||
impl spin_http::SpinHttp for SpinHttp {
|
||||
// Implement the `handler` entrypoint for Spin HTTP components.
|
||||
fn handler(req: Request) -> Response {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion = "0.1.0"
|
||||
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
||||
name = "spin-assets-test"
|
||||
trigger = {type = "http", base = "/"}
|
||||
version = "1.0.0"
|
||||
|
||||
[[component]]
|
||||
id = "fs"
|
||||
source = "spin_static_fs.wasm"
|
||||
files = ["static/thisshouldbemounted/*"]
|
||||
environment = { PATH_PREFIX = "static/" }
|
||||
[component.trigger]
|
||||
executor = {type = "spin"}
|
||||
route = "/static/..."
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
a
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1 @@
|
|||
2
|
|
@ -0,0 +1 @@
|
|||
3
|
|
@ -0,0 +1,206 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "env"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-gen-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-gen-rust"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"wit-bindgen-gen-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-gen-rust-wasm"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"wit-bindgen-gen-core",
|
||||
"wit-bindgen-gen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-impl"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"wit-bindgen-gen-core",
|
||||
"wit-bindgen-gen-rust-wasm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"pulldown-cmark",
|
||||
"unicode-normalization",
|
||||
"unicode-xid",
|
||||
]
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "env"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = [ "cdylib" ]
|
||||
|
||||
[dependencies]
|
||||
# The wit-bindgen-rust dependency generates bindings for interfaces.
|
||||
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
||||
|
||||
[workspace]
|
||||
|
||||
# Metadata about this component.
|
||||
[package.metadata.component]
|
||||
name = "spinhelloworld"
|
|
@ -0,0 +1,61 @@
|
|||
// The entrypoint for an HTTP handler.
|
||||
handler: function(req: request) -> response
|
||||
|
||||
// This is a temporary workaround very similar to https://github.com/deislabs/wasi-experimental-http.
|
||||
// Once asynchronous functions, streams, and the upstream HTTP API are available, this should be removed.
|
||||
|
||||
// The HTTP status code.
|
||||
// This is currently an unsigned 16-bit integer,
|
||||
// but it could be represented as an enum containing
|
||||
// all possible HTTP status codes.
|
||||
type http-status = u16
|
||||
|
||||
// The HTTP body.
|
||||
// Currently, this is a synchonous byte array, but it should be
|
||||
// possible to have a stream for both request and response bodies.
|
||||
type body = list<u8>
|
||||
|
||||
// The HTTP headers represented as a list of (name, value) pairs.
|
||||
type headers = list<tuple<string, string>>
|
||||
|
||||
// The HTTP parameter queries, represented as a list of (name, value) pairs.
|
||||
type params = list<tuple<string, string>>
|
||||
|
||||
// The HTTP URI of the current request.
|
||||
type uri = string
|
||||
|
||||
// The HTTP method.
|
||||
enum method {
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete,
|
||||
patch,
|
||||
head,
|
||||
options,
|
||||
}
|
||||
|
||||
// An HTTP request.
|
||||
record request {
|
||||
method: method,
|
||||
uri: uri,
|
||||
headers: headers,
|
||||
params: params,
|
||||
body: option<body>,
|
||||
}
|
||||
|
||||
// An HTTP response.
|
||||
record response {
|
||||
status: http-status,
|
||||
headers: option<headers>,
|
||||
body: option<body>,
|
||||
}
|
||||
|
||||
// HTTP errors returned by the runtime.
|
||||
enum http-error {
|
||||
success,
|
||||
destination-not-allowed,
|
||||
invalid-url,
|
||||
request-error,
|
||||
runtime-error,
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion = "0.1.0"
|
||||
name = "spin-headers-env-routes-test"
|
||||
version = "1.0.0"
|
||||
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
||||
description = "A simple application that returns hello and goodbye."
|
||||
trigger = {type = "http", base = "/"}
|
||||
|
||||
[[component]]
|
||||
id = "env"
|
||||
source = "target/wasm32-wasi/release/env.wasm"
|
||||
environment = { some_key = "some_value" }
|
||||
[component.trigger]
|
||||
route = "/env/..."
|
|
@ -0,0 +1,41 @@
|
|||
// Import the HTTP objects from the generated bindings.
|
||||
use spin_http::{Request, Response};
|
||||
|
||||
// Generate Rust bindings for interface defined in spin-http.wit file
|
||||
wit_bindgen_rust::export!("spin-http.wit");
|
||||
|
||||
struct SpinHttp;
|
||||
impl spin_http::SpinHttp for SpinHttp {
|
||||
// Implement the `handler` entrypoint for Spin HTTP components.
|
||||
// This handler does the following:
|
||||
// - returns all environment variables as headers with an ENV_ prefix
|
||||
// - returns all request headers as response headers.
|
||||
fn handler(req: Request) -> Response {
|
||||
let mut headers = Self::env_to_headers();
|
||||
Self::append_request_headers(&mut headers, &req.headers);
|
||||
let headers = Some(headers);
|
||||
Response {
|
||||
status: 200,
|
||||
headers,
|
||||
body: Some("I'm a teapot".as_bytes().to_vec()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpinHttp {
|
||||
fn env_to_headers() -> Vec<(String, String)> {
|
||||
let mut res = vec![];
|
||||
std::env::vars().for_each(|(k, v)| res.push((format!("ENV_{}", k), v)));
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn append_request_headers(
|
||||
res_headers: &mut Vec<(String, String)>,
|
||||
req_headers: &[(String, String)],
|
||||
) {
|
||||
for (k, v) in req_headers {
|
||||
res_headers.push((k.clone(), v.clone()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
target = "wasm32-wasi"
|
|
@ -0,0 +1,206 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinhelloworld"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-gen-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-gen-rust"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"wit-bindgen-gen-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-gen-rust-wasm"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"wit-bindgen-gen-core",
|
||||
"wit-bindgen-gen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-impl"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"wit-bindgen-gen-core",
|
||||
"wit-bindgen-gen-rust-wasm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=e9c7c0a3405845cecd3fe06f3c20ab413302fc73#e9c7c0a3405845cecd3fe06f3c20ab413302fc73"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"pulldown-cmark",
|
||||
"unicode-normalization",
|
||||
"unicode-xid",
|
||||
]
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "spinhelloworld"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = [ "cdylib" ]
|
||||
|
||||
[dependencies]
|
||||
# The wit-bindgen-rust dependency generates bindings for interfaces.
|
||||
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
||||
|
||||
[workspace]
|
||||
|
||||
# Metadata about this component.
|
||||
[package.metadata.component]
|
||||
name = "spinhelloworld"
|
|
@ -0,0 +1,61 @@
|
|||
// The entrypoint for an HTTP handler.
|
||||
handler: function(req: request) -> response
|
||||
|
||||
// This is a temporary workaround very similar to https://github.com/deislabs/wasi-experimental-http.
|
||||
// Once asynchronous functions, streams, and the upstream HTTP API are available, this should be removed.
|
||||
|
||||
// The HTTP status code.
|
||||
// This is currently an unsigned 16-bit integer,
|
||||
// but it could be represented as an enum containing
|
||||
// all possible HTTP status codes.
|
||||
type http-status = u16
|
||||
|
||||
// The HTTP body.
|
||||
// Currently, this is a synchonous byte array, but it should be
|
||||
// possible to have a stream for both request and response bodies.
|
||||
type body = list<u8>
|
||||
|
||||
// The HTTP headers represented as a list of (name, value) pairs.
|
||||
type headers = list<tuple<string, string>>
|
||||
|
||||
// The HTTP parameter queries, represented as a list of (name, value) pairs.
|
||||
type params = list<tuple<string, string>>
|
||||
|
||||
// The HTTP URI of the current request.
|
||||
type uri = string
|
||||
|
||||
// The HTTP method.
|
||||
enum method {
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete,
|
||||
patch,
|
||||
head,
|
||||
options,
|
||||
}
|
||||
|
||||
// An HTTP request.
|
||||
record request {
|
||||
method: method,
|
||||
uri: uri,
|
||||
headers: headers,
|
||||
params: params,
|
||||
body: option<body>,
|
||||
}
|
||||
|
||||
// An HTTP response.
|
||||
record response {
|
||||
status: http-status,
|
||||
headers: option<headers>,
|
||||
body: option<body>,
|
||||
}
|
||||
|
||||
// HTTP errors returned by the runtime.
|
||||
enum http-error {
|
||||
success,
|
||||
destination-not-allowed,
|
||||
invalid-url,
|
||||
request-error,
|
||||
runtime-error,
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion = "0.1.0"
|
||||
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
||||
description = "A simple application that returns hello and goodbye."
|
||||
name = "spin-hello-world"
|
||||
trigger = {type = "http", base = "/test"}
|
||||
version = "1.0.0"
|
||||
|
||||
[[component]]
|
||||
id = "hello"
|
||||
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
||||
[component.trigger]
|
||||
route = "/hello/..."
|
|
@ -0,0 +1,17 @@
|
|||
// Import the HTTP objects from the generated bindings.
|
||||
use spin_http::{Request, Response};
|
||||
|
||||
// Generate Rust bindings for interface defined in spin-http.wit file
|
||||
wit_bindgen_rust::export!("spin-http.wit");
|
||||
|
||||
struct SpinHttp {}
|
||||
impl spin_http::SpinHttp for SpinHttp {
|
||||
// Implement the `handler` entrypoint for Spin HTTP components.
|
||||
fn handler(req: Request) -> Response {
|
||||
Response {
|
||||
status: 200,
|
||||
headers: None,
|
||||
body: Some("I'm a teapot".as_bytes().to_vec()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,396 @@
|
|||
#[cfg(test)]
|
||||
mod integration_tests {
|
||||
use anyhow::{Context, Result};
|
||||
use hyper::{header::HeaderName, Body, Client, Response};
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
net::{Ipv4Addr, SocketAddrV4, TcpListener},
|
||||
process::{self, Child, Command},
|
||||
time::Duration,
|
||||
};
|
||||
use tempfile::TempDir;
|
||||
use tokio::{net::TcpStream, time::sleep};
|
||||
|
||||
const RUST_HTTP_INTEGRATION_TEST: &str = "tests/http/simple-spin-rust";
|
||||
const RUST_HTTP_INTEGRATION_TEST_REF: &str = "spin-hello-world/1.0.0";
|
||||
|
||||
const RUST_HTTP_STATIC_ASSETS_TEST: &str = "tests/http/assets-test";
|
||||
const RUST_HTTP_STATIC_ASSETS_REST_REF: &str = "spin-assets-test/1.0.0";
|
||||
|
||||
const RUST_HTTP_HEADERS_ENV_ROUTES_TEST: &str = "tests/http/headers-env-routes-test";
|
||||
const RUST_HTTP_HEADERS_ENV_ROUTES_TEST_REF: &str = "spin-headers-env-routes-test/1.0.0";
|
||||
|
||||
const DEFAULT_MANIFEST_LOCATION: &str = "spin.toml";
|
||||
|
||||
const SPIN_BINARY: &str = "./target/debug/spin";
|
||||
const BINDLE_SERVER_BINARY: &str = "bindle-server";
|
||||
|
||||
// This assumes all tests have been previously compiled by the top-level build script.
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_simple_rust_local() -> Result<()> {
|
||||
let s = SpinTestController::with_manifest(
|
||||
&format!(
|
||||
"{}/{}",
|
||||
RUST_HTTP_INTEGRATION_TEST, DEFAULT_MANIFEST_LOCATION
|
||||
),
|
||||
&[],
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_status(&s, "/test/hello", 200).await?;
|
||||
assert_status(&s, "/test/hello/wildcards/should/be/handled", 200).await?;
|
||||
assert_status(&s, "/thisshouldfail", 404).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_bindle_roundtrip() -> Result<()> {
|
||||
// start the Bindle registry.
|
||||
let b = BindleTestController::new().await?;
|
||||
|
||||
// push the application to the registry using the Spin CLI.
|
||||
run(
|
||||
vec![
|
||||
SPIN_BINARY,
|
||||
"bindle",
|
||||
"push",
|
||||
"--file",
|
||||
&format!(
|
||||
"{}/{}",
|
||||
RUST_HTTP_INTEGRATION_TEST, DEFAULT_MANIFEST_LOCATION
|
||||
),
|
||||
"--bindle-server",
|
||||
&b.url,
|
||||
],
|
||||
None,
|
||||
)?;
|
||||
|
||||
// start Spin using the bindle reference of the application that was just pushed.
|
||||
let s =
|
||||
SpinTestController::with_bindle(RUST_HTTP_INTEGRATION_TEST_REF, &b.url, &[]).await?;
|
||||
|
||||
assert_status(&s, "/test/hello", 200).await?;
|
||||
assert_status(&s, "/test/hello/wildcards/should/be/handled", 200).await?;
|
||||
assert_status(&s, "/thisshouldfail", 404).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_bindle_static_assets() -> Result<()> {
|
||||
// start the Bindle registry.
|
||||
let b = BindleTestController::new().await?;
|
||||
|
||||
// push the application to the registry using the Spin CLI.
|
||||
run(
|
||||
vec![
|
||||
SPIN_BINARY,
|
||||
"bindle",
|
||||
"push",
|
||||
"--file",
|
||||
&format!(
|
||||
"{}/{}",
|
||||
RUST_HTTP_STATIC_ASSETS_TEST, DEFAULT_MANIFEST_LOCATION
|
||||
),
|
||||
"--bindle-server",
|
||||
&b.url,
|
||||
],
|
||||
None,
|
||||
)?;
|
||||
|
||||
// start Spin using the bindle reference of the application that was just pushed.
|
||||
let s =
|
||||
SpinTestController::with_bindle(RUST_HTTP_STATIC_ASSETS_REST_REF, &b.url, &[]).await?;
|
||||
|
||||
assert_status(&s, "/static/thisshouldbemounted/1", 200).await?;
|
||||
assert_status(&s, "/static/thisshouldbemounted/2", 200).await?;
|
||||
assert_status(&s, "/static/thisshouldbemounted/3", 200).await?;
|
||||
|
||||
assert_status(&s, "/static/donotmount/a", 404).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_headers_env_routes() -> Result<()> {
|
||||
// start the Bindle registry.
|
||||
let b = BindleTestController::new().await?;
|
||||
|
||||
// push the application to the registry using the Spin CLI.
|
||||
run(
|
||||
vec![
|
||||
SPIN_BINARY,
|
||||
"bindle",
|
||||
"push",
|
||||
"--file",
|
||||
&format!(
|
||||
"{}/{}",
|
||||
RUST_HTTP_HEADERS_ENV_ROUTES_TEST, DEFAULT_MANIFEST_LOCATION
|
||||
),
|
||||
"--bindle-server",
|
||||
&b.url,
|
||||
],
|
||||
None,
|
||||
)?;
|
||||
|
||||
// start Spin using the bindle reference of the application that was just pushed.
|
||||
let s = SpinTestController::with_bindle(
|
||||
RUST_HTTP_HEADERS_ENV_ROUTES_TEST_REF,
|
||||
&b.url,
|
||||
&["foo=bar"],
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_status(&s, "/env", 200).await?;
|
||||
|
||||
verify_headers(
|
||||
&s,
|
||||
"/env/foo",
|
||||
200,
|
||||
&[("env_foo", "bar"), ("env_some_key", "some_value")],
|
||||
"/foo",
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn verify_headers(
|
||||
s: &SpinTestController,
|
||||
absolute_uri: &str,
|
||||
expected: u16,
|
||||
expected_env_as_headers: &[(&str, &str)],
|
||||
expected_path_info: &str,
|
||||
) -> Result<()> {
|
||||
let res = req(s, absolute_uri).await?;
|
||||
assert_eq!(res.status(), expected);
|
||||
|
||||
// check the environment variables sent back as headers:
|
||||
for (k, v) in expected_env_as_headers {
|
||||
assert_eq!(
|
||||
&res.headers()
|
||||
.get(HeaderName::from_bytes(k.as_bytes())?)
|
||||
.unwrap_or_else(|| panic!("cannot find header {}", k))
|
||||
.to_str()?,
|
||||
v
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
res.headers()
|
||||
.get(HeaderName::from_bytes("PATH_INFO".as_bytes())?)
|
||||
.unwrap_or_else(|| panic!("cannot find PATH_INFO header"))
|
||||
.to_str()?,
|
||||
expected_path_info
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn assert_status(
|
||||
s: &SpinTestController,
|
||||
absolute_uri: &str,
|
||||
expected: u16,
|
||||
) -> Result<()> {
|
||||
let res = req(s, absolute_uri).await?;
|
||||
assert_eq!(res.status(), expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn req(s: &SpinTestController, absolute_uri: &str) -> Result<Response<Body>> {
|
||||
let c = Client::new();
|
||||
let url = format!("http://{}{}", s.url, absolute_uri)
|
||||
.parse()
|
||||
.with_context(|| "cannot parse URL")?;
|
||||
Ok(c.get(url).await?)
|
||||
}
|
||||
|
||||
/// Controller for running Spin.
|
||||
pub struct SpinTestController {
|
||||
pub url: String,
|
||||
spin_handle: Child,
|
||||
}
|
||||
|
||||
impl SpinTestController {
|
||||
pub async fn with_manifest(
|
||||
manifest_path: &str,
|
||||
env: &[&str],
|
||||
) -> Result<SpinTestController> {
|
||||
// start Spin using the given application manifest and wait for the HTTP server to be available.
|
||||
let url = format!("127.0.0.1:{}", get_random_port()?);
|
||||
let mut args = vec!["up", "--file", manifest_path, "--listen", &url];
|
||||
for v in env {
|
||||
args.push("--env");
|
||||
args.push(v);
|
||||
}
|
||||
|
||||
let spin_handle = Command::new(get_process(SPIN_BINARY))
|
||||
.args(args)
|
||||
.env(
|
||||
"RUST_LOG",
|
||||
"spin=trace,spin_loader=trace,spin_engine=trace,spin_http=trace",
|
||||
)
|
||||
.spawn()
|
||||
.with_context(|| "executing Spin")?;
|
||||
|
||||
// ensure the server is accepting requests before continuing.
|
||||
wait_tcp(&url, SPIN_BINARY).await?;
|
||||
|
||||
Ok(SpinTestController { url, spin_handle })
|
||||
}
|
||||
|
||||
// Unfortunately, this is a lot of duplicated code.
|
||||
pub async fn with_bindle(
|
||||
id: &str,
|
||||
bindle_url: &str,
|
||||
env: &[&str],
|
||||
) -> Result<SpinTestController> {
|
||||
let url = format!("127.0.0.1:{}", get_random_port()?);
|
||||
let mut args = vec![
|
||||
"up", "--bindle", id, "--server", bindle_url, "--listen", &url,
|
||||
];
|
||||
for v in env {
|
||||
args.push("--env");
|
||||
args.push(v);
|
||||
}
|
||||
|
||||
let spin_handle = Command::new(get_process(SPIN_BINARY))
|
||||
.args(args)
|
||||
.env(
|
||||
"RUST_LOG",
|
||||
"spin=trace,spin_loader=trace,spin_engine=trace,spin_http=trace",
|
||||
)
|
||||
.spawn()
|
||||
.with_context(|| "executing Spin")?;
|
||||
|
||||
// ensure the server is accepting requests before continuing.
|
||||
wait_tcp(&url, SPIN_BINARY).await?;
|
||||
|
||||
Ok(SpinTestController { url, spin_handle })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SpinTestController {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.spin_handle.kill();
|
||||
}
|
||||
}
|
||||
|
||||
/// Controller for running a Bindle server.
|
||||
/// This assumes `bindle-server` is present in the path.
|
||||
pub struct BindleTestController {
|
||||
pub url: String,
|
||||
pub server_cache: TempDir,
|
||||
server_handle: Child,
|
||||
}
|
||||
|
||||
impl BindleTestController {
|
||||
pub async fn new() -> Result<BindleTestController> {
|
||||
let server_cache = tempfile::tempdir()?;
|
||||
|
||||
let address = format!("127.0.0.1:{}", get_random_port()?);
|
||||
let url = format!("http://{}/v1/", address);
|
||||
|
||||
let server_handle = Command::new(BINDLE_SERVER_BINARY)
|
||||
.args(&[
|
||||
"-d",
|
||||
server_cache.path().to_string_lossy().to_string().as_str(),
|
||||
"-i",
|
||||
address.as_str(),
|
||||
"--unauthenticated",
|
||||
])
|
||||
.spawn()
|
||||
.with_context(|| format!("executing {}", BINDLE_SERVER_BINARY))?;
|
||||
|
||||
wait_tcp(&address, BINDLE_SERVER_BINARY).await?;
|
||||
|
||||
Ok(Self {
|
||||
url,
|
||||
server_handle,
|
||||
server_cache,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BindleTestController {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.server_handle.kill();
|
||||
}
|
||||
}
|
||||
|
||||
fn run<S: Into<String> + AsRef<OsStr>>(args: Vec<S>, dir: Option<S>) -> Result<()> {
|
||||
let mut cmd = Command::new(get_os_process());
|
||||
cmd.stdout(process::Stdio::piped());
|
||||
cmd.stderr(process::Stdio::piped());
|
||||
|
||||
if let Some(dir) = dir {
|
||||
cmd.current_dir(dir.into());
|
||||
};
|
||||
|
||||
cmd.arg("-c");
|
||||
cmd.arg(
|
||||
args.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<String>>()
|
||||
.join(" "),
|
||||
);
|
||||
|
||||
let output = cmd.output()?;
|
||||
let code = output.status.code().expect("should have status code");
|
||||
if code != 0 {
|
||||
println!("{:#?}", std::str::from_utf8(&output.stderr)?);
|
||||
println!("{:#?}", std::str::from_utf8(&output.stdout)?);
|
||||
panic!("command `{:?}` exited with code {}", cmd, code);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_process(binary: &str) -> String {
|
||||
if cfg!(target_os = "windows") {
|
||||
format!("{}.exe", binary)
|
||||
} else {
|
||||
binary.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_os_process() -> String {
|
||||
if cfg!(target_os = "windows") {
|
||||
String::from("powershell.exe")
|
||||
} else {
|
||||
String::from("/bin/bash")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_random_port() -> Result<u16> {
|
||||
Ok(
|
||||
TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?
|
||||
.local_addr()?
|
||||
.port(),
|
||||
)
|
||||
}
|
||||
|
||||
async fn wait_tcp(url: &str, target: &str) -> Result<()> {
|
||||
let mut wait_count = 0;
|
||||
loop {
|
||||
if wait_count >= 50 {
|
||||
panic!(
|
||||
"Ran out of retries waiting for {} to start on URL {}",
|
||||
target, url
|
||||
);
|
||||
}
|
||||
match TcpStream::connect(&url).await {
|
||||
Ok(_) => break,
|
||||
Err(_) => {
|
||||
wait_count += 1;
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue