From a10730cb0f61fb7331c62168459c5dc43d0724bd Mon Sep 17 00:00:00 2001 From: Lann Martin Date: Fri, 26 Jul 2024 14:02:24 -0400 Subject: [PATCH] factors: Update spin-factors-test's TestEnvironment Signed-off-by: Lann Martin --- Cargo.lock | 2 - crates/core/tests/integration_test.rs | 2 +- .../tests/{test.rs => factor_test.rs} | 53 +++++++------- .../tests/{factor.rs => factor_test.rs} | 6 +- crates/factor-outbound-http/Cargo.toml | 1 - .../factor-outbound-http/tests/factor_test.rs | 19 ++--- .../tests/factor_test.rs | 32 +++----- .../factor-outbound-pg/tests/factor_test.rs | 31 +++----- crates/factor-outbound-redis/Cargo.toml | 1 - .../tests/factor_test.rs | 39 ++++------ .../tests/{factor.rs => factor_test.rs} | 33 ++++----- crates/factor-variables/src/spin_cli/env.rs | 4 +- crates/factor-variables/tests/factor_test.rs | 36 ++++----- crates/factor-wasi/tests/factor_test.rs | 17 ++--- crates/factors-derive/src/lib.rs | 25 +------ crates/factors-test/src/lib.rs | 73 ++++++++++--------- crates/factors/src/factor.rs | 10 +-- crates/factors/src/runtime_factors.rs | 2 +- 18 files changed, 160 insertions(+), 226 deletions(-) rename crates/factor-key-value/tests/{test.rs => factor_test.rs} (87%) rename crates/factor-llm/tests/{factor.rs => factor_test.rs} (96%) rename crates/factor-sqlite/tests/{factor.rs => factor_test.rs} (84%) diff --git a/Cargo.lock b/Cargo.lock index 12c87ed71..d9769241d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7648,7 +7648,6 @@ dependencies = [ "http 1.1.0", "spin-factor-outbound-networking", "spin-factor-variables", - "spin-factor-wasi", "spin-factors", "spin-factors-test", "spin-world", @@ -7702,7 +7701,6 @@ dependencies = [ "spin-core", "spin-factor-outbound-networking", "spin-factor-variables", - "spin-factor-wasi", "spin-factors", "spin-factors-test", "spin-world", diff --git a/crates/core/tests/integration_test.rs b/crates/core/tests/integration_test.rs index 97dd5e644..da328b2c5 100644 --- a/crates/core/tests/integration_test.rs +++ b/crates/core/tests/integration_test.rs @@ -138,7 +138,7 @@ async fn run_test( }] }))?; let app = App::new("test-app", locked); - let configured_app = factors.configure_app(app, ())?; + let configured_app = factors.configure_app(app, Default::default())?; let mut builders = factors.prepare(&configured_app, "test-component")?; // FIXME: it is unfortunate that we have to unwrap here... builders.wasi.as_mut().unwrap().args(args); diff --git a/crates/factor-key-value/tests/test.rs b/crates/factor-key-value/tests/factor_test.rs similarity index 87% rename from crates/factor-key-value/tests/test.rs rename to crates/factor-key-value/tests/factor_test.rs index aed6bb998..c0c24eac0 100644 --- a/crates/factor-key-value/tests/test.rs +++ b/crates/factor-key-value/tests/factor_test.rs @@ -38,12 +38,12 @@ async fn default_key_value_works() -> anyhow::Result<()> { let factors = TestFactors { key_value: KeyValueFactor::new(test_resolver), }; - let env = TestEnvironment::default_manifest_extend(toml! { + let env = TestEnvironment::new(factors).extend_manifest(toml! { [component.test-component] source = "does-not-exist.wasm" key_value_stores = ["default"] }); - let state = env.build_instance_state(factors, ()).await?; + let state = env.build_instance_state().await?; assert_eq!( state.key_value.allowed_stores(), @@ -67,14 +67,14 @@ async fn run_test_with_config_and_stores_for_label( key_value: KeyValueFactor::new(test_resolver), }; let labels_clone = labels.clone(); - let env = TestEnvironment::default_manifest_extend(toml! { - [component.test-component] - source = "does-not-exist.wasm" - key_value_stores = labels_clone - }); - let state = env - .build_instance_state(factors, TomlConfig(runtime_config)) - .await?; + let env = TestEnvironment::new(factors) + .extend_manifest(toml! { + [component.test-component] + source = "does-not-exist.wasm" + key_value_stores = labels_clone + }) + .runtime_config(TomlConfig(runtime_config))?; + let state = env.build_instance_state().await?; assert_eq!( labels, state.key_value.allowed_stores().iter().collect::>() @@ -192,29 +192,28 @@ async fn misconfigured_spin_key_value_fails() -> anyhow::Result<()> { #[tokio::test] async fn multiple_custom_key_value_uses_first_store() -> anyhow::Result<()> { let tmp_dir = tempdir::TempDir::new("example")?; - let runtime_config = toml::toml! { - [key_value_store.custom] - type = "spin" - path = "custom.db" - - [key_value_store.custom] - type = "redis" - url = "redis://localhost:6379" - }; let mut test_resolver = DelegatingRuntimeConfigResolver::new(); test_resolver.add_store_type(RedisKeyValueStore)?; test_resolver.add_store_type(SpinKeyValueStore::new(tmp_dir.path().to_owned()))?; let factors = TestFactors { key_value: KeyValueFactor::new(test_resolver), }; - let env = TestEnvironment::default_manifest_extend(toml! { - [component.test-component] - source = "does-not-exist.wasm" - key_value_stores = ["custom"] - }); - let state = env - .build_instance_state(factors, TomlConfig(Some(runtime_config))) - .await?; + let env = TestEnvironment::new(factors) + .extend_manifest(toml! { + [component.test-component] + source = "does-not-exist.wasm" + key_value_stores = ["custom"] + }) + .runtime_config(TomlConfig(Some(toml::toml! { + [key_value_store.custom] + type = "spin" + path = "custom.db" + + [key_value_store.custom] + type = "redis" + url = "redis://localhost:6379" + })))?; + let state = env.build_instance_state().await?; assert_eq!( state.key_value.allowed_stores(), diff --git a/crates/factor-llm/tests/factor.rs b/crates/factor-llm/tests/factor_test.rs similarity index 96% rename from crates/factor-llm/tests/factor.rs rename to crates/factor-llm/tests/factor_test.rs index a05b68aa3..4504238b5 100644 --- a/crates/factor-llm/tests/factor.rs +++ b/crates/factor-llm/tests/factor_test.rs @@ -42,13 +42,13 @@ async fn llm_works() -> anyhow::Result<()> { }) as _ }), }; - - let env = TestEnvironment::default_manifest_extend(toml! { + let env = TestEnvironment::new(factors).extend_manifest(toml! { [component.test-component] source = "does-not-exist.wasm" ai_models = ["llama2-chat"] }); - let mut state = env.build_instance_state(factors, ()).await?; + let mut state = env.build_instance_state().await?; + assert_eq!( &*state.llm.allowed_models, &["llama2-chat".to_owned()] diff --git a/crates/factor-outbound-http/Cargo.toml b/crates/factor-outbound-http/Cargo.toml index 7cf2044d8..b9c5943e4 100644 --- a/crates/factor-outbound-http/Cargo.toml +++ b/crates/factor-outbound-http/Cargo.toml @@ -8,7 +8,6 @@ edition = { workspace = true } anyhow = "1.0" http = "1.1.0" spin-factor-outbound-networking = { path = "../factor-outbound-networking" } -spin-factor-wasi = { path = "../factor-wasi" } spin-factors = { path = "../factors" } spin-world = { path = "../world" } tracing = { workspace = true } diff --git a/crates/factor-outbound-http/tests/factor_test.rs b/crates/factor-outbound-http/tests/factor_test.rs index d5479ee1c..90394f3a0 100644 --- a/crates/factor-outbound-http/tests/factor_test.rs +++ b/crates/factor-outbound-http/tests/factor_test.rs @@ -5,7 +5,6 @@ use http::Request; use spin_factor_outbound_http::OutboundHttpFactor; use spin_factor_outbound_networking::OutboundNetworkingFactor; use spin_factor_variables::spin_cli::VariablesFactor; -use spin_factor_wasi::{DummyFilesMounter, WasiFactor}; use spin_factors::{anyhow, RuntimeFactors}; use spin_factors_test::{toml, TestEnvironment}; use wasmtime_wasi_http::{ @@ -14,30 +13,24 @@ use wasmtime_wasi_http::{ #[derive(RuntimeFactors)] struct TestFactors { - wasi: WasiFactor, variables: VariablesFactor, networking: OutboundNetworkingFactor, http: OutboundHttpFactor, } -fn test_env() -> TestEnvironment { - TestEnvironment::default_manifest_extend(toml! { - [component.test-component] - source = "does-not-exist.wasm" - allowed_outbound_hosts = ["http://allowed.test"] - }) -} - #[tokio::test] async fn disallowed_host_fails() -> anyhow::Result<()> { let factors = TestFactors { - wasi: WasiFactor::new(DummyFilesMounter), variables: VariablesFactor::default(), networking: OutboundNetworkingFactor, http: OutboundHttpFactor, }; - let env = test_env(); - let mut state = env.build_instance_state(factors, ()).await?; + let env = TestEnvironment::new(factors).extend_manifest(toml! { + [component.test-component] + source = "does-not-exist.wasm" + allowed_outbound_hosts = ["http://allowed.test"] + }); + let mut state = env.build_instance_state().await?; let mut wasi_http = OutboundHttpFactor::get_wasi_http_impl(&mut state).unwrap(); let req = Request::get("https://denied.test").body(Default::default())?; diff --git a/crates/factor-outbound-networking/tests/factor_test.rs b/crates/factor-outbound-networking/tests/factor_test.rs index 950fd9a3a..8d85af094 100644 --- a/crates/factor-outbound-networking/tests/factor_test.rs +++ b/crates/factor-outbound-networking/tests/factor_test.rs @@ -12,14 +12,6 @@ struct TestFactors { networking: OutboundNetworkingFactor, } -fn test_env() -> TestEnvironment { - TestEnvironment::default_manifest_extend(toml! { - [component.test-component] - source = "does-not-exist.wasm" - allowed_outbound_hosts = ["*://192.0.2.1:12345"] - }) -} - #[tokio::test] async fn configures_wasi_socket_addr_check() -> anyhow::Result<()> { let factors = TestFactors { @@ -27,9 +19,12 @@ async fn configures_wasi_socket_addr_check() -> anyhow::Result<()> { variables: VariablesFactor::default(), networking: OutboundNetworkingFactor, }; - - let env = test_env(); - let mut state = env.build_instance_state(factors, ()).await?; + let env = TestEnvironment::new(factors).extend_manifest(toml! { + [component.test-component] + source = "does-not-exist.wasm" + allowed_outbound_hosts = ["*://192.0.2.1:12345"] + }); + let mut state = env.build_instance_state().await?; let mut wasi = WasiFactor::get_wasi_impl(&mut state).unwrap(); let network_resource = wasi.instance_network()?; @@ -61,14 +56,11 @@ async fn wasi_factor_is_optional() -> anyhow::Result<()> { variables: VariablesFactor, networking: OutboundNetworkingFactor, } - TestEnvironment::default() - .build_instance_state( - WithoutWasi { - variables: VariablesFactor::default(), - networking: OutboundNetworkingFactor, - }, - (), - ) - .await?; + TestEnvironment::new(WithoutWasi { + variables: VariablesFactor::default(), + networking: OutboundNetworkingFactor, + }) + .build_instance_state() + .await?; Ok(()) } diff --git a/crates/factor-outbound-pg/tests/factor_test.rs b/crates/factor-outbound-pg/tests/factor_test.rs index 89d89f924..77fa257bb 100644 --- a/crates/factor-outbound-pg/tests/factor_test.rs +++ b/crates/factor-outbound-pg/tests/factor_test.rs @@ -2,7 +2,7 @@ use anyhow::{bail, Result}; use spin_factor_outbound_networking::OutboundNetworkingFactor; use spin_factor_outbound_pg::client::Client; use spin_factor_outbound_pg::OutboundPgFactor; -use spin_factor_variables::spin_cli::{StaticVariables, VariablesFactor}; +use spin_factor_variables::spin_cli::VariablesFactor; use spin_factors::{anyhow, RuntimeFactors}; use spin_factors_test::{toml, TestEnvironment}; use spin_world::async_trait; @@ -18,18 +18,16 @@ struct TestFactors { pg: OutboundPgFactor, } -fn factors() -> Result { - let mut f = TestFactors { +fn factors() -> TestFactors { + TestFactors { variables: VariablesFactor::default(), networking: OutboundNetworkingFactor, pg: OutboundPgFactor::::new(), - }; - f.variables.add_provider_resolver(StaticVariables)?; - Ok(f) + } } -fn test_env() -> TestEnvironment { - TestEnvironment::default_manifest_extend(toml! { +fn test_env() -> TestEnvironment { + TestEnvironment::new(factors()).extend_manifest(toml! { [component.test-component] source = "does-not-exist.wasm" allowed_outbound_hosts = ["postgres://*:*"] @@ -38,12 +36,11 @@ fn test_env() -> TestEnvironment { #[tokio::test] async fn disallowed_host_fails() -> anyhow::Result<()> { - let factors = factors()?; - let env = TestEnvironment::default_manifest_extend(toml! { + let env = TestEnvironment::new(factors()).extend_manifest(toml! { [component.test-component] source = "does-not-exist.wasm" }); - let mut state = env.build_instance_state(factors, ()).await?; + let mut state = env.build_instance_state().await?; let res = state .pg @@ -59,9 +56,7 @@ async fn disallowed_host_fails() -> anyhow::Result<()> { #[tokio::test] async fn allowed_host_succeeds() -> anyhow::Result<()> { - let factors = factors()?; - let env = test_env(); - let mut state = env.build_instance_state(factors, ()).await?; + let mut state = test_env().build_instance_state().await?; let res = state .pg @@ -76,9 +71,7 @@ async fn allowed_host_succeeds() -> anyhow::Result<()> { #[tokio::test] async fn exercise_execute() -> anyhow::Result<()> { - let factors = factors()?; - let env = test_env(); - let mut state = env.build_instance_state(factors, ()).await?; + let mut state = test_env().build_instance_state().await?; let connection = state .pg @@ -95,9 +88,7 @@ async fn exercise_execute() -> anyhow::Result<()> { #[tokio::test] async fn exercise_query() -> anyhow::Result<()> { - let factors = factors()?; - let env = test_env(); - let mut state = env.build_instance_state(factors, ()).await?; + let mut state = test_env().build_instance_state().await?; let connection = state .pg diff --git a/crates/factor-outbound-redis/Cargo.toml b/crates/factor-outbound-redis/Cargo.toml index 330e070a4..0dffe6ea4 100644 --- a/crates/factor-outbound-redis/Cargo.toml +++ b/crates/factor-outbound-redis/Cargo.toml @@ -19,7 +19,6 @@ redis = { version = "0.21", features = ["tokio-comp", "tokio-native-tls-comp", " spin-factors-test = { path = "../factors-test" } tokio = { version = "1", features = ["macros", "rt"] } spin-factor-variables = { path = "../factor-variables" } -spin-factor-wasi = { path = "../factor-wasi" } # wasmtime-wasi-http = { workspace = true } [lints] diff --git a/crates/factor-outbound-redis/tests/factor_test.rs b/crates/factor-outbound-redis/tests/factor_test.rs index 89b8f64da..dc6578a33 100644 --- a/crates/factor-outbound-redis/tests/factor_test.rs +++ b/crates/factor-outbound-redis/tests/factor_test.rs @@ -1,47 +1,34 @@ use anyhow::bail; use spin_factor_outbound_networking::OutboundNetworkingFactor; use spin_factor_outbound_redis::OutboundRedisFactor; -use spin_factor_variables::spin_cli::{StaticVariables, VariablesFactor}; -use spin_factor_wasi::{DummyFilesMounter, WasiFactor}; +use spin_factor_variables::spin_cli::VariablesFactor; use spin_factors::{anyhow, RuntimeFactors}; use spin_factors_test::{toml, TestEnvironment}; use spin_world::v2::redis::{Error, HostConnection}; #[derive(RuntimeFactors)] struct TestFactors { - wasi: WasiFactor, variables: VariablesFactor, networking: OutboundNetworkingFactor, redis: OutboundRedisFactor, } -fn get_test_factors() -> TestFactors { - TestFactors { - wasi: WasiFactor::new(DummyFilesMounter), +#[tokio::test] +async fn no_outbound_hosts_fails() -> anyhow::Result<()> { + let factors = TestFactors { variables: VariablesFactor::default(), networking: OutboundNetworkingFactor, redis: OutboundRedisFactor, - } -} - -#[tokio::test] -async fn no_outbound_hosts_fails() -> anyhow::Result<()> { - let mut factors = get_test_factors(); - - factors.variables.add_provider_resolver(StaticVariables)?; - - let env = TestEnvironment { - manifest: toml! { - spin_manifest_version = 2 - application.name = "test-app" - [[trigger.test]] - - [component.test-component] - source = "does-not-exist.wasm" - }, - ..Default::default() }; - let mut state = env.build_instance_state(factors, ()).await?; + let env = TestEnvironment::new(factors).extend_manifest(toml! { + spin_manifest_version = 2 + application.name = "test-app" + [[trigger.test]] + + [component.test-component] + source = "does-not-exist.wasm" + }); + let mut state = env.build_instance_state().await?; let connection = state .redis .open("redis://redis.test:8080".to_string()) diff --git a/crates/factor-sqlite/tests/factor.rs b/crates/factor-sqlite/tests/factor_test.rs similarity index 84% rename from crates/factor-sqlite/tests/factor.rs rename to crates/factor-sqlite/tests/factor_test.rs index 690dff009..4699dab78 100644 --- a/crates/factor-sqlite/tests/factor.rs +++ b/crates/factor-sqlite/tests/factor_test.rs @@ -2,7 +2,7 @@ use std::{collections::HashSet, sync::Arc}; use factor_sqlite::{runtime_config::spin::SpinSqliteRuntimeConfig, SqliteFactor}; use spin_factors::{ - anyhow::{self, bail}, + anyhow::{self, bail, Context}, runtime_config::toml::TomlKeyTracker, Factor, FactorRuntimeConfigSource, RuntimeConfigSourceFinalizer, RuntimeFactors, }; @@ -19,12 +19,12 @@ async fn sqlite_works() -> anyhow::Result<()> { let factors = TestFactors { sqlite: SqliteFactor::new(test_resolver), }; - let env = TestEnvironment::default_manifest_extend(toml! { + let env = TestEnvironment::new(factors).extend_manifest(toml! { [component.test-component] source = "does-not-exist.wasm" sqlite_databases = ["default"] }); - let state = env.build_instance_state(factors, ()).await?; + let state = env.build_instance_state().await?; assert_eq!( state.sqlite.allowed_databases(), @@ -40,12 +40,12 @@ async fn errors_when_non_configured_database_used() -> anyhow::Result<()> { let factors = TestFactors { sqlite: SqliteFactor::new(test_resolver), }; - let env = TestEnvironment::default_manifest_extend(toml! { + let env = TestEnvironment::new(factors).extend_manifest(toml! { [component.test-component] source = "does-not-exist.wasm" sqlite_databases = ["foo"] }); - let Err(err) = env.build_instance_state(factors, ()).await else { + let Err(err) = env.build_instance_state().await else { bail!("Expected build_instance_state to error but it did not"); }; @@ -62,26 +62,21 @@ async fn no_error_when_database_is_configured() -> anyhow::Result<()> { let factors = TestFactors { sqlite: SqliteFactor::new(test_resolver), }; - let env = TestEnvironment::default_manifest_extend(toml! { - [component.test-component] - source = "does-not-exist.wasm" - sqlite_databases = ["foo"] - }); let runtime_config = toml! { [sqlite_database.foo] type = "spin" }; let sqlite_config = SpinSqliteRuntimeConfig::new("/".into(), "/".into()); - if let Err(e) = env - .build_instance_state( - factors, - TomlRuntimeSource::new(&runtime_config, sqlite_config), - ) + let env = TestEnvironment::new(factors) + .extend_manifest(toml! { + [component.test-component] + source = "does-not-exist.wasm" + sqlite_databases = ["foo"] + }) + .runtime_config(TomlRuntimeSource::new(&runtime_config, sqlite_config))?; + env.build_instance_state() .await - { - bail!("Expected build_instance_state to succeed but it errored: {e}"); - } - + .context("build_instance_state failed")?; Ok(()) } diff --git a/crates/factor-variables/src/spin_cli/env.rs b/crates/factor-variables/src/spin_cli/env.rs index 8db82e1d6..779f54d85 100644 --- a/crates/factor-variables/src/spin_cli/env.rs +++ b/crates/factor-variables/src/spin_cli/env.rs @@ -52,10 +52,12 @@ pub struct EnvVariablesConfig { const DEFAULT_ENV_PREFIX: &str = "SPIN_VARIABLE"; +type EnvFetcherFn = Box Result + Send + Sync>; + /// A config Provider that uses environment variables. pub struct EnvVariablesProvider { prefix: Option, - env_fetcher: Box Result + Send + Sync>, + env_fetcher: EnvFetcherFn, dotenv_path: Option, dotenv_cache: OnceLock>, } diff --git a/crates/factor-variables/tests/factor_test.rs b/crates/factor-variables/tests/factor_test.rs index 7557f1882..cc2735574 100644 --- a/crates/factor-variables/tests/factor_test.rs +++ b/crates/factor-variables/tests/factor_test.rs @@ -13,24 +13,8 @@ struct TestFactors { variables: VariablesFactor, } -fn test_env() -> TestEnvironment { - TestEnvironment::default_manifest_extend(toml! { - [variables] - foo = { required = true } - - [component.test-component] - source = "does-not-exist.wasm" - variables = { baz = "<{{ foo }}>" } - }) -} - #[tokio::test] async fn static_provider_works() -> anyhow::Result<()> { - let runtime_config = toml! { - [[variable_provider]] - type = "static" - values = { foo = "bar" } - }; let mut factors = TestFactors { variables: VariablesFactor::default(), }; @@ -38,10 +22,22 @@ async fn static_provider_works() -> anyhow::Result<()> { // The env provider will be ignored since there's no configuration for it. factors.variables.add_provider_resolver(EnvVariables)?; - let env = test_env(); - let mut state = env - .build_instance_state(factors, TomlConfig(runtime_config)) - .await?; + let env = TestEnvironment::new(factors) + .extend_manifest(toml! { + [variables] + foo = { required = true } + + [component.test-component] + source = "does-not-exist.wasm" + variables = { baz = "<{{ foo }}>" } + }) + .runtime_config(TomlConfig(toml! { + [[variable_provider]] + type = "static" + values = { foo = "bar" } + }))?; + + let mut state = env.build_instance_state().await?; let val = state.variables.get("baz".try_into().unwrap()).await?; assert_eq!(val, ""); Ok(()) diff --git a/crates/factor-wasi/tests/factor_test.rs b/crates/factor-wasi/tests/factor_test.rs index d6019393f..e5f1c7f29 100644 --- a/crates/factor-wasi/tests/factor_test.rs +++ b/crates/factor-wasi/tests/factor_test.rs @@ -8,22 +8,19 @@ struct TestFactors { wasi: WasiFactor, } -fn test_env() -> TestEnvironment { - TestEnvironment::default_manifest_extend(toml! { - [component.test-component] - source = "does-not-exist.wasm" - environment = { FOO = "bar" } - }) -} - #[tokio::test] async fn environment_works() -> anyhow::Result<()> { let factors = TestFactors { wasi: WasiFactor::new(DummyFilesMounter), }; - let env = test_env(); - let mut state = env.build_instance_state(factors, ()).await?; + let env = TestEnvironment::new(factors).extend_manifest(toml! { + [component.test-component] + source = "does-not-exist.wasm" + environment = { FOO = "bar" } + }); + let mut state = env.build_instance_state().await?; let mut wasi = WasiFactor::get_wasi_impl(&mut state).unwrap(); + let val = wasi .get_environment()? .into_iter() diff --git a/crates/factors-derive/src/lib.rs b/crates/factors-derive/src/lib.rs index 5b2d38568..80b750d46 100644 --- a/crates/factors-derive/src/lib.rs +++ b/crates/factors-derive/src/lib.rs @@ -112,7 +112,7 @@ fn expand_factors(input: &DeriveInput) -> syn::Result { fn configure_app( &self, app: #factors_path::App, - mut runtime_config: Self::RuntimeConfig, + runtime_config: Self::RuntimeConfig, ) -> #Result<#ConfiguredApp> { let mut app_state = #app_state_name { #( #factor_names: None, )* @@ -124,7 +124,7 @@ fn expand_factors(input: &DeriveInput) -> syn::Result { #factors_path::ConfigureAppContext::::new( &app, &app_state, - &mut runtime_config, + runtime_config.#factor_names, )?, ).map_err(#Error::factor_configure_app_error::<#factor_types>)? ); @@ -245,6 +245,7 @@ fn expand_factors(input: &DeriveInput) -> syn::Result { } } + #[derive(Default)] #vis struct #runtime_config_name { #( pub #factor_names: Option<<#factor_types as #Factor>::RuntimeConfig>, @@ -253,6 +254,7 @@ fn expand_factors(input: &DeriveInput) -> syn::Result { impl #runtime_config_name { /// Get the runtime configuration from the given source. + #[allow(dead_code)] pub fn from_source(mut source: T) -> anyhow::Result where T: #(#factors_path::FactorRuntimeConfigSource<#factor_types> +)* #factors_path::RuntimeConfigSourceFinalizer { @@ -267,24 +269,5 @@ fn expand_factors(input: &DeriveInput) -> syn::Result { }) } } - - impl From<()> for #runtime_config_name { - fn from(_: ()) -> Self { - #runtime_config_name { - #( - #factor_names: None, - )* - } - } - } - - #( - impl #factors_path::FactorRuntimeConfigSource<#factor_types> for #runtime_config_name { - fn get_runtime_config(&mut self) -> anyhow::Result::RuntimeConfig>> { - Ok(self.#factor_names.take()) - } - } - )* - }) } diff --git a/crates/factors-test/src/lib.rs b/crates/factors-test/src/lib.rs index 13437b0d4..344153fbe 100644 --- a/crates/factors-test/src/lib.rs +++ b/crates/factors-test/src/lib.rs @@ -9,13 +9,26 @@ use spin_loader::FilesMountStrategy; pub use toml::toml; /// A test environment for building [`RuntimeFactors`] instances. -pub struct TestEnvironment { +pub struct TestEnvironment { + /// The RuntimeFactors under test. + pub factors: T, /// The `spin.toml` manifest. pub manifest: toml::Table, + /// Runtime configuration for the factors. + pub runtime_config: T::RuntimeConfig, } -impl Default for TestEnvironment { - fn default() -> Self { +impl TestEnvironment { + /// Creates a new test environment by initializing the given + /// [`RuntimeFactors`]. + pub fn new(mut factors: T) -> Self { + let engine = Engine::new(Config::new().async_support(true)) + .expect("wasmtime engine failed to initialize"); + let mut linker = Linker::::new(&engine); + factors + .init(&mut linker) + .expect("RuntimeFactors::init failed"); + let manifest = toml! { spin_manifest_version = 2 @@ -27,60 +40,54 @@ impl Default for TestEnvironment { [component.empty] source = "does-not-exist.wasm" }; - Self { manifest } + Self { + factors, + manifest, + runtime_config: Default::default(), + } } -} -impl TestEnvironment { - /// Builds a TestEnvironment by extending a default manifest with the given - /// manifest TOML. + /// Extends the manifest with the given TOML. /// /// The default manifest includes boilerplate like the /// `spin_manifest_version` and `[application]` section, so you typically /// need to pass only a `[component.test-component]` section. - pub fn default_manifest_extend(manifest_merge: toml::Table) -> Self { - let mut env = Self::default(); - env.manifest.extend(manifest_merge); - env + pub fn extend_manifest(mut self, manifest_merge: toml::Table) -> Self { + self.manifest.extend(manifest_merge); + self } - /// Starting from a new _uninitialized_ [`RuntimeFactors`], run through the - /// [`Factor`]s' lifecycle(s) to build a [`RuntimeFactors::InstanceState`] - /// for the last component defined in the manifest. - pub async fn build_instance_state<'a, T, C, E>( - &'a self, - mut factors: T, - runtime_config: C, - ) -> anyhow::Result + /// Sets the runtime config. + pub fn runtime_config(mut self, runtime_config: C) -> anyhow::Result where - T: RuntimeFactors, C: TryInto, E: Into, { - let mut linker = Self::new_linker::(); - factors.init(&mut linker)?; + self.runtime_config = runtime_config + .try_into() + .map_err(Into::into) + .context("failed to build runtime config")?; + Ok(self) + } + /// Run through the [`Factor`]s' lifecycle(s) to build a + /// [`RuntimeFactors::InstanceState`] for the last component defined in the + /// manifest. + pub async fn build_instance_state(self) -> anyhow::Result { let locked_app = self .build_locked_app() .await .context("failed to build locked app")?; let app = App::new("test-app", locked_app); - let configured_app = - factors.configure_app(app, runtime_config.try_into().map_err(|e| e.into())?)?; + let configured_app = self.factors.configure_app(app, self.runtime_config)?; let component = configured_app.app().components().last().context( "expected configured app to have at least one component, but it did not", )?; - let builders = factors.prepare(&configured_app, component.id())?; + let builders = self.factors.prepare(&configured_app, component.id())?; - Ok(factors.build_instance_state(builders)?) - } - - pub fn new_linker() -> Linker { - let engine = Engine::new(Config::new().async_support(true)) - .expect("wasmtime engine failed to initialize"); - Linker::::new(&engine) + Ok(self.factors.build_instance_state(builders)?) } pub async fn build_locked_app(&self) -> anyhow::Result { diff --git a/crates/factors/src/factor.rs b/crates/factors/src/factor.rs index 39be75e59..06e8a996d 100644 --- a/crates/factors/src/factor.rs +++ b/crates/factors/src/factor.rs @@ -3,8 +3,7 @@ use std::any::Any; use wasmtime::component::{Linker, ResourceTable}; use crate::{ - prepare::FactorInstanceBuilder, runtime_config::FactorRuntimeConfigSource, App, Error, - InstanceBuilders, PrepareContext, RuntimeFactors, + prepare::FactorInstanceBuilder, App, Error, InstanceBuilders, PrepareContext, RuntimeFactors, }; /// A contained (i.e., "factored") piece of runtime functionality. @@ -137,14 +136,11 @@ pub struct ConfigureAppContext<'a, T: RuntimeFactors, F: Factor> { impl<'a, T: RuntimeFactors, F: Factor> ConfigureAppContext<'a, T, F> { #[doc(hidden)] - pub fn new>( + pub fn new( app: &'a App, app_state: &'a T::AppState, - runtime_config: &mut S, + runtime_config: Option, ) -> crate::Result { - let runtime_config = runtime_config - .get_runtime_config() - .map_err(Error::factor_configure_app_error::)?; Ok(Self { app, app_state, diff --git a/crates/factors/src/runtime_factors.rs b/crates/factors/src/runtime_factors.rs index 124005d32..a0ff6dd68 100644 --- a/crates/factors/src/runtime_factors.rs +++ b/crates/factors/src/runtime_factors.rs @@ -38,7 +38,7 @@ pub trait RuntimeFactors: Sized + 'static { /// The collection of all the `InstanceBuilder`s of the factors. type InstanceBuilders; /// The runtime configuration of all the factors. - type RuntimeConfig; + type RuntimeConfig: Default; /// Initialize the factors with the given linker. ///