From 8a615e07cb39dd5b7b7b1cb6dd33ae53370d187d Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 10 Jan 2024 17:56:05 +0100 Subject: [PATCH 1/4] Get one e2e test working using the testing framework Signed-off-by: Ryan Levick --- tests/integration.rs | 1 + tests/runtime-tests/src/lib.rs | 2 +- tests/spinup_tests.rs | 94 ++- tests/test-components/components/Cargo.lock | 20 + .../components/key-value-simple/Cargo.toml | 12 + .../components/key-value-simple/README.md | 8 + .../components/key-value-simple/src/lib.rs | 14 + tests/testcases/key-value/.cargo/config.toml | 2 - tests/testcases/key-value/Cargo.lock | 615 ------------------ tests/testcases/key-value/Cargo.toml | 17 - tests/testcases/key-value/spin.toml | 6 +- tests/testcases/key-value/src/lib.rs | 41 -- tests/testcases/mod.rs | 51 -- tests/testing-framework/src/spin.rs | 7 +- .../testing-framework/src/test_environment.rs | 10 +- 15 files changed, 159 insertions(+), 741 deletions(-) create mode 100644 tests/test-components/components/key-value-simple/Cargo.toml create mode 100644 tests/test-components/components/key-value-simple/README.md create mode 100644 tests/test-components/components/key-value-simple/src/lib.rs delete mode 100644 tests/testcases/key-value/.cargo/config.toml delete mode 100644 tests/testcases/key-value/Cargo.lock delete mode 100644 tests/testcases/key-value/Cargo.toml delete mode 100644 tests/testcases/key-value/src/lib.rs diff --git a/tests/integration.rs b/tests/integration.rs index 69955f62f..5df42a16c 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -249,6 +249,7 @@ mod integration_tests { let manifest_path = manifest_path.into(); let spin = testing_framework::TestEnvironmentConfig::spin( spin_binary().into(), + [], move |env| { // Copy manifest let mut template = testing_framework::ManifestTemplate::from_file(manifest_path)?; diff --git a/tests/runtime-tests/src/lib.rs b/tests/runtime-tests/src/lib.rs index 4a9add186..6221ebce6 100644 --- a/tests/runtime-tests/src/lib.rs +++ b/tests/runtime-tests/src/lib.rs @@ -60,7 +60,7 @@ impl RuntimeTest { Ok(()) }; let services_config = services_config(&config)?; - let env_config = TestEnvironmentConfig::spin(spin_binary, preboot, services_config); + let env_config = TestEnvironmentConfig::spin(spin_binary, [], preboot, services_config); let env = TestEnvironment::up(env_config)?; Ok(Self { test_path: config.test_path, diff --git a/tests/spinup_tests.rs b/tests/spinup_tests.rs index 3d556eaeb..5db71a352 100644 --- a/tests/spinup_tests.rs +++ b/tests/spinup_tests.rs @@ -1,6 +1,95 @@ +use std::path::PathBuf; + #[cfg(feature = "e2e-tests")] mod testcases; +fn spin_binary() -> PathBuf { + env!("CARGO_BIN_EXE_spin").into() +} + +#[test] +/// Test that the --key-value flag works as expected +fn key_value_cli_flag() -> anyhow::Result<()> { + let test_key = uuid::Uuid::new_v4().to_string(); + let test_value = uuid::Uuid::new_v4().to_string(); + run_test( + "key-value", + ["--key-value".into(), format!("{test_key}={test_value}")], + move |spin: &mut testing_framework::Spin| { + assert_spin_request( + spin, + reqwest::Method::GET, + &format!("/test?key={test_key}"), + 200, + &test_value, + ) + }, + )?; + Ok(()) +} + +/// Run an e2e test +fn run_test( + test_name: impl Into, + spin_up_args: impl IntoIterator, + test: impl testing_framework::Test, +) -> testing_framework::TestResult { + let config = environment_config(test_name.into(), spin_up_args); + testing_framework::TestEnvironment::up(config)?.test(test)?; + Ok(()) +} + +/// Assert that a request to the spin server returns the expected status and body +fn assert_spin_request( + spin: &mut testing_framework::Spin, + method: reqwest::Method, + uri: &str, + expected_status: u16, + expected_body: &str, +) -> testing_framework::TestResult { + let r = spin.make_http_request(method, uri)?; + let status = r.status(); + let body = r.text().unwrap_or_else(|_| String::from("")); + if status != expected_status { + return Err(testing_framework::TestError::Failure(anyhow::anyhow!( + "Expected status {expected_status} for {uri} but got {status}\nBody:\n{body}", + ))); + } + if body != expected_body { + return Err(anyhow::anyhow!("expected {expected_body}, got {body}",).into()); + } + Ok(()) +} + +/// Get the configuration for a test environment +fn environment_config( + test_name: String, + spin_up_args: impl IntoIterator, +) -> testing_framework::TestEnvironmentConfig { + testing_framework::TestEnvironmentConfig::spin( + spin_binary(), + spin_up_args, + move |env| preboot(&test_name, env), + testing_framework::ServicesConfig::none(), + ) +} + +/// Get the test environment ready to run a test +fn preboot( + test: &str, + env: &mut testing_framework::TestEnvironment, +) -> anyhow::Result<()> { + // Copy everything into the test environment + env.copy_into(format!("tests/testcases/{test}"), "")?; + + // Copy the manifest with all templates substituted + let manifest_path = PathBuf::from(format!("tests/testcases/{test}/spin.toml")); + let mut template = testing_framework::ManifestTemplate::from_file(manifest_path)?; + template.substitute(env)?; + env.write_file("spin.toml", template.contents())?; + Ok(()) +} + #[cfg(feature = "e2e-tests")] mod spinup_tests { use super::testcases; @@ -12,11 +101,6 @@ mod spinup_tests { testcases::component_outbound_http_works(CONTROLLER).await } - #[tokio::test] - async fn key_value_works() { - testcases::key_value_works(CONTROLLER).await - } - #[tokio::test] async fn http_go_works() { testcases::http_go_works(CONTROLLER).await diff --git a/tests/test-components/components/Cargo.lock b/tests/test-components/components/Cargo.lock index 81dc9aa72..e34b8d2bf 100644 --- a/tests/test-components/components/Cargo.lock +++ b/tests/test-components/components/Cargo.lock @@ -230,6 +230,15 @@ dependencies = [ "wit-bindgen 0.16.0", ] +[[package]] +name = "key-value-simple" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde_qs", + "spin-sdk", +] + [[package]] name = "leb128" version = "0.2.5" @@ -367,6 +376,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "slab" version = "0.4.9" diff --git a/tests/test-components/components/key-value-simple/Cargo.toml b/tests/test-components/components/key-value-simple/Cargo.toml new file mode 100644 index 000000000..ead21d877 --- /dev/null +++ b/tests/test-components/components/key-value-simple/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "key-value-simple" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +serde_qs = "0.12.0" +spin-sdk = { path = "../../../../sdk/rust" } diff --git a/tests/test-components/components/key-value-simple/README.md b/tests/test-components/components/key-value-simple/README.md new file mode 100644 index 000000000..b7f9ef96e --- /dev/null +++ b/tests/test-components/components/key-value-simple/README.md @@ -0,0 +1,8 @@ +# Key Value Simple + +Simple Key/Value Component that takes a query param `?key=$KEY` and returns the value in the default store for that key. + +## Expectations + +This test component expects the following to be true: +* It is given permission to open a connection to the "default" store. diff --git a/tests/test-components/components/key-value-simple/src/lib.rs b/tests/test-components/components/key-value-simple/src/lib.rs new file mode 100644 index 000000000..ab4c06c5c --- /dev/null +++ b/tests/test-components/components/key-value-simple/src/lib.rs @@ -0,0 +1,14 @@ +use anyhow::Context as _; +use spin_sdk::http::{IntoResponse, Request, Response}; +use spin_sdk::{http_component, key_value::Store}; +use std::collections::HashMap; + +/// A simple Spin HTTP component. +#[http_component] +fn hello_world(req: Request) -> anyhow::Result { + let conn = Store::open_default()?; + let query: HashMap = serde_qs::from_str(req.query())?; + let key = query.get("key").context("missing key query parameter")?; + let value = conn.get(key)?.unwrap_or_else(|| "".into()); + Ok(Response::new(200, value)) +} diff --git a/tests/testcases/key-value/.cargo/config.toml b/tests/testcases/key-value/.cargo/config.toml deleted file mode 100644 index 6b77899cb..000000000 --- a/tests/testcases/key-value/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-wasi" diff --git a/tests/testcases/key-value/Cargo.lock b/tests/testcases/key-value/Cargo.lock deleted file mode 100644 index a84075b3a..000000000 --- a/tests/testcases/key-value/Cargo.lock +++ /dev/null @@ -1,615 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "indexmap" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "key-value-testcase" -version = "0.1.0" -dependencies = [ - "anyhow", - "http", - "itertools", - "serde", - "serde_qs", - "spin-sdk", -] - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "routefinder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" -dependencies = [ - "smartcow", - "smartstring", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_qs" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" -dependencies = [ - "percent-encoding", - "serde", - "thiserror", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "spdx" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] - -[[package]] -name = "spin-macro" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "bytes", - "http", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin-sdk" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "form_urlencoded", - "futures", - "http", - "once_cell", - "routefinder", - "serde", - "serde_json", - "spin-macro", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-encoder" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.115.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.38", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/tests/testcases/key-value/Cargo.toml b/tests/testcases/key-value/Cargo.toml deleted file mode 100644 index e49752c37..000000000 --- a/tests/testcases/key-value/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "key-value-testcase" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -anyhow = "1" -http = "0.2" -itertools = "0.10" -serde = { version = "1.0", features = ["derive"] } -serde_qs = "0.12" -spin-sdk = { path = "../../../sdk/rust" } - -[workspace] diff --git a/tests/testcases/key-value/spin.toml b/tests/testcases/key-value/spin.toml index 93bc8075c..d24146717 100644 --- a/tests/testcases/key-value/spin.toml +++ b/tests/testcases/key-value/spin.toml @@ -2,14 +2,12 @@ spin_version = "1" authors = ["Fermyon Engineering "] description = "A simple application that exercises key/value storage." name = "key-value" -trigger = {type = "http", base = "/test"} +trigger = { type = "http", base = "/test" } version = "1.0.0" [[component]] id = "hello" key_value_stores = ["default"] -source = "target/wasm32-wasi/release/key_value_testcase.wasm" +source = "%{source=key-value-simple}" [component.trigger] route = "/..." -[component.build] -command = "cargo build --release --target wasm32-wasi" diff --git a/tests/testcases/key-value/src/lib.rs b/tests/testcases/key-value/src/lib.rs deleted file mode 100644 index c534c8937..000000000 --- a/tests/testcases/key-value/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -use anyhow::{ensure, Result}; -use itertools::sorted; -use spin_sdk::{http_component, key_value::Store}; - -#[http_component] -fn handle_request(req: http::Request<()>) -> Result> { - let query = req - .uri() - .query() - .expect("Should have a testkey query string"); - let query: std::collections::HashMap = serde_qs::from_str(query)?; - let init_key = query - .get("testkey") - .expect("Should have a testkey query string"); - let init_val = query - .get("testval") - .expect("Should have a testval query string"); - - let store = Store::open_default()?; - - let result = store.get(init_key)?; - ensure!( - Some(init_val.as_bytes()) == result.as_deref(), - "Expected to look up {init_key} and get {init_val} but actually got {:?}", - result.as_deref().map(String::from_utf8_lossy) - ); - - ensure!( - sorted(vec![init_key.to_owned()]).collect::>() - == sorted(store.get_keys()?).collect::>(), - "Expected exactly keys '{}' but got '{:?}'", - init_key, - &store.get_keys()? - ); - - store.delete(init_key)?; - - ensure!(&[] as &[String] == &store.get_keys()?); - - Ok(http::Response::builder().status(200).body(())?) -} diff --git a/tests/testcases/mod.rs b/tests/testcases/mod.rs index 0efba72e0..2cc5d8b6e 100644 --- a/tests/testcases/mod.rs +++ b/tests/testcases/mod.rs @@ -61,57 +61,6 @@ pub async fn component_outbound_http_works(controller: &dyn Controller) { tc.run(controller).await.unwrap() } -pub async fn key_value_works(controller: &dyn Controller) { - async fn checks( - metadata: AppMetadata, - test_init_key: String, - test_init_value: String, - // TODO: investigate why omitting these two next parameters does not - // cause a compile time error but causes a runtime one - _: Option>>, - _: Option>>, - ) -> Result<()> { - assert_http_response( - get_url( - metadata.base.as_str(), - &format!("/test?testkey={test_init_key}&testval={test_init_value}"), - ) - .as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await - } - - let init_key = uuid::Uuid::new_v4().to_string(); - let init_value = uuid::Uuid::new_v4().to_string(); - - let tc = TestCaseBuilder::default() - .name("key-value".to_string()) - .appname(Some("key-value".to_string())) - .template(None) - .deploy_args(vec![ - "--key-value".to_string(), - format!("{init_key}={init_value}"), - ]) - .assertions( - move |metadata: AppMetadata, - stdout_stream: Option>>, - stderr_stream: Option>>| { - let ik = init_key.clone(); - let iv = init_value.clone(); - Box::pin(checks(metadata, ik, iv, stdout_stream, stderr_stream)) - }, - ) - .build() - .unwrap(); - - tc.run(controller).await.unwrap() -} - pub async fn http_python_works(controller: &dyn Controller) { async fn checks( metadata: AppMetadata, diff --git a/tests/testing-framework/src/spin.rs b/tests/testing-framework/src/spin.rs index 3b6eaa91e..fcbb7db3a 100644 --- a/tests/testing-framework/src/spin.rs +++ b/tests/testing-framework/src/spin.rs @@ -15,12 +15,17 @@ pub struct Spin { impl Spin { /// Start Spin in `current_dir` using the binary at `spin_binary_path` - pub fn start(spin_binary_path: &Path, current_dir: &Path) -> anyhow::Result { + pub fn start( + spin_binary_path: &Path, + current_dir: &Path, + spin_up_args: Vec>, + ) -> anyhow::Result { let port = get_random_port()?; let mut child = Command::new(spin_binary_path) .arg("up") .current_dir(current_dir) .args(["--listen", &format!("127.0.0.1:{port}")]) + .args(spin_up_args) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn()?; diff --git a/tests/testing-framework/src/test_environment.rs b/tests/testing-framework/src/test_environment.rs index a75cac9b9..4ba5d88e2 100644 --- a/tests/testing-framework/src/test_environment.rs +++ b/tests/testing-framework/src/test_environment.rs @@ -116,9 +116,9 @@ impl TestEnvironment { /// Configuration for a test environment pub struct TestEnvironmentConfig { /// A callback to create a runtime given a path to a temporary directory - pub create_runtime: Box>, + create_runtime: Box>, /// The services that the test requires - pub services_config: ServicesConfig, + services_config: ServicesConfig, } impl TestEnvironmentConfig { @@ -128,16 +128,18 @@ impl TestEnvironmentConfig { /// * `preboot` - a callback that happens after the services have started but before the runtime is /// * `test` - a callback that runs the test against the runtime /// * `services_config` - the services that the test requires - pub fn spin( + pub fn spin<'a>( spin_binary: PathBuf, + spin_up_args: impl IntoIterator, preboot: impl FnOnce(&mut TestEnvironment) -> anyhow::Result<()> + 'static, services_config: ServicesConfig, ) -> Self { + let spin_up_args = spin_up_args.into_iter().collect(); Self { services_config, create_runtime: Box::new(move |env| { preboot(env)?; - Spin::start(&spin_binary, env.path()) + Spin::start(&spin_binary, env.path(), spin_up_args) }), } } From f07a04544945582696963799b345b0c411a36046 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 10 Jan 2024 18:11:24 +0100 Subject: [PATCH 2/4] Add smoke test Signed-off-by: Ryan Levick --- tests/spinup_tests.rs | 45 +- .../head-rust-sdk-http/.cargo/config.toml | 2 - tests/testcases/head-rust-sdk-http/Cargo.lock | 587 ------------------ tests/testcases/head-rust-sdk-http/Cargo.toml | 19 - tests/testcases/head-rust-sdk-http/src/lib.rs | 18 - tests/testcases/mod.rs | 70 --- .../assets/test.txt | 0 .../spin.toml | 8 +- 8 files changed, 43 insertions(+), 706 deletions(-) delete mode 100644 tests/testcases/head-rust-sdk-http/.cargo/config.toml delete mode 100644 tests/testcases/head-rust-sdk-http/Cargo.lock delete mode 100644 tests/testcases/head-rust-sdk-http/Cargo.toml delete mode 100644 tests/testcases/head-rust-sdk-http/src/lib.rs rename tests/testcases/{head-rust-sdk-http => smoke-test}/assets/test.txt (100%) rename tests/testcases/{head-rust-sdk-http => smoke-test}/spin.toml (60%) diff --git a/tests/spinup_tests.rs b/tests/spinup_tests.rs index 5db71a352..4499e4aa4 100644 --- a/tests/spinup_tests.rs +++ b/tests/spinup_tests.rs @@ -28,6 +28,46 @@ fn key_value_cli_flag() -> anyhow::Result<()> { Ok(()) } +#[test] +fn http_smoke_test() -> anyhow::Result<()> { + run_test( + "smoke-test", + [], + move |spin: &mut testing_framework::Spin| { + assert_spin_request( + spin, + reqwest::Method::GET, + &format!("/test/hello"), + 200, + "I'm a teapot", + )?; + assert_spin_request( + spin, + reqwest::Method::GET, + &format!("/test/hello/wildcards/should/be/handled"), + 200, + "I'm a teapot", + )?; + assert_spin_request( + spin, + reqwest::Method::GET, + &format!("/thishsouldfail"), + 404, + "", + )?; + assert_spin_request( + spin, + reqwest::Method::GET, + &format!("/test/hello/test-placement"), + 200, + "text for test", + ) + }, + )?; + + Ok(()) +} + /// Run an e2e test fn run_test( test_name: impl Into, @@ -157,11 +197,6 @@ mod spinup_tests { testcases::assets_routing_works(CONTROLLER).await } - #[tokio::test] - async fn head_rust_sdk_http() { - testcases::head_rust_sdk_http(CONTROLLER).await - } - #[tokio::test] async fn head_rust_sdk_redis() { testcases::head_rust_sdk_redis(CONTROLLER).await diff --git a/tests/testcases/head-rust-sdk-http/.cargo/config.toml b/tests/testcases/head-rust-sdk-http/.cargo/config.toml deleted file mode 100644 index 6b77899cb..000000000 --- a/tests/testcases/head-rust-sdk-http/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-wasi" diff --git a/tests/testcases/head-rust-sdk-http/Cargo.lock b/tests/testcases/head-rust-sdk-http/Cargo.lock deleted file mode 100644 index 56eb3558c..000000000 --- a/tests/testcases/head-rust-sdk-http/Cargo.lock +++ /dev/null @@ -1,587 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - -[[package]] -name = "head-rust-sdk-http" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "spin-sdk", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "indexmap" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "routefinder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" -dependencies = [ - "smartcow", - "smartstring", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "spdx" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] - -[[package]] -name = "spin-macro" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "bytes", - "http", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin-sdk" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "form_urlencoded", - "futures", - "http", - "once_cell", - "routefinder", - "serde", - "serde_json", - "spin-macro", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-encoder" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.115.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.38", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/tests/testcases/head-rust-sdk-http/Cargo.toml b/tests/testcases/head-rust-sdk-http/Cargo.toml deleted file mode 100644 index 8f109a004..000000000 --- a/tests/testcases/head-rust-sdk-http/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "head-rust-sdk-http" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = [ "cdylib" ] - -[dependencies] -# Useful crate to handle errors. -anyhow = "1" -# Crate to simplify working with bytes. -bytes = "1" -# General-purpose crate with common HTTP types. -http = "0.2" -# The Spin SDK. -spin-sdk = { path = "../../../sdk/rust" } - -[workspace] diff --git a/tests/testcases/head-rust-sdk-http/src/lib.rs b/tests/testcases/head-rust-sdk-http/src/lib.rs deleted file mode 100644 index 67eac02fb..000000000 --- a/tests/testcases/head-rust-sdk-http/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -use anyhow::Result; -use spin_sdk::{http_component, variables}; - -#[http_component] -fn hello_world(req: http::Request<()>) -> Result> { - let path = req.uri().path(); - - if path.contains("test-placement") { - match std::fs::read_to_string("/test.txt") { - Ok(txt) => Ok(http::Response::builder().status(200).body(txt)?), - Err(e) => anyhow::bail!("Error, could not access test.txt: {}", e), - } - } else { - let msg = variables::get("message").expect("Failed to acquire message from spin.toml"); - - Ok(http::Response::builder().status(200).body(msg)?) - } -} diff --git a/tests/testcases/mod.rs b/tests/testcases/mod.rs index 2cc5d8b6e..c2353288b 100644 --- a/tests/testcases/mod.rs +++ b/tests/testcases/mod.rs @@ -520,76 +520,6 @@ pub async fn assets_routing_works(controller: &dyn Controller) { tc.run(controller).await.unwrap() } -/// Test an http app using the current branch's version of the Rust SDK -pub async fn head_rust_sdk_http(controller: &dyn Controller) { - async fn checks( - metadata: AppMetadata, - _: Option>>, - _: Option>>, - ) -> Result<()> { - assert_http_response( - get_url(metadata.base.as_str(), "/test/hello").as_str(), - Method::GET, - "", - 200, - &[], - Some("I'm a teapot"), - ) - .await?; - - assert_http_response( - get_url( - metadata.base.as_str(), - "/test/hello/wildcards/should/be/handled", - ) - .as_str(), - Method::GET, - "", - 200, - &[], - Some("I'm a teapot"), - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/thisshouldfail").as_str(), - Method::GET, - "", - 404, - &[], - None, - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/test/hello/test-placement").as_str(), - Method::GET, - "", - 200, - &[], - Some("text for test"), - ) - .await?; - - Ok(()) - } - - let tc = TestCaseBuilder::default() - .name("head-rust-sdk-http".to_string()) - .appname(Some("head-rust-sdk-http".to_string())) - .assertions( - |metadata: AppMetadata, - stdout_stream: Option>>, - stderr_stream: Option>>| { - Box::pin(checks(metadata, stdout_stream, stderr_stream)) - }, - ) - .build() - .unwrap(); - - tc.run(controller).await.unwrap() -} - /// Test a redis app using the current branch's version of the Rust SDK pub async fn head_rust_sdk_redis(controller: &dyn Controller) { async fn checks( diff --git a/tests/testcases/head-rust-sdk-http/assets/test.txt b/tests/testcases/smoke-test/assets/test.txt similarity index 100% rename from tests/testcases/head-rust-sdk-http/assets/test.txt rename to tests/testcases/smoke-test/assets/test.txt diff --git a/tests/testcases/head-rust-sdk-http/spin.toml b/tests/testcases/smoke-test/spin.toml similarity index 60% rename from tests/testcases/head-rust-sdk-http/spin.toml rename to tests/testcases/smoke-test/spin.toml index f7de55301..b12a0e28d 100644 --- a/tests/testcases/head-rust-sdk-http/spin.toml +++ b/tests/testcases/smoke-test/spin.toml @@ -2,7 +2,7 @@ spin_version = "1" authors = ["Fermyon Engineering "] description = "A simple application that returns hello and goodbye." name = "head-rust-sdk-http" -trigger = {type = "http", base = "/test"} +trigger = { type = "http", base = "/test" } version = "1.0.0" [variables] @@ -10,11 +10,9 @@ object = { default = "teapot" } [[component]] id = "hello" -source = "target/wasm32-wasi/release/head_rust_sdk_http.wasm" -files = [ { source = "assets", destination = "/" } ] +source = "%{source=integration-simple}" +files = [{ source = "assets", destination = "/" }] [component.trigger] route = "/hello/..." [component.config] message = "I'm a {{object}}" -[component.build] -command = "cargo build --target wasm32-wasi --release" \ No newline at end of file From 162b514395baff8d4219510385f67f203361d7ac Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 10 Jan 2024 18:36:53 +0100 Subject: [PATCH 3/4] Add redis support Signed-off-by: Ryan Levick --- Cargo.lock | 22 +- Cargo.toml | 9 +- tests/integration.rs | 14 +- tests/runtime-tests/src/lib.rs | 13 +- tests/spinup_tests.rs | 124 ++-- tests/test-components/components/Cargo.lock | 9 + .../components/redis-smoke-test/Cargo.toml | 12 + .../components/redis-smoke-test}/src/lib.rs | 0 .../head-rust-sdk-redis/.cargo/config.toml | 2 - .../testcases/head-rust-sdk-redis/Cargo.lock | 587 ------------------ .../testcases/head-rust-sdk-redis/Cargo.toml | 15 - .../assets/test.txt | 0 .../{smoke-test => http-smoke-test}/spin.toml | 0 tests/testcases/mod.rs | 34 - .../spin.toml | 4 +- tests/testing-framework/src/lib.rs | 10 +- tests/testing-framework/src/services.rs | 4 +- tests/testing-framework/src/spin.rs | 76 ++- .../testing-framework/src/test_environment.rs | 35 +- 19 files changed, 256 insertions(+), 714 deletions(-) create mode 100644 tests/test-components/components/redis-smoke-test/Cargo.toml rename tests/{testcases/head-rust-sdk-redis => test-components/components/redis-smoke-test}/src/lib.rs (100%) delete mode 100644 tests/testcases/head-rust-sdk-redis/.cargo/config.toml delete mode 100644 tests/testcases/head-rust-sdk-redis/Cargo.lock delete mode 100644 tests/testcases/head-rust-sdk-redis/Cargo.toml rename tests/testcases/{smoke-test => http-smoke-test}/assets/test.txt (100%) rename tests/testcases/{smoke-test => http-smoke-test}/spin.toml (100%) rename tests/testcases/{head-rust-sdk-redis => redis-smoke-test}/spin.toml (74%) diff --git a/Cargo.lock b/Cargo.lock index c2ac4c928..4577f4f23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4274,7 +4274,7 @@ name = "outbound-redis" version = "2.2.0-pre0" dependencies = [ "anyhow", - "redis", + "redis 0.21.7", "spin-app", "spin-core", "spin-outbound-networking", @@ -4891,6 +4891,21 @@ dependencies = [ "url", ] +[[package]] +name = "redis" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" +dependencies = [ + "combine", + "itoa", + "percent-encoding", + "ryu", + "sha1_smol", + "socket2 0.4.10", + "url", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -5757,6 +5772,7 @@ dependencies = [ "outbound-redis", "path-absolutize", "rand 0.8.5", + "redis 0.24.0", "regex", "reqwest", "rpassword", @@ -5923,7 +5939,7 @@ name = "spin-key-value-redis" version = "0.1.0" dependencies = [ "anyhow", - "redis", + "redis 0.21.7", "spin-core", "spin-key-value", "spin-world", @@ -6149,7 +6165,7 @@ dependencies = [ "anyhow", "async-trait", "futures", - "redis", + "redis 0.21.7", "serde", "spin-app", "spin-core", diff --git a/Cargo.toml b/Cargo.toml index 91b5b097f..9373b0203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,6 +92,7 @@ e2e-testing = { path = "crates/e2e-testing" } http-body-util = { workspace = true } testing-framework = { path = "tests/testing-framework" } hyper-util = { version = "0.1.2", features = ["tokio"] } +redis = "0.24" runtime-tests = { path = "tests/runtime-tests" } test-components = { path = "tests/test-components" } test-codegen-macro = { path = "crates/test-codegen-macro" } @@ -133,8 +134,12 @@ tracing = { version = "0.1", features = ["log"] } # TODO: update to final 17.0.0 release once it's available wasi-common-preview1 = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-17.0.0", package = "wasi-common" } -wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-17.0.0", features = ["component-model"] } -wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-17.0.0", features = ["tokio"] } +wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-17.0.0", features = [ + "component-model", +] } +wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-17.0.0", features = [ + "tokio", +] } wasmtime-wasi-http = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-17.0.0" } spin-componentize = { git = "https://github.com/fermyon/spin-componentize", rev = "191789170abde10cd55590466c0660dd6c7d472a" } diff --git a/tests/integration.rs b/tests/integration.rs index 5df42a16c..db4028aa5 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -41,7 +41,8 @@ mod integration_tests { "{}/{}", RUST_HTTP_INTEGRATION_TEST, DEFAULT_MANIFEST_LOCATION ), - |spin| { + |env| { + let spin = env.runtime_mut(); assert_spin_status(spin, "/test/hello", 200)?; assert_spin_status(spin, "/test/hello/wildcards/should/be/handled", 200)?; assert_spin_status(spin, "/thisshouldfail", 404)?; @@ -57,7 +58,8 @@ mod integration_tests { fn test_duplicate_rust_local() -> Result<()> { integration_test( format!("{}/{}", RUST_HTTP_INTEGRATION_TEST, "double-trouble.toml"), - |spin| { + |env| { + let spin = env.runtime_mut(); assert_spin_status(spin, "/route1", 200)?; assert_spin_status(spin, "/route2", 200)?; assert_spin_status(spin, "/thisshouldfail", 404)?; @@ -243,7 +245,9 @@ mod integration_tests { fn integration_test( manifest_path: impl Into, - test: impl FnOnce(&mut testing_framework::Spin) -> testing_framework::TestResult + test: impl FnOnce( + &mut testing_framework::TestEnvironment, + ) -> testing_framework::TestResult + 'static, ) -> anyhow::Result<()> { let manifest_path = manifest_path.into(); @@ -262,9 +266,11 @@ mod integration_tests { Ok(()) }, testing_framework::ServicesConfig::none(), + testing_framework::SpinMode::Http, ); let mut env = testing_framework::TestEnvironment::up(spin)?; - Ok(env.test(test)?) + test(&mut env)?; + Ok(()) } fn assert_spin_status( diff --git a/tests/runtime-tests/src/lib.rs b/tests/runtime-tests/src/lib.rs index 6221ebce6..ac692573a 100644 --- a/tests/runtime-tests/src/lib.rs +++ b/tests/runtime-tests/src/lib.rs @@ -60,7 +60,13 @@ impl RuntimeTest { Ok(()) }; let services_config = services_config(&config)?; - let env_config = TestEnvironmentConfig::spin(spin_binary, [], preboot, services_config); + let env_config = TestEnvironmentConfig::spin( + spin_binary, + [], + preboot, + services_config, + testing_framework::SpinMode::Http, + ); let env = TestEnvironment::up(env_config)?; Ok(Self { test_path: config.test_path, @@ -84,7 +90,7 @@ impl RuntimeTest { } }; } - let response = self.env.test(test); + let response = test(&mut self.env); let error_file = self.test_path.join("error.txt"); match response { Ok(()) if !error_file.exists() => log::info!("Test passed!"), @@ -173,7 +179,8 @@ fn copy_manifest(test_dir: &Path, env: &mut TestEnvironment) -> anyhow::Re Ok(()) } -fn test(runtime: &mut Spin) -> TestResult { +fn test(env: &mut TestEnvironment) -> TestResult { + let runtime = env.runtime_mut(); let response = runtime.make_http_request(reqwest::Method::GET, "/")?; if response.status() == 200 { return Ok(()); diff --git a/tests/spinup_tests.rs b/tests/spinup_tests.rs index 4499e4aa4..6af9550a8 100644 --- a/tests/spinup_tests.rs +++ b/tests/spinup_tests.rs @@ -1,10 +1,25 @@ +use anyhow::Context; +use redis::Commands; use std::path::PathBuf; #[cfg(feature = "e2e-tests")] mod testcases; -fn spin_binary() -> PathBuf { - env!("CARGO_BIN_EXE_spin").into() +/// Helper macro to assert that a condition is true eventually +macro_rules! assert_eventually { + ($e:expr) => { + let mut i = 0; + loop { + if $e { + break; + } else if i > 20 { + assert!($e); + break; + } + std::thread::sleep(std::time::Duration::from_millis(100)); + i += 1; + } + }; } #[test] @@ -14,8 +29,11 @@ fn key_value_cli_flag() -> anyhow::Result<()> { let test_value = uuid::Uuid::new_v4().to_string(); run_test( "key-value", + testing_framework::SpinMode::Http, ["--key-value".into(), format!("{test_key}={test_value}")], - move |spin: &mut testing_framework::Spin| { + testing_framework::ServicesConfig::none(), + move |env| { + let spin = env.runtime_mut(); assert_spin_request( spin, reqwest::Method::GET, @@ -29,36 +47,34 @@ fn key_value_cli_flag() -> anyhow::Result<()> { } #[test] +/// Test that basic http trigger support works fn http_smoke_test() -> anyhow::Result<()> { run_test( - "smoke-test", + "http-smoke-test", + testing_framework::SpinMode::Http, [], - move |spin: &mut testing_framework::Spin| { + testing_framework::ServicesConfig::none(), + move |env| { + let spin = env.runtime_mut(); assert_spin_request( spin, reqwest::Method::GET, - &format!("/test/hello"), + "/test/hello", 200, "I'm a teapot", )?; assert_spin_request( spin, reqwest::Method::GET, - &format!("/test/hello/wildcards/should/be/handled"), + "/test/hello/wildcards/should/be/handled", 200, "I'm a teapot", )?; + assert_spin_request(spin, reqwest::Method::GET, "/thishsouldfail", 404, "")?; assert_spin_request( spin, reqwest::Method::GET, - &format!("/thishsouldfail"), - 404, - "", - )?; - assert_spin_request( - spin, - reqwest::Method::GET, - &format!("/test/hello/test-placement"), + "/test/hello/test-placement", 200, "text for test", ) @@ -68,14 +84,63 @@ fn http_smoke_test() -> anyhow::Result<()> { Ok(()) } +#[test] +/// Test that basic redis trigger support works +fn redis_smoke_test() -> anyhow::Result<()> { + run_test( + "redis-smoke-test", + testing_framework::SpinMode::Redis, + [], + testing_framework::ServicesConfig::new(vec!["redis".into()])?, + move |env| { + let redis_port = env + .services_mut() + .get_port(6379)? + .context("no redis port was exposed by test services")?; + + let mut redis = redis::Client::open(format!("redis://localhost:{redis_port}")) + .context("could not connect to redis in test")?; + redis + .publish("my-channel", "msg-from-test") + .context("could not publish test message to redis")?; + assert_eventually!({ + match env.read_file(".spin/logs/hello_stdout.txt") { + Ok(logs) => { + let logs = String::from_utf8_lossy(&logs); + logs.contains("Got message: 'msg-from-test'") + } + Err(e) if e.kind() == std::io::ErrorKind::NotFound => false, + Err(e) => return Err(anyhow::anyhow!("could not read stdout file: {e}").into()), + } + }); + Ok(()) + }, + )?; + + Ok(()) +} + /// Run an e2e test fn run_test( test_name: impl Into, + mode: testing_framework::SpinMode, spin_up_args: impl IntoIterator, - test: impl testing_framework::Test, + services_config: testing_framework::ServicesConfig, + test: impl FnOnce( + &mut testing_framework::TestEnvironment, + ) -> testing_framework::TestResult + + 'static, ) -> testing_framework::TestResult { - let config = environment_config(test_name.into(), spin_up_args); - testing_framework::TestEnvironment::up(config)?.test(test)?; + let test_name = test_name.into(); + let config = testing_framework::TestEnvironmentConfig::spin( + spin_binary(), + spin_up_args, + move |env| preboot(&test_name, env), + services_config, + mode, + ); + let mut env = testing_framework::TestEnvironment::up(config)?; + test(&mut env)?; Ok(()) } @@ -101,19 +166,6 @@ fn assert_spin_request( Ok(()) } -/// Get the configuration for a test environment -fn environment_config( - test_name: String, - spin_up_args: impl IntoIterator, -) -> testing_framework::TestEnvironmentConfig { - testing_framework::TestEnvironmentConfig::spin( - spin_binary(), - spin_up_args, - move |env| preboot(&test_name, env), - testing_framework::ServicesConfig::none(), - ) -} - /// Get the test environment ready to run a test fn preboot( test: &str, @@ -130,6 +182,11 @@ fn preboot( Ok(()) } +/// Get the spin binary path +fn spin_binary() -> PathBuf { + env!("CARGO_BIN_EXE_spin").into() +} + #[cfg(feature = "e2e-tests")] mod spinup_tests { use super::testcases; @@ -197,11 +254,6 @@ mod spinup_tests { testcases::assets_routing_works(CONTROLLER).await } - #[tokio::test] - async fn head_rust_sdk_redis() { - testcases::head_rust_sdk_redis(CONTROLLER).await - } - #[tokio::test] async fn llm_works() { testcases::llm_works(CONTROLLER).await diff --git a/tests/test-components/components/Cargo.lock b/tests/test-components/components/Cargo.lock index e34b8d2bf..5c2d5b739 100644 --- a/tests/test-components/components/Cargo.lock +++ b/tests/test-components/components/Cargo.lock @@ -153,6 +153,15 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "head-rust-sdk-redis" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "spin-sdk", +] + [[package]] name = "heck" version = "0.4.1" diff --git a/tests/test-components/components/redis-smoke-test/Cargo.toml b/tests/test-components/components/redis-smoke-test/Cargo.toml new file mode 100644 index 000000000..6d16c22b7 --- /dev/null +++ b/tests/test-components/components/redis-smoke-test/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "head-rust-sdk-redis" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1" +bytes = "1" +spin-sdk = { path = "../../../../sdk/rust" } diff --git a/tests/testcases/head-rust-sdk-redis/src/lib.rs b/tests/test-components/components/redis-smoke-test/src/lib.rs similarity index 100% rename from tests/testcases/head-rust-sdk-redis/src/lib.rs rename to tests/test-components/components/redis-smoke-test/src/lib.rs diff --git a/tests/testcases/head-rust-sdk-redis/.cargo/config.toml b/tests/testcases/head-rust-sdk-redis/.cargo/config.toml deleted file mode 100644 index 6b77899cb..000000000 --- a/tests/testcases/head-rust-sdk-redis/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-wasi" diff --git a/tests/testcases/head-rust-sdk-redis/Cargo.lock b/tests/testcases/head-rust-sdk-redis/Cargo.lock deleted file mode 100644 index f5c1e6231..000000000 --- a/tests/testcases/head-rust-sdk-redis/Cargo.lock +++ /dev/null @@ -1,587 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - -[[package]] -name = "head-rust-sdk-redis" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "spin-sdk", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "indexmap" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "routefinder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" -dependencies = [ - "smartcow", - "smartstring", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "spdx" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] - -[[package]] -name = "spin-macro" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "bytes", - "http", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin-sdk" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "form_urlencoded", - "futures", - "http", - "once_cell", - "routefinder", - "serde", - "serde_json", - "spin-macro", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-encoder" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.115.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.38", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/tests/testcases/head-rust-sdk-redis/Cargo.toml b/tests/testcases/head-rust-sdk-redis/Cargo.toml deleted file mode 100644 index 3de29bf0e..000000000 --- a/tests/testcases/head-rust-sdk-redis/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "head-rust-sdk-redis" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = [ "cdylib" ] - -[dependencies] -anyhow = "1" -bytes = "1" -http = "0.2" -spin-sdk = { path = "../../../sdk/rust"} - -[workspace] diff --git a/tests/testcases/smoke-test/assets/test.txt b/tests/testcases/http-smoke-test/assets/test.txt similarity index 100% rename from tests/testcases/smoke-test/assets/test.txt rename to tests/testcases/http-smoke-test/assets/test.txt diff --git a/tests/testcases/smoke-test/spin.toml b/tests/testcases/http-smoke-test/spin.toml similarity index 100% rename from tests/testcases/smoke-test/spin.toml rename to tests/testcases/http-smoke-test/spin.toml diff --git a/tests/testcases/mod.rs b/tests/testcases/mod.rs index c2353288b..84710deae 100644 --- a/tests/testcases/mod.rs +++ b/tests/testcases/mod.rs @@ -520,40 +520,6 @@ pub async fn assets_routing_works(controller: &dyn Controller) { tc.run(controller).await.unwrap() } -/// Test a redis app using the current branch's version of the Rust SDK -pub async fn head_rust_sdk_redis(controller: &dyn Controller) { - async fn checks( - _: AppMetadata, - _: Option>>, - stderr_stream: Option>>, - ) -> Result<()> { - wait_for_spin().await; - let stderr = get_output_stream(stderr_stream).await?; - anyhow::ensure!( - stderr.is_empty(), - "expected stderr to be empty, but it was not: {}", - stderr.join("\n") - ); - Ok(()) - } - - let tc = TestCaseBuilder::default() - .name("head-rust-sdk-redis".to_string()) - .appname(Some("head-rust-sdk-redis".to_string())) - .trigger_type("redis".to_string()) - .assertions( - |metadata: AppMetadata, - stdout_stream: Option>>, - stderr_stream: Option>>| { - Box::pin(checks(metadata, stdout_stream, stderr_stream)) - }, - ) - .build() - .unwrap(); - - tc.run(controller).await.unwrap() -} - pub async fn llm_works(controller: &dyn Controller) { async fn checks( metadata: AppMetadata, diff --git a/tests/testcases/head-rust-sdk-redis/spin.toml b/tests/testcases/redis-smoke-test/spin.toml similarity index 74% rename from tests/testcases/head-rust-sdk-redis/spin.toml rename to tests/testcases/redis-smoke-test/spin.toml index 7a5a8bf1f..61403e352 100644 --- a/tests/testcases/head-rust-sdk-redis/spin.toml +++ b/tests/testcases/redis-smoke-test/spin.toml @@ -2,12 +2,12 @@ spin_version = "1" authors = ["Fermyon Engineering "] description = "A simple redis application that exercises the Rust SDK in the current branch" name = "head-rust-sdk-redis" -trigger = {type = "redis", address = "redis://redis:6379"} +trigger = { type = "redis", address = "redis://localhost:%{port=6379}" } version = "1.0.0" [[component]] id = "hello" -source = "target/wasm32-wasi/release/head_rust_sdk_redis.wasm" +source = "%{source=redis-smoke-test}" [component.trigger] channel = "my-channel" [component.build] diff --git a/tests/testing-framework/src/lib.rs b/tests/testing-framework/src/lib.rs index 53bde6484..599560ee6 100644 --- a/tests/testing-framework/src/lib.rs +++ b/tests/testing-framework/src/lib.rs @@ -12,7 +12,7 @@ mod test_environment; pub use manifest_template::ManifestTemplate; pub use services::ServicesConfig; -pub use spin::Spin; +pub use spin::{Spin, SpinMode}; pub use test_environment::{TestEnvironment, TestEnvironmentConfig}; #[derive(Debug, Clone, Copy)] @@ -41,18 +41,18 @@ pub trait Test { type Failure; /// Run the test against the runtime - fn test(self, runtime: &mut Self::Runtime) -> TestResult; + fn test(self, env: &mut TestEnvironment) -> TestResult; } impl Test for F where - F: FnOnce(&mut Spin) -> TestResult + 'static, + F: FnOnce(&mut TestEnvironment) -> TestResult + 'static, { type Runtime = Spin; type Failure = E; - fn test(self, runtime: &mut Self::Runtime) -> TestResult { - self(runtime) + fn test(self, env: &mut TestEnvironment) -> TestResult { + self(env) } } diff --git a/tests/testing-framework/src/services.rs b/tests/testing-framework/src/services.rs index 5a87cc3d0..9baae60f6 100644 --- a/tests/testing-framework/src/services.rs +++ b/tests/testing-framework/src/services.rs @@ -52,8 +52,8 @@ impl Services { Ok(()) } - /// Get the host port that a service exposes a guest port on. - pub(crate) fn get_port(&mut self, guest_port: u16) -> anyhow::Result> { + /// Get the host port that one of the services exposes a guest port on. + pub fn get_port(&mut self, guest_port: u16) -> anyhow::Result> { let mut result = None; for service in &mut self.services { let host_port = service.ports().unwrap().get(&guest_port); diff --git a/tests/testing-framework/src/spin.rs b/tests/testing-framework/src/spin.rs index fcbb7db3a..eb58262aa 100644 --- a/tests/testing-framework/src/spin.rs +++ b/tests/testing-framework/src/spin.rs @@ -10,15 +10,27 @@ pub struct Spin { #[allow(dead_code)] stdout: OutputStream, stderr: OutputStream, - port: u16, + io_mode: IoMode, } impl Spin { - /// Start Spin in `current_dir` using the binary at `spin_binary_path` pub fn start( spin_binary_path: &Path, current_dir: &Path, spin_up_args: Vec>, + mode: SpinMode, + ) -> anyhow::Result { + match mode { + SpinMode::Http => Self::start_http(spin_binary_path, current_dir, spin_up_args), + SpinMode::Redis => Self::start_redis(spin_binary_path, current_dir, spin_up_args), + } + } + + /// Start Spin in `current_dir` using the binary at `spin_binary_path` + pub fn start_http( + spin_binary_path: &Path, + current_dir: &Path, + spin_up_args: Vec>, ) -> anyhow::Result { let port = get_random_port()?; let mut child = Command::new(spin_binary_path) @@ -36,13 +48,13 @@ impl Spin { process: child, stdout, stderr, - port, + io_mode: IoMode::Http(port), }; let start = std::time::Instant::now(); loop { match std::net::TcpStream::connect(format!("127.0.0.1:{port}")) { Ok(_) => { - log::debug!("Spin started on port {}.", spin.port); + log::debug!("Spin started on port {port}."); return Ok(spin); } Err(e) => { @@ -71,18 +83,54 @@ impl Spin { ) } + pub fn start_redis( + spin_binary_path: &Path, + current_dir: &Path, + spin_up_args: Vec>, + ) -> anyhow::Result { + let mut child = Command::new(spin_binary_path) + .arg("up") + .current_dir(current_dir) + .args(spin_up_args) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + let stdout = OutputStream::new(child.stdout.take().unwrap()); + let stderr = OutputStream::new(child.stderr.take().unwrap()); + let mut spin = Self { + process: child, + stdout, + stderr, + io_mode: IoMode::Redis, + }; + // TODO this is a hack to wait for the redis service to start + std::thread::sleep(std::time::Duration::from_millis(10000)); + if let Some(status) = spin.try_wait()? { + anyhow::bail!( + "Spin exited early with status code {:?}\n{}{}", + status.code(), + spin.stdout.output_as_str().unwrap_or(""), + spin.stderr.output_as_str().unwrap_or("") + ); + } + Ok(spin) + } + pub fn make_http_request( &mut self, method: reqwest::Method, path: &str, ) -> anyhow::Result { + let IoMode::Http(port) = self.io_mode else { + anyhow::bail!("Spin is not running in HTTP mode"); + }; if let Some(status) = self.try_wait()? { anyhow::bail!("Spin exited early with status code {:?}", status.code()); } - log::debug!("Connecting to HTTP server on port {}...", self.port); + log::debug!("Connecting to HTTP server on port {port}..."); let request = reqwest::blocking::Request::new( method, - format!("http://localhost:{}{}", self.port, path) + format!("http://localhost:{}{}", port, path) .parse() .unwrap(), ); @@ -94,6 +142,10 @@ impl Spin { Ok(response) } + pub fn stdout(&mut self) -> &str { + self.stdout.output_as_str().unwrap_or("") + } + pub fn stderr(&mut self) -> &str { self.stderr.output_as_str().unwrap_or("") } @@ -131,6 +183,18 @@ fn kill_process(process: &mut std::process::Child) { } } +/// How this Spin instance is communicating with the outside world +enum IoMode { + Http(u16), + Redis, +} + +/// The mode start Spin up in +pub enum SpinMode { + Http, + Redis, +} + /// Uses a track to ge a random unused port fn get_random_port() -> anyhow::Result { Ok(std::net::TcpListener::bind("localhost:0")? diff --git a/tests/testing-framework/src/test_environment.rs b/tests/testing-framework/src/test_environment.rs index 4ba5d88e2..9acf91eab 100644 --- a/tests/testing-framework/src/test_environment.rs +++ b/tests/testing-framework/src/test_environment.rs @@ -2,8 +2,8 @@ use std::path::{Path, PathBuf}; use crate::{ services::{Services, ServicesConfig}, - spin::Spin, - Runtime, Test, TestResult, + spin::{Spin, SpinMode}, + Runtime, }; use anyhow::Context as _; @@ -37,15 +37,6 @@ impl TestEnvironment { Ok(env) } - /// Run test against runtime - pub fn test>(&mut self, test: T) -> TestResult { - let runtime = self - .runtime - .as_mut() - .context("runtime was not initialized")?; - test.test(runtime) - } - /// Whether an error has occurred fn error(&mut self) -> anyhow::Result<()> { self.services.healthy()?; @@ -57,6 +48,18 @@ impl TestEnvironment { } impl TestEnvironment { + /// Get the services that are running for the test + pub fn services_mut(&mut self) -> &mut Services { + &mut self.services + } + + /// Get the runtime that is running for the test + pub fn runtime_mut(&mut self) -> &mut R { + self.runtime + .as_mut() + .expect("runtime has not been initialized") + } + /// Copy a file into the test environment at the given relative path pub fn copy_into(&self, from: impl AsRef, into: impl AsRef) -> anyhow::Result<()> { fn copy_dir_all(from: &Path, into: &Path) -> anyhow::Result<()> { @@ -107,6 +110,11 @@ impl TestEnvironment { Ok(()) } + /// Read a file from the test environment at the given relative path + pub fn read_file(&self, path: impl AsRef) -> std::io::Result> { + std::fs::read(self.temp.path().join(path)) + } + /// Get the path to test environment pub(crate) fn path(&self) -> &Path { self.temp.path() @@ -128,18 +136,19 @@ impl TestEnvironmentConfig { /// * `preboot` - a callback that happens after the services have started but before the runtime is /// * `test` - a callback that runs the test against the runtime /// * `services_config` - the services that the test requires - pub fn spin<'a>( + pub fn spin( spin_binary: PathBuf, spin_up_args: impl IntoIterator, preboot: impl FnOnce(&mut TestEnvironment) -> anyhow::Result<()> + 'static, services_config: ServicesConfig, + mode: SpinMode, ) -> Self { let spin_up_args = spin_up_args.into_iter().collect(); Self { services_config, create_runtime: Box::new(move |env| { preboot(env)?; - Spin::start(&spin_binary, env.path(), spin_up_args) + Spin::start(&spin_binary, env.path(), spin_up_args, mode) }), } } From 2efcbdd9f893926d246d4bdbdc423c9d5a41f814 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 11 Jan 2024 15:13:15 +0100 Subject: [PATCH 4/4] Add dynamic env test Signed-off-by: Ryan Levick --- tests/integration.rs | 3 +- tests/runtime-tests/src/lib.rs | 3 +- tests/spinup_tests.rs | 121 ++-- tests/test-components/components/Cargo.lock | 9 + .../components/headers-dynamic-env/Cargo.toml | 12 + .../headers-dynamic-env}/src/lib.rs | 0 .../spin.toml | 6 +- .../.cargo/config.toml | 2 - .../headers-dynamic-env-test/Cargo.lock | 587 ------------------ .../headers-dynamic-env-test/Cargo.toml | 22 - tests/testcases/mod.rs | 46 -- tests/testing-framework/src/lib.rs | 2 +- tests/testing-framework/src/spin.rs | 65 +- 13 files changed, 169 insertions(+), 709 deletions(-) create mode 100644 tests/test-components/components/headers-dynamic-env/Cargo.toml rename tests/{testcases/headers-dynamic-env-test => test-components/components/headers-dynamic-env}/src/lib.rs (100%) rename tests/testcases/{headers-dynamic-env-test => dynamic-env-test}/spin.toml (64%) delete mode 100644 tests/testcases/headers-dynamic-env-test/.cargo/config.toml delete mode 100644 tests/testcases/headers-dynamic-env-test/Cargo.lock delete mode 100644 tests/testcases/headers-dynamic-env-test/Cargo.toml diff --git a/tests/integration.rs b/tests/integration.rs index db4028aa5..960cbb0a4 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -278,7 +278,8 @@ mod integration_tests { uri: &str, status: u16, ) -> testing_framework::TestResult { - let r = spin.make_http_request(reqwest::Method::GET, uri)?; + let r = + spin.make_http_request(testing_framework::Request::new(reqwest::Method::GET, uri))?; if r.status() != status { return Err(testing_framework::TestError::Failure(anyhow!( "Expected status {} for {} but got {}", diff --git a/tests/runtime-tests/src/lib.rs b/tests/runtime-tests/src/lib.rs index ac692573a..3d983a529 100644 --- a/tests/runtime-tests/src/lib.rs +++ b/tests/runtime-tests/src/lib.rs @@ -181,7 +181,8 @@ fn copy_manifest(test_dir: &Path, env: &mut TestEnvironment) -> anyhow::Re fn test(env: &mut TestEnvironment) -> TestResult { let runtime = env.runtime_mut(); - let response = runtime.make_http_request(reqwest::Method::GET, "/")?; + let request = testing_framework::Request::new(reqwest::Method::GET, "/"); + let response = runtime.make_http_request(request)?; if response.status() == 200 { return Ok(()); } diff --git a/tests/spinup_tests.rs b/tests/spinup_tests.rs index 6af9550a8..e5366dc07 100644 --- a/tests/spinup_tests.rs +++ b/tests/spinup_tests.rs @@ -1,27 +1,9 @@ -use anyhow::Context; -use redis::Commands; +use reqwest::header::HeaderValue; use std::path::PathBuf; #[cfg(feature = "e2e-tests")] mod testcases; -/// Helper macro to assert that a condition is true eventually -macro_rules! assert_eventually { - ($e:expr) => { - let mut i = 0; - loop { - if $e { - break; - } else if i > 20 { - assert!($e); - break; - } - std::thread::sleep(std::time::Duration::from_millis(100)); - i += 1; - } - }; -} - #[test] /// Test that the --key-value flag works as expected fn key_value_cli_flag() -> anyhow::Result<()> { @@ -36,9 +18,12 @@ fn key_value_cli_flag() -> anyhow::Result<()> { let spin = env.runtime_mut(); assert_spin_request( spin, - reqwest::Method::GET, - &format!("/test?key={test_key}"), + testing_framework::Request::new( + reqwest::Method::GET, + &format!("/test?key={test_key}"), + ), 200, + &[], &test_value, ) }, @@ -58,24 +43,33 @@ fn http_smoke_test() -> anyhow::Result<()> { let spin = env.runtime_mut(); assert_spin_request( spin, - reqwest::Method::GET, - "/test/hello", + testing_framework::Request::new(reqwest::Method::GET, "/test/hello"), 200, + &[], "I'm a teapot", )?; assert_spin_request( spin, - reqwest::Method::GET, - "/test/hello/wildcards/should/be/handled", + testing_framework::Request::new( + reqwest::Method::GET, + "/test/hello/wildcards/should/be/handled", + ), 200, + &[], "I'm a teapot", )?; - assert_spin_request(spin, reqwest::Method::GET, "/thishsouldfail", 404, "")?; assert_spin_request( spin, - reqwest::Method::GET, - "/test/hello/test-placement", + testing_framework::Request::new(reqwest::Method::GET, "/thishsouldfail"), + 404, + &[], + "", + )?; + assert_spin_request( + spin, + testing_framework::Request::new(reqwest::Method::GET, "/test/hello/test-placement"), 200, + &[], "text for test", ) }, @@ -85,8 +79,30 @@ fn http_smoke_test() -> anyhow::Result<()> { } #[test] +// TODO: it seems that running this test on macOS CI is not possible because the docker services doesn't run. +// Investigate if there is a possible fix for this. +#[cfg(feature = "e2e-tests")] /// Test that basic redis trigger support works fn redis_smoke_test() -> anyhow::Result<()> { + /// Helper macro to assert that a condition is true eventually + macro_rules! assert_eventually { + ($e:expr) => { + let mut i = 0; + loop { + if $e { + break; + } else if i > 20 { + assert!($e); + break; + } + std::thread::sleep(std::time::Duration::from_millis(100)); + i += 1; + } + }; + } + + use anyhow::Context; + use redis::Commands; run_test( "redis-smoke-test", testing_framework::SpinMode::Redis, @@ -120,6 +136,30 @@ fn redis_smoke_test() -> anyhow::Result<()> { Ok(()) } +#[test] +/// Test dynamic environment variables +fn dynamic_env_test() -> anyhow::Result<()> { + run_test( + "dynamic-env-test", + testing_framework::SpinMode::Http, + vec!["--env".to_owned(), "foo=bar".to_owned()], + testing_framework::ServicesConfig::none(), + move |env| { + let spin = env.runtime_mut(); + assert_spin_request( + spin, + testing_framework::Request::new(reqwest::Method::GET, "/env"), + 200, + &[("env_some_key", "some_value"), ("ENV_foo", "bar")], + "I'm a teapot", + )?; + Ok(()) + }, + )?; + + Ok(()) +} + /// Run an e2e test fn run_test( test_name: impl Into, @@ -147,21 +187,33 @@ fn run_test( /// Assert that a request to the spin server returns the expected status and body fn assert_spin_request( spin: &mut testing_framework::Spin, - method: reqwest::Method, - uri: &str, + request: testing_framework::Request<'_>, expected_status: u16, + expected_headers: &[(&str, &str)], expected_body: &str, ) -> testing_framework::TestResult { - let r = spin.make_http_request(method, uri)?; + let uri = request.uri; + let mut r = spin.make_http_request(request)?; let status = r.status(); + let headers = std::mem::take(r.headers_mut()); let body = r.text().unwrap_or_else(|_| String::from("")); if status != expected_status { return Err(testing_framework::TestError::Failure(anyhow::anyhow!( "Expected status {expected_status} for {uri} but got {status}\nBody:\n{body}", ))); } + let wrong_headers: std::collections::HashMap<_, _> = expected_headers + .iter() + .copied() + .filter(|(ek, ev)| headers.get(*ek) != Some(&HeaderValue::from_str(ev).unwrap())) + .collect(); + if !wrong_headers.is_empty() { + return Err(testing_framework::TestError::Failure(anyhow::anyhow!( + "Expected headers {headers:?} to contain {wrong_headers:?}\nBody:\n{body}" + ))); + } if body != expected_body { - return Err(anyhow::anyhow!("expected {expected_body}, got {body}",).into()); + return Err(anyhow::anyhow!("expected {expected_body}, got {body}").into()); } Ok(()) } @@ -264,11 +316,6 @@ mod spinup_tests { testcases::header_env_routes_works(CONTROLLER).await } - #[tokio::test] - async fn header_dynamic_env_works() { - testcases::header_dynamic_env_works(CONTROLLER).await - } - #[tokio::test] async fn redis_go_works() { testcases::redis_go_works(CONTROLLER).await diff --git a/tests/test-components/components/Cargo.lock b/tests/test-components/components/Cargo.lock index 5c2d5b739..0685a4ce0 100644 --- a/tests/test-components/components/Cargo.lock +++ b/tests/test-components/components/Cargo.lock @@ -162,6 +162,15 @@ dependencies = [ "spin-sdk", ] +[[package]] +name = "headers-dynamic-env" +version = "0.1.0" +dependencies = [ + "anyhow", + "http", + "spin-sdk", +] + [[package]] name = "heck" version = "0.4.1" diff --git a/tests/test-components/components/headers-dynamic-env/Cargo.toml b/tests/test-components/components/headers-dynamic-env/Cargo.toml new file mode 100644 index 000000000..cf6d87bbd --- /dev/null +++ b/tests/test-components/components/headers-dynamic-env/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "headers-dynamic-env" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1" +http = "0.2" +spin-sdk = { path = "../../../../sdk/rust" } diff --git a/tests/testcases/headers-dynamic-env-test/src/lib.rs b/tests/test-components/components/headers-dynamic-env/src/lib.rs similarity index 100% rename from tests/testcases/headers-dynamic-env-test/src/lib.rs rename to tests/test-components/components/headers-dynamic-env/src/lib.rs diff --git a/tests/testcases/headers-dynamic-env-test/spin.toml b/tests/testcases/dynamic-env-test/spin.toml similarity index 64% rename from tests/testcases/headers-dynamic-env-test/spin.toml rename to tests/testcases/dynamic-env-test/spin.toml index fca302f7e..c60dfd64e 100644 --- a/tests/testcases/headers-dynamic-env-test/spin.toml +++ b/tests/testcases/dynamic-env-test/spin.toml @@ -3,13 +3,11 @@ name = "headers-dynamic-env-test" version = "1.0.0" authors = ["Fermyon Engineering "] description = "A simple application that returns hello and goodbye." -trigger = {type = "http"} +trigger = { type = "http" } [[component]] id = "env" -source = "target/wasm32-wasi/release/headers_dynamic_env_test.wasm" +source = "%{source=headers-dynamic-env}" environment = { some_key = "some_value" } -[component.build] -command = "cargo build --target wasm32-wasi --release" [component.trigger] route = "/env/..." diff --git a/tests/testcases/headers-dynamic-env-test/.cargo/config.toml b/tests/testcases/headers-dynamic-env-test/.cargo/config.toml deleted file mode 100644 index 6b77899cb..000000000 --- a/tests/testcases/headers-dynamic-env-test/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-wasi" diff --git a/tests/testcases/headers-dynamic-env-test/Cargo.lock b/tests/testcases/headers-dynamic-env-test/Cargo.lock deleted file mode 100644 index bc28b8c46..000000000 --- a/tests/testcases/headers-dynamic-env-test/Cargo.lock +++ /dev/null @@ -1,587 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - -[[package]] -name = "headers-dynamic-env-test" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "spin-sdk", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "indexmap" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "routefinder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" -dependencies = [ - "smartcow", - "smartstring", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "spdx" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] - -[[package]] -name = "spin-macro" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "bytes", - "http", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin-sdk" -version = "2.2.0-pre0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "form_urlencoded", - "futures", - "http", - "once_cell", - "routefinder", - "serde", - "serde_json", - "spin-macro", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-encoder" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.115.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.38", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/tests/testcases/headers-dynamic-env-test/Cargo.toml b/tests/testcases/headers-dynamic-env-test/Cargo.toml deleted file mode 100644 index c0161d104..000000000 --- a/tests/testcases/headers-dynamic-env-test/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "headers-dynamic-env-test" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = [ "cdylib" ] - -[dependencies] -# Useful crate to handle errors. -anyhow = "1" -# Crate to simplify working with bytes. -bytes = "1" -# General-purpose crate with common HTTP types. -http = "0.2" -spin-sdk = { path = "../../../sdk/rust"} - -[workspace] - -# Metadata about this component. -[package.metadata.component] -name = "spinhelloworld" diff --git a/tests/testcases/mod.rs b/tests/testcases/mod.rs index 84710deae..674c40a54 100644 --- a/tests/testcases/mod.rs +++ b/tests/testcases/mod.rs @@ -604,52 +604,6 @@ pub async fn header_env_routes_works(controller: &dyn Controller) { tc.run(controller).await.unwrap() } -pub async fn header_dynamic_env_works(controller: &dyn Controller) { - async fn checks( - metadata: AppMetadata, - _: Option>>, - _: Option>>, - ) -> Result<()> { - assert_http_response( - get_url(metadata.base.as_str(), "/env").as_str(), - Method::GET, - "", - 200, - &[], - Some("I'm a teapot"), - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/env/foo").as_str(), - Method::GET, - "", - 200, - &[("env_some_key", "some_value")], - Some("I'm a teapot"), - ) - .await?; - - Ok(()) - } - - let tc = TestCaseBuilder::default() - .name("headers-dynamic-env-test".to_string()) - .appname(Some("headers-dynamic-env-test".to_string())) - .deploy_args(vec!["--env".to_string(), "foo=bar".to_string()]) - .assertions( - |metadata: AppMetadata, - stdout_stream: Option>>, - stderr_stream: Option>>| { - Box::pin(checks(metadata, stdout_stream, stderr_stream)) - }, - ) - .build() - .unwrap(); - - tc.run(controller).await.unwrap() -} - pub async fn redis_go_works(controller: &dyn Controller) { async fn checks( _: AppMetadata, diff --git a/tests/testing-framework/src/lib.rs b/tests/testing-framework/src/lib.rs index 599560ee6..a2a377b51 100644 --- a/tests/testing-framework/src/lib.rs +++ b/tests/testing-framework/src/lib.rs @@ -12,7 +12,7 @@ mod test_environment; pub use manifest_template::ManifestTemplate; pub use services::ServicesConfig; -pub use spin::{Spin, SpinMode}; +pub use spin::{Request, Spin, SpinMode}; pub use test_environment::{TestEnvironment, TestEnvironmentConfig}; #[derive(Debug, Clone, Copy)] diff --git a/tests/testing-framework/src/spin.rs b/tests/testing-framework/src/spin.rs index eb58262aa..232263712 100644 --- a/tests/testing-framework/src/spin.rs +++ b/tests/testing-framework/src/spin.rs @@ -1,3 +1,5 @@ +use anyhow::Context; + use crate::{io::OutputStream, Runtime}; use std::{ path::Path, @@ -116,10 +118,12 @@ impl Spin { Ok(spin) } + /// Make an HTTP request against Spin + /// + /// Will fail if Spin has already exited or if the io mode is not HTTP pub fn make_http_request( &mut self, - method: reqwest::Method, - path: &str, + request: Request<'_>, ) -> anyhow::Result { let IoMode::Http(port) = self.io_mode else { anyhow::bail!("Spin is not running in HTTP mode"); @@ -128,13 +132,23 @@ impl Spin { anyhow::bail!("Spin exited early with status code {:?}", status.code()); } log::debug!("Connecting to HTTP server on port {port}..."); - let request = reqwest::blocking::Request::new( - method, - format!("http://localhost:{}{}", port, path) - .parse() - .unwrap(), + let mut outgoing = reqwest::blocking::Request::new( + request.method, + reqwest::Url::parse(&format!("http://localhost:{port}")) + .unwrap() + .join(request.uri) + .context("could not construct url for request against Spin")?, ); - let response = reqwest::blocking::Client::new().execute(request)?; + outgoing + .headers_mut() + .extend(request.headers.iter().map(|(k, v)| { + ( + reqwest::header::HeaderName::from_bytes(k.as_bytes()).unwrap(), + reqwest::header::HeaderValue::from_str(v).unwrap(), + ) + })); + *outgoing.body_mut() = request.body.map(Into::into); + let response = reqwest::blocking::Client::new().execute(outgoing)?; log::debug!("Awaiting response from server"); if let Some(status) = self.try_wait()? { anyhow::bail!("Spin exited early with status code {:?}", status.code()); @@ -201,3 +215,38 @@ fn get_random_port() -> anyhow::Result { .local_addr()? .port()) } + +/// A request to the spin server +pub struct Request<'a> { + pub method: reqwest::Method, + pub uri: &'a str, + pub headers: &'a [(&'a str, &'a str)], + pub body: Option>, +} + +impl<'a> Request<'a> { + /// Create a new request with no headers or body + pub fn new(method: reqwest::Method, uri: &'a str) -> Self { + Self { + method, + uri, + headers: &[], + body: None, + } + } + + /// Create a new request with headers and a body + pub fn full( + method: reqwest::Method, + uri: &'a str, + headers: &'a [(&'a str, &'a str)], + body: Option>, + ) -> Self { + Self { + method, + uri, + headers, + body, + } + } +}