Merge pull request #1459 from itowlson/test-spin-up-kv
Exercise `spin up --key-value` in tests
This commit is contained in:
commit
8be5db2b93
|
@ -6073,6 +6073,7 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ toml = "0.6"
|
|||
tracing = { workspace = true }
|
||||
tracing-subscriber = { version = "0.3.7", features = ["env-filter"] }
|
||||
url = "2.2.2"
|
||||
uuid = "^1.0"
|
||||
uuid = { version = "^1.0", features = ["v4"] }
|
||||
wasmtime = { workspace = true }
|
||||
watchexec = { git = "https://github.com/watchexec/watchexec.git", rev = "8e91d26ef6400c1e60b32a8314cbb144fa33f288" }
|
||||
subprocess = "0.2.9"
|
||||
|
|
|
@ -10,11 +10,13 @@ use std::future::Future;
|
|||
use tokio::io::BufReader;
|
||||
use tokio::process::{ChildStderr, ChildStdout};
|
||||
|
||||
type ChecksFunc = fn(
|
||||
type ChecksFunc = Box<
|
||||
dyn Fn(
|
||||
AppMetadata,
|
||||
Option<BufReader<ChildStdout>>,
|
||||
Option<BufReader<ChildStderr>>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<()>>>>;
|
||||
) -> Pin<Box<dyn Future<Output = Result<()>>>>,
|
||||
>;
|
||||
|
||||
/// Represents a testcase
|
||||
#[derive(Builder)]
|
||||
|
@ -65,6 +67,7 @@ pub struct TestCase {
|
|||
pub pre_build_hooks: Option<Vec<Vec<String>>>,
|
||||
|
||||
/// assertions to run once the app is running
|
||||
#[builder(setter(custom))]
|
||||
pub assertions: ChecksFunc,
|
||||
|
||||
/// registry app url where app is pushed and run from
|
||||
|
@ -72,6 +75,22 @@ pub struct TestCase {
|
|||
pub push_to_registry: Option<String>,
|
||||
}
|
||||
|
||||
impl TestCaseBuilder {
|
||||
pub fn assertions(
|
||||
self,
|
||||
value: impl Fn(
|
||||
AppMetadata,
|
||||
Option<BufReader<ChildStdout>>,
|
||||
Option<BufReader<ChildStderr>>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<()>>>>
|
||||
+ 'static,
|
||||
) -> Self {
|
||||
let mut this = self;
|
||||
this.assertions = Some(Box::new(value));
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase {
|
||||
pub async fn run(&self, controller: &dyn Controller) -> Result<()> {
|
||||
controller.name();
|
||||
|
|
|
@ -13,6 +13,9 @@ anyhow = "1"
|
|||
bytes = "1"
|
||||
# General-purpose crate with common HTTP types.
|
||||
http = "0.2"
|
||||
itertools = "0.10"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_qs = "0.12"
|
||||
spin-sdk = { path = "../../../sdk/rust"}
|
||||
# The wit-bindgen-rust dependency generates bindings for interfaces.
|
||||
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "cb871cfa1ee460b51eb1d144b175b9aab9c50aba" }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use anyhow::{ensure, Result};
|
||||
use itertools::sorted;
|
||||
use spin_sdk::{
|
||||
http::{Request, Response},
|
||||
http_component,
|
||||
|
@ -6,11 +7,16 @@ use spin_sdk::{
|
|||
};
|
||||
|
||||
#[http_component]
|
||||
fn handle_request(_req: Request) -> Result<Response> {
|
||||
fn handle_request(req: Request) -> Result<Response> {
|
||||
// TODO: once we allow users to pass non-default stores, test that opening
|
||||
// an allowed-but-non-existent one returns Error::NoSuchStore
|
||||
ensure!(matches!(Store::open("forbidden"), Err(Error::AccessDenied)));
|
||||
|
||||
let query = req.uri().query().expect("Should have a testkey query string");
|
||||
let query: std::collections::HashMap::<String, String> = 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()?;
|
||||
|
||||
store.delete("bar")?;
|
||||
|
@ -29,9 +35,21 @@ fn handle_request(_req: Request) -> Result<Response> {
|
|||
|
||||
ensure!(b"wow" as &[_] == &store.get("bar")?);
|
||||
|
||||
ensure!(&["bar".to_owned()] as &[_] == &store.get_keys()?);
|
||||
ensure!(
|
||||
init_val.as_bytes() == &store.get(&init_key)?,
|
||||
"Expected to look up {init_key} and get {init_val} but actually got {}",
|
||||
String::from_utf8_lossy(&store.get(&init_key)?)
|
||||
);
|
||||
|
||||
ensure!(
|
||||
sorted(vec!["bar".to_owned(), init_key.to_owned()]).collect::<Vec<_>>() == sorted(store.get_keys()?).collect::<Vec<_>>(),
|
||||
"Expected exectly keys 'bar' and '{}' but got '{:?}'",
|
||||
init_key,
|
||||
&store.get_keys()?
|
||||
);
|
||||
|
||||
store.delete("bar")?;
|
||||
store.delete(&init_key)?;
|
||||
|
||||
ensure!(&[] as &[String] == &store.get_keys()?);
|
||||
|
||||
|
|
|
@ -20,13 +20,19 @@ pub mod all {
|
|||
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<BufReader<ChildStdout>>,
|
||||
_: Option<BufReader<ChildStderr>>,
|
||||
) -> Result<()> {
|
||||
assert_http_response(
|
||||
get_url(metadata.base.as_str(), "/test").as_str(),
|
||||
get_url(
|
||||
metadata.base.as_str(),
|
||||
&format!("/test?testkey={test_init_key}&testval={test_init_value}"),
|
||||
)
|
||||
.as_str(),
|
||||
Method::GET,
|
||||
"",
|
||||
200,
|
||||
|
@ -36,15 +42,24 @@ pub mod all {
|
|||
.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(
|
||||
|metadata: AppMetadata,
|
||||
move |metadata: AppMetadata,
|
||||
stdout_stream: Option<BufReader<ChildStdout>>,
|
||||
stderr_stream: Option<BufReader<ChildStderr>>| {
|
||||
Box::pin(checks(metadata, stdout_stream, stderr_stream))
|
||||
let ik = init_key.clone();
|
||||
let iv = init_value.clone();
|
||||
Box::pin(checks(metadata, ik, iv, stdout_stream, stderr_stream))
|
||||
},
|
||||
)
|
||||
.build()
|
||||
|
|
Loading…
Reference in New Issue