Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add macro for generating runtime tests automatically #2196

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ e2e-testing = { path = "crates/e2e-testing" }
http-body-util = { workspace = true }
runtime-tests = { path = "tests/runtime-tests" }
test-components = { path = "tests/test-components" }
test-codegen-macro = { path = "crates/test-codegen-macro" }

[build-dependencies]
cargo-target-dep = { git = "https://github.com/fermyon/cargo-target-dep", rev = "482f269eceb7b1a7e8fc618bf8c082dd24979cf1" }
Expand All @@ -113,12 +114,7 @@ llm-metal = ["llm", "spin-trigger-http/llm-metal"]
llm-cublas = ["llm", "spin-trigger-http/llm-cublas"]

[workspace]
members = [
"crates/*",
"sdk/rust",
"sdk/rust/macro",
"tests/runtime-tests",
]
members = ["crates/*", "sdk/rust", "sdk/rust/macro", "tests/runtime-tests"]

[workspace.dependencies]
anyhow = "1.0.75"
Expand Down
14 changes: 14 additions & 0 deletions crates/test-codegen-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "test-codegen-macro"
version = "0.0.0"
edition.workspace = true
publish = false

[lib]
proc-macro = true
doctest = false
test = false

[dependencies]
heck = "0.4.0"
quote = "1.0.32"
3 changes: 3 additions & 0 deletions crates/test-codegen-macro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Test Codegen Macro

A macro for automatically producing `#[test]` annotated functions based on file directory structure. This is used by the runtime tests so that when adding a runtime test, you're not required to also add a test function corresponding to that runtime test.
42 changes: 42 additions & 0 deletions crates/test-codegen-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use heck::*;
use proc_macro::TokenStream;
use std::{env, path::PathBuf};

/// This macro generates the `#[test]` functions for the runtime tests.
#[proc_macro]
pub fn codegen_tests(_input: TokenStream) -> TokenStream {
let mut tests = Vec::new();
let tests_path =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../tests/runtime-tests/tests");
for entry in std::fs::read_dir(tests_path).expect("failed to read tests directory") {
let entry = entry.expect("error reading test directory entry");
let test = entry.path();

if entry.file_type().unwrap().is_dir() {
let requires_services = entry.path().join("services").exists();

let name = test.file_stem().unwrap().to_str().unwrap();
let ident = quote::format_ident!("{}", name.to_snake_case());
let feature_attribute = if requires_services {
quote::quote!(#[cfg(feature = "e2e-tests")])
} else {
quote::quote!()
};
// Generate the following code:
// ```rust
// #[test]
// fn outbound_mysql() {
// run("outbound-mysql")
// }
// ```
tests.push(quote::quote! {
#[test]
#feature_attribute
fn #ident() {
run(#name)
}
});
}
}
(quote::quote!(#(#tests)*)).into()
}
Empty file.
Empty file.
Empty file.
37 changes: 4 additions & 33 deletions tests/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,11 @@
#[cfg(feature = "e2e-tests")]
/// Run the tests found in `tests/runtime-tests` directory.
mod runtime_tests {
use runtime_tests::Config;
use std::path::PathBuf;

// TODO: write a proc macro that reads from the tests folder
// and creates tests for every subdirectory
macro_rules! test {
($ident:ident, $path:literal) => {
#[test]
fn $ident() {
run($path)
}
};
}

test!(outbound_mysql, "outbound-mysql");
test!(outbound_mysql_no_permission, "outbound-mysql-no-permission");
test!(outbound_postgres, "outbound-postgres");
test!(
outbound_postgres_no_permission,
"outbound-postgres-no-permission"
);
test!(outbound_redis, "outbound-redis");
test!(outbound_redis_no_permission, "outbound-redis-no-permission");
test!(sqlite, "sqlite");
test!(sqlite_no_permission, "sqlite-no-permission");
test!(key_value, "key-value");
test!(key_value_no_permission, "key-value-no-permission");
test!(variables, "variables");
test!(tcp_sockets, "tcp-sockets");
test!(tcp_sockets_ip_range, "tcp-sockets-ip-range");
test!(
tcp_sockets_no_port_permission,
"tcp-sockets-no-port-permission"
);
test!(tcp_sockets_no_ip_permission, "tcp-sockets-no-ip-permission");
// The macro inspects the tests directory and
// generates individual tests for each one.
test_codegen_macro::codegen_tests!();

fn run(name: &str) {
let spin_binary_path = env!("CARGO_BIN_EXE_spin").into();
Expand Down