Skip to content

Commit 449ad5a

Browse files
committed
Rework tests
Signed-off-by: Ryan Levick <[email protected]>
1 parent 708b63d commit 449ad5a

File tree

6 files changed

+103
-200
lines changed

6 files changed

+103
-200
lines changed

crates/factor-key-value/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ tracing = { workspace = true }
1919

2020
[dev-dependencies]
2121
spin-factors-test = { path = "../factors-test" }
22-
spin-key-value-redis = { path = "../key-value-redis" }
2322
spin-key-value-spin = { path = "../key-value-spin" }
23+
spin-key-value-redis = { path = "../key-value-redis" }
2424
tempfile = "3.12.0"
2525
tokio = { version = "1", features = ["macros", "rt"] }
2626

crates/factor-key-value/src/runtime_config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ impl RuntimeConfig {
1818
pub fn add_store_manager(&mut self, label: String, store_manager: Arc<dyn StoreManager>) {
1919
self.store_managers.insert(label, store_manager);
2020
}
21+
22+
/// Returns whether a store manager exists for the store with the given label.
23+
pub fn has_store_manager(&self, label: &str) -> bool {
24+
self.store_managers.contains_key(label)
25+
}
2126
}
2227

2328
impl IntoIterator for RuntimeConfig {

crates/factor-key-value/src/runtime_config/spin.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,23 @@ impl RuntimeConfigResolver {
100100
/// Resolves a toml table into a runtime config.
101101
///
102102
/// The default stores are also added to the runtime config.
103-
pub fn resolve_from_toml(
103+
pub fn resolve(&self, table: Option<&impl GetTomlValue>) -> anyhow::Result<RuntimeConfig> {
104+
let mut runtime_config = self.resolve_from_toml(table)?.unwrap_or_default();
105+
106+
for (&label, config) in &self.defaults {
107+
if !runtime_config.store_managers.contains_key(label) {
108+
let store_manager = self
109+
.store_manager_from_config(config.clone())
110+
.with_context(|| {
111+
format!("could not configure key-value store with label '{label}'")
112+
})?;
113+
runtime_config.add_store_manager(label.to_owned(), store_manager);
114+
}
115+
}
116+
Ok(runtime_config)
117+
}
118+
119+
fn resolve_from_toml(
104120
&self,
105121
table: Option<&impl GetTomlValue>,
106122
) -> anyhow::Result<Option<RuntimeConfig>> {
@@ -117,16 +133,6 @@ impl RuntimeConfigResolver {
117133
runtime_config.add_store_manager(label.clone(), store_manager);
118134
}
119135

120-
for (&label, config) in &self.defaults {
121-
if !runtime_config.store_managers.contains_key(label) {
122-
let store_manager = self
123-
.store_manager_from_config(config.clone())
124-
.with_context(|| {
125-
format!("could not configure key-value store with label '{label}'")
126-
})?;
127-
runtime_config.add_store_manager(label.to_owned(), store_manager);
128-
}
129-
}
130136
Ok(Some(runtime_config))
131137
}
132138

crates/factor-key-value/tests/factor_test.rs

Lines changed: 0 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -141,159 +141,3 @@ impl Store for MockStore {
141141
todo!()
142142
}
143143
}
144-
145-
// async fn run_test_with_config_and_stores_for_label(
146-
// runtime_config: Option<toml::Table>,
147-
// store_types: Vec<impl MakeKeyValueStore>,
148-
// labels: Vec<&str>,
149-
// ) -> anyhow::Result<TestFactorsInstanceState> {
150-
// let mut test_resolver = RuntimeConfigResolver::new();
151-
// for store_type in store_types {
152-
// test_resolver.register_store_type(store_type)?;
153-
// }
154-
// let test_resolver = Arc::new(test_resolver);
155-
// let factors = TestFactors {
156-
// key_value: KeyValueFactor::new(),
157-
// };
158-
// let labels_clone = labels.clone();
159-
// let env = TestEnvironment::new(factors)
160-
// .extend_manifest(toml! {
161-
// [component.test-component]
162-
// source = "does-not-exist.wasm"
163-
// key_value_stores = labels_clone
164-
// })
165-
// .runtime_config(TomlConfig::new(test_resolver, runtime_config))?;
166-
// let state = env.build_instance_state().await?;
167-
// assert_eq!(
168-
// labels,
169-
// state.key_value.allowed_stores().iter().collect::<Vec<_>>()
170-
// );
171-
172-
// Ok(state)
173-
// }
174-
175-
// #[tokio::test]
176-
// async fn overridden_default_key_value_works() -> anyhow::Result<()> {
177-
// let runtime_config = toml::toml! {
178-
// [key_value_store.default]
179-
// type = "redis"
180-
// url = "redis://localhost:6379"
181-
// };
182-
// run_test_with_config_and_stores_for_label(
183-
// Some(runtime_config),
184-
// vec![RedisKeyValueStore::new()],
185-
// vec!["default"],
186-
// )
187-
// .await?;
188-
// Ok(())
189-
// }
190-
191-
// #[tokio::test]
192-
// async fn custom_spin_key_value_works() -> anyhow::Result<()> {
193-
// let runtime_config = toml::toml! {
194-
// [key_value_store.custom]
195-
// type = "spin"
196-
// };
197-
// run_test_with_config_and_stores_for_label(
198-
// Some(runtime_config),
199-
// vec![SpinKeyValueStore::new(None)],
200-
// vec!["custom"],
201-
// )
202-
// .await?;
203-
// Ok(())
204-
// }
205-
206-
// #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
207-
// async fn custom_spin_key_value_works_with_absolute_path() -> anyhow::Result<()> {
208-
// let tmp_dir = tempfile::TempDir::with_prefix("example")?;
209-
// let db_path = tmp_dir.path().join("foo/custom.db");
210-
// // Check that the db does not exist yet - it will exist by the end of the test
211-
// assert!(!db_path.exists());
212-
213-
// let path_str = db_path.to_str().unwrap();
214-
// let runtime_config = toml::toml! {
215-
// [key_value_store.custom]
216-
// type = "spin"
217-
// path = path_str
218-
// };
219-
// let mut state = run_test_with_config_and_stores_for_label(
220-
// Some(runtime_config),
221-
// vec![SpinKeyValueStore::new(Some(
222-
// std::env::current_dir().context("failed to get current directory")?,
223-
// ))],
224-
// vec!["custom"],
225-
// )
226-
// .await?;
227-
228-
// // Actually et a key since store creation is lazy
229-
// let store = state.key_value.open("custom".to_owned()).await??;
230-
// let _ = state.key_value.get(store, "foo".to_owned()).await??;
231-
232-
// // Check that the parent has been created
233-
// assert!(db_path.exists());
234-
// Ok(())
235-
// }
236-
237-
// #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
238-
// async fn custom_spin_key_value_works_with_relative_path() -> anyhow::Result<()> {
239-
// let tmp_dir = tempfile::TempDir::with_prefix("example")?;
240-
// let db_path = tmp_dir.path().join("custom.db");
241-
// // Check that the db does not exist yet - it will exist by the end of the test
242-
// assert!(!db_path.exists());
243-
244-
// let runtime_config = toml::toml! {
245-
// [key_value_store.custom]
246-
// type = "spin"
247-
// path = "custom.db"
248-
// };
249-
// let mut state = run_test_with_config_and_stores_for_label(
250-
// Some(runtime_config),
251-
// vec![SpinKeyValueStore::new(Some(tmp_dir.path().to_owned()))],
252-
// vec!["custom"],
253-
// )
254-
// .await?;
255-
256-
// // Actually et a key since store creation is lazy
257-
// let store = state.key_value.open("custom".to_owned()).await??;
258-
// let _ = state.key_value.get(store, "foo".to_owned()).await??;
259-
260-
// // Check that the correct store in the config was chosen by verifying the existence of the DB
261-
// assert!(db_path.exists());
262-
// Ok(())
263-
// }
264-
265-
// #[tokio::test]
266-
// async fn custom_redis_key_value_works() -> anyhow::Result<()> {
267-
// let runtime_config = toml::toml! {
268-
// [key_value_store.custom]
269-
// type = "redis"
270-
// url = "redis://localhost:6379"
271-
// };
272-
// run_test_with_config_and_stores_for_label(
273-
// Some(runtime_config),
274-
// vec![RedisKeyValueStore::new()],
275-
// vec!["custom"],
276-
// )
277-
// .await?;
278-
// Ok(())
279-
// }
280-
281-
// #[tokio::test]
282-
// async fn misconfigured_spin_key_value_fails() -> anyhow::Result<()> {
283-
// let tmp_dir = tempfile::TempDir::with_prefix("example")?;
284-
// let runtime_config = toml::toml! {
285-
// [key_value_store.custom]
286-
// type = "spin"
287-
// path = "/$$&/bad/path/foo.db"
288-
// };
289-
// let result = run_test_with_config_and_stores_for_label(
290-
// Some(runtime_config),
291-
// vec![SpinKeyValueStore::new(Some(tmp_dir.path().to_owned()))],
292-
// vec!["custom"],
293-
// )
294-
// .await;
295-
// // TODO(rylev): This only fails on my machine due to a read-only file system error.
296-
// // We should consider adding a check for the error message.
297-
// assert!(result.is_err());
298-
// Ok(())
299-
// }

crates/runtime-config/src/lib.rs

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ impl FactorRuntimeConfigSource<KeyValueFactor> for TomlRuntimeConfigSource<'_, '
300300
fn get_runtime_config(
301301
&mut self,
302302
) -> anyhow::Result<Option<spin_factor_key_value::RuntimeConfig>> {
303-
self.key_value.resolve_from_toml(Some(&self.toml.table))
303+
Ok(Some(self.key_value.resolve(Some(&self.toml.table))?))
304304
}
305305
}
306306

@@ -368,7 +368,7 @@ impl FactorRuntimeConfigSource<OutboundMqttFactor> for TomlRuntimeConfigSource<'
368368

369369
impl FactorRuntimeConfigSource<SqliteFactor> for TomlRuntimeConfigSource<'_, '_> {
370370
fn get_runtime_config(&mut self) -> anyhow::Result<Option<spin_factor_sqlite::RuntimeConfig>> {
371-
self.sqlite.resolve_from_toml(&self.toml.table)
371+
Ok(Some(self.sqlite.resolve(&self.toml.table)?))
372372
}
373373
}
374374

@@ -438,32 +438,53 @@ fn sqlite_config_resolver(
438438

439439
#[cfg(test)]
440440
mod tests {
441+
use std::{collections::HashMap, sync::Arc};
442+
441443
use spin_factors::RuntimeFactors;
442444

443445
use super::*;
444446

447+
/// Define a test factor with the given field and factor type.
448+
macro_rules! define_test_factor {
449+
($field:ident : $factor:ty) => {
450+
#[derive(RuntimeFactors)]
451+
struct TestFactors {
452+
$field: $factor,
453+
}
454+
impl TryFrom<TomlRuntimeConfigSource<'_, '_>> for TestFactorsRuntimeConfig {
455+
type Error = anyhow::Error;
456+
457+
fn try_from(value: TomlRuntimeConfigSource<'_, '_>) -> Result<Self, Self::Error> {
458+
Self::from_source(value)
459+
}
460+
}
461+
fn resolve_toml(toml: toml::Table) -> ResolvedRuntimeConfig<TestFactorsRuntimeConfig> {
462+
ResolvedRuntimeConfig::<TestFactorsRuntimeConfig>::new(
463+
toml_resolver(&toml),
464+
None,
465+
false,
466+
)
467+
.unwrap()
468+
}
469+
};
470+
}
471+
445472
#[test]
446473
fn sqlite_is_configured_correctly() {
447-
#[derive(RuntimeFactors)]
448-
struct Factors {
449-
sqlite: SqliteFactor,
450-
}
451-
impl TryFrom<TomlRuntimeConfigSource<'_, '_>> for FactorsRuntimeConfig {
452-
type Error = anyhow::Error;
453-
454-
fn try_from(value: TomlRuntimeConfigSource<'_, '_>) -> Result<Self, Self::Error> {
455-
Self::from_source(value)
474+
define_test_factor!(sqlite: SqliteFactor);
475+
476+
impl TestFactorsRuntimeConfig {
477+
/// Get the connection creators for the configured sqlite databases.
478+
fn connection_creators(
479+
&self,
480+
) -> &HashMap<String, Arc<dyn spin_factor_sqlite::ConnectionCreator>> {
481+
&self.sqlite.as_ref().unwrap().connection_creators
456482
}
457-
}
458483

459-
impl FactorsRuntimeConfig {
460484
/// Get the labels of the configured sqlite databases.
461485
fn configured_labels(&self) -> Vec<&str> {
462486
let mut configured_labels = self
463-
.sqlite
464-
.as_ref()
465-
.unwrap()
466-
.connection_creators
487+
.connection_creators()
467488
.keys()
468489
.map(|s| s.as_str())
469490
.collect::<Vec<_>>();
@@ -478,20 +499,36 @@ mod tests {
478499
[sqlite_database.foo]
479500
type = "spin"
480501
};
481-
let config =
482-
ResolvedRuntimeConfig::<FactorsRuntimeConfig>::new(toml_resolver(&toml), None, false)
483-
.unwrap();
484502
assert_eq!(
485-
config.runtime_config.configured_labels(),
503+
resolve_toml(toml).runtime_config.configured_labels(),
486504
vec!["default", "foo"]
487505
);
488506

489507
// Test that the default label is added with an empty toml config.
490508
let toml = toml::Table::new();
491-
let config =
492-
ResolvedRuntimeConfig::<FactorsRuntimeConfig>::new(toml_resolver(&toml), None, false)
493-
.unwrap();
494-
assert_eq!(config.runtime_config.configured_labels(), vec!["default"]);
509+
let runtime_config = resolve_toml(toml).runtime_config;
510+
assert_eq!(runtime_config.configured_labels(), vec!["default"]);
511+
}
512+
513+
#[test]
514+
fn key_value_is_configured_correctly() {
515+
define_test_factor!(key_value: KeyValueFactor);
516+
impl TestFactorsRuntimeConfig {
517+
/// Get whether the store manager exists for the given label.
518+
fn has_store_manager(&self, label: &str) -> bool {
519+
self.key_value.as_ref().unwrap().has_store_manager(label)
520+
}
521+
}
522+
523+
// Test that the default label is added if not provided.
524+
let toml = toml::toml! {
525+
[key_value_store.foo]
526+
type = "spin"
527+
};
528+
let runtime_config = resolve_toml(toml).runtime_config;
529+
assert!(["default", "foo"]
530+
.iter()
531+
.all(|label| { runtime_config.has_store_manager(label) }));
495532
}
496533

497534
fn toml_resolver(toml: &toml::Table) -> TomlResolver<'_> {

crates/sqlite/src/lib.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,23 @@ impl RuntimeConfigResolver {
5252
/// ```
5353
///
5454
/// Configuration is automatically added for the 'default' label if it is not provided.
55-
pub fn resolve_from_toml(
55+
pub fn resolve(
56+
&self,
57+
table: &impl GetTomlValue,
58+
) -> anyhow::Result<spin_factor_sqlite::runtime_config::RuntimeConfig> {
59+
let mut runtime_config = self.resolve_from_toml(table)?.unwrap_or_default();
60+
// If the user did not provide configuration for the default label, add it.
61+
if !runtime_config.connection_creators.contains_key("default") {
62+
runtime_config
63+
.connection_creators
64+
.insert("default".to_owned(), self.default());
65+
}
66+
67+
Ok(runtime_config)
68+
}
69+
70+
/// Get the runtime configuration for SQLite databases from a TOML table.
71+
fn resolve_from_toml(
5672
&self,
5773
table: &impl GetTomlValue,
5874
) -> anyhow::Result<Option<spin_factor_sqlite::runtime_config::RuntimeConfig>> {
@@ -61,16 +77,11 @@ impl RuntimeConfigResolver {
6177
};
6278
let config: std::collections::HashMap<String, TomlRuntimeConfig> =
6379
table.clone().try_into()?;
64-
let mut connection_creators = config
80+
let connection_creators = config
6581
.into_iter()
6682
.map(|(k, v)| Ok((k, self.get_connection_creator(v)?)))
6783
.collect::<anyhow::Result<HashMap<_, _>>>()?;
6884

69-
// If the user did not provide configuration for the default label, add it.
70-
if connection_creators.contains_key("default") {
71-
connection_creators.insert("default".to_owned(), self.default());
72-
}
73-
7485
Ok(Some(spin_factor_sqlite::runtime_config::RuntimeConfig {
7586
connection_creators,
7687
}))

0 commit comments

Comments
 (0)