Skip to content

Commit ddb3bbc

Browse files
committed
refactor: test & function rename + improved readability
Signed-off-by: Aminu Oluwaseun Joshua <[email protected]>
1 parent 9c7c742 commit ddb3bbc

File tree

5 files changed

+77
-55
lines changed

5 files changed

+77
-55
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/expressions/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,5 @@ spin-locked-app = { path = "../locked-app" }
1212
thiserror = { workspace = true }
1313

1414
[dev-dependencies]
15-
spin-world = { path = "../world" }
1615
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
1716
toml = { workspace = true }

crates/expressions/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ impl ProviderResolver {
9292
Ok(PreparedResolver { variables })
9393
}
9494

95-
/// Validates `Provider`(s) that are `ProviderVariableKind::Static` provide their variables at startup.
96-
pub async fn validate_variables(&self) -> Result<()> {
95+
/// Ensures that all required variables are resolvable at startup
96+
pub async fn ensure_required_variables_resolved(&self) -> Result<()> {
9797
// If a dynamic provider is available, skip validation.
9898
if self
9999
.providers

crates/expressions/tests/validation_test.rs

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
22

3+
use async_trait::async_trait;
34
use spin_expressions::{provider::ProviderVariableKind, Key, Provider, ProviderResolver};
45
use spin_locked_app::Variable;
56

@@ -14,18 +15,12 @@ impl ResolverTester {
1415
Self::default()
1516
}
1617

17-
fn with_dynamic_provider(mut self) -> Self {
18-
self.providers.push(Box::new(DynamicProvider));
18+
fn with_provider(mut self, provider: impl Provider + 'static) -> Self {
19+
self.providers.push(Box::new(provider));
1920
self
2021
}
2122

22-
fn with_static_provider(mut self, key: &str, value: Option<&str>) -> Self {
23-
self.providers
24-
.push(Box::new(StaticProvider::with_variable(key, value)));
25-
self
26-
}
27-
28-
fn with_variable(mut self, (key, default): (&str, Option<&str>)) -> Self {
23+
fn with_variable(mut self, key: &str, default: Option<&str>) -> Self {
2924
self.variables.insert(
3025
key.to_string(),
3126
Variable {
@@ -41,32 +36,33 @@ impl ResolverTester {
4136
let mut provider_resolver = ProviderResolver::new(self.variables)?;
4237

4338
for provider in self.providers {
44-
provider_resolver.add_provider(provider as _);
39+
provider_resolver.add_provider(provider);
4540
}
4641

4742
Ok(provider_resolver)
4843
}
4944
}
5045

5146
#[tokio::test(flavor = "multi_thread")]
52-
async fn single_static_provider_with_no_variable_provided_is_valid() -> anyhow::Result<()> {
47+
async fn if_single_static_provider_with_no_key_to_resolve_is_valid() -> anyhow::Result<()> {
5348
let resolver = ResolverTester::new()
54-
.with_static_provider("foo", Some("bar"))
49+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
5550
.make_resolver()?;
5651

57-
resolver.validate_variables().await?;
52+
resolver.ensure_required_variables_resolved().await?;
5853

5954
Ok(())
6055
}
6156

6257
#[tokio::test(flavor = "multi_thread")]
63-
async fn if_single_static_provider_has_variable_value_validation_succeeds() -> anyhow::Result<()> {
58+
async fn if_single_static_provider_has_data_for_variable_key_to_resolve_it_succeeds(
59+
) -> anyhow::Result<()> {
6460
let resolver = ResolverTester::new()
65-
.with_static_provider("foo", Some("bar"))
66-
.with_variable(("foo", None))
61+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
62+
.with_variable("foo", None)
6763
.make_resolver()?;
6864

69-
resolver.validate_variables().await?;
65+
resolver.ensure_required_variables_resolved().await?;
7066

7167
Ok(())
7268
}
@@ -75,38 +71,38 @@ async fn if_single_static_provider_has_variable_value_validation_succeeds() -> a
7571
async fn if_there_is_a_single_static_provider_and_it_does_not_contain_a_required_variable_then_validation_fails(
7672
) -> anyhow::Result<()> {
7773
let resolver = ResolverTester::new()
78-
.with_static_provider("foo", Some("bar"))
79-
.with_variable(("bar", None))
74+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
75+
.with_variable("bar", None)
8076
.make_resolver()?;
8177

82-
assert!(resolver.validate_variables().await.is_err());
78+
assert!(resolver.ensure_required_variables_resolved().await.is_err());
8379

8480
Ok(())
8581
}
8682

8783
#[tokio::test(flavor = "multi_thread")]
88-
async fn if_there_is_a_dynamic_provider_then_validation_succeeds_even_if_a_static_provider_without_the_variable_is_in_play(
84+
async fn if_there_is_a_dynamic_provider_then_validation_succeeds_even_without_default_value_in_play(
8985
) -> anyhow::Result<()> {
9086
let resolver = ResolverTester::new()
91-
.with_dynamic_provider()
92-
.with_variable(("bar", None))
87+
.with_provider(DynamicProvider)
88+
.with_variable("bar", None)
9389
.make_resolver()?;
9490

95-
resolver.validate_variables().await?;
91+
resolver.ensure_required_variables_resolved().await?;
9692

9793
Ok(())
9894
}
9995

10096
#[tokio::test(flavor = "multi_thread")]
101-
async fn if_there_is_a_dynamic_provider_and_a_static_provider_then_validation_succeeds_even_if_a_static_provider_without_the_variable_is_in_play(
97+
async fn if_there_is_a_dynamic_provider_and_static_provider_but_the_variable_to_be_resolved_is_not_in_play(
10298
) -> anyhow::Result<()> {
10399
let resolver = ResolverTester::new()
104-
.with_dynamic_provider()
105-
.with_static_provider("foo", Some("bar"))
106-
.with_variable(("baz", None))
100+
.with_provider(DynamicProvider)
101+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
102+
.with_variable("baz", None)
107103
.make_resolver()?;
108104

109-
resolver.validate_variables().await?;
105+
resolver.ensure_required_variables_resolved().await?;
110106

111107
Ok(())
112108
}
@@ -115,52 +111,78 @@ async fn if_there_is_a_dynamic_provider_and_a_static_provider_then_validation_su
115111
async fn if_there_is_a_dynamic_provider_and_a_static_provider_then_validation_succeeds_even_if_a_static_provider_with_the_variable_is_in_play(
116112
) -> anyhow::Result<()> {
117113
let resolver = ResolverTester::new()
118-
.with_dynamic_provider()
119-
.with_static_provider("foo", Some("bar"))
120-
.with_variable(("baz", Some("coo")))
114+
.with_provider(DynamicProvider)
115+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
116+
.with_variable("baz", Some("coo"))
121117
.make_resolver()?;
122118

123-
resolver.validate_variables().await?;
119+
resolver.ensure_required_variables_resolved().await?;
124120

125121
Ok(())
126122
}
127123

128124
#[tokio::test(flavor = "multi_thread")]
129-
async fn if_there_is_two_static_providers_where_one_has_data_is_valid() -> anyhow::Result<()> {
125+
async fn if_there_are_two_static_providers_where_one_has_data_is_valid() -> anyhow::Result<()> {
130126
let resolver = ResolverTester::new()
131-
.with_static_provider("foo", Some("bar"))
132-
.with_static_provider("baz", Some("hay"))
133-
.with_variable(("foo", None))
127+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
128+
.with_provider(StaticProvider::with_variable("baz", Some("hay")))
129+
.with_variable("foo", None)
134130
.make_resolver()?;
135131

136-
resolver.validate_variables().await?;
132+
resolver.ensure_required_variables_resolved().await?;
137133

138134
Ok(())
139135
}
140-
136+
// This is a bit of an edge case, but we want to ensure that if there are two or more static providers
137+
// and the first one does not have data for the variable to be resolved, but the second or subsequent one does,
138+
// then validation still succeeds.
141139
#[tokio::test(flavor = "multi_thread")]
142-
async fn if_there_is_two_static_providers_where_first_provider_does_not_have_data_while_second_provider_does(
140+
async fn if_there_are_two_static_providers_where_first_provider_does_not_have_data_while_second_provider_does(
143141
) -> anyhow::Result<()> {
144142
let resolver = ResolverTester::new()
145-
.with_static_provider("foo", Some("bar"))
146-
.with_static_provider("baz", Some("hay"))
147-
.with_variable(("baz", None))
143+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
144+
.with_provider(StaticProvider::with_variable("baz", Some("hay")))
145+
.with_variable("baz", None)
148146
.make_resolver()?;
149147

150-
resolver.validate_variables().await?;
148+
resolver.ensure_required_variables_resolved().await?;
151149

152150
Ok(())
153151
}
154152

155153
#[tokio::test(flavor = "multi_thread")]
156154
async fn if_there_is_two_static_providers_neither_having_data_is_invalid() -> anyhow::Result<()> {
157155
let resolver = ResolverTester::new()
158-
.with_static_provider("foo", Some("bar"))
159-
.with_static_provider("baz", Some("hay"))
160-
.with_variable(("hello", None))
156+
.with_provider(StaticProvider::with_variable("foo", Some("bar")))
157+
.with_provider(StaticProvider::with_variable("baz", Some("hay")))
158+
.with_variable("hello", None)
159+
.make_resolver()?;
160+
161+
assert!(resolver.ensure_required_variables_resolved().await.is_err());
162+
163+
Ok(())
164+
}
165+
166+
#[tokio::test(flavor = "multi_thread")]
167+
async fn no_provider_data_available_but_variable_default_value_needed_is_invalid(
168+
) -> anyhow::Result<()> {
169+
let resolver = ResolverTester::new()
170+
.with_variable("hello", None)
171+
.make_resolver()?;
172+
173+
assert!(resolver.ensure_required_variables_resolved().await.is_err());
174+
175+
Ok(())
176+
}
177+
178+
#[tokio::test(flavor = "multi_thread")]
179+
async fn no_provider_data_available_but_variable_has_default_value_needed_is_valid(
180+
) -> anyhow::Result<()> {
181+
let resolver = ResolverTester::new()
182+
.with_variable("hello", Some("World"))
161183
.make_resolver()?;
162184

163-
assert!(resolver.validate_variables().await.is_err());
185+
resolver.ensure_required_variables_resolved().await?;
164186

165187
Ok(())
166188
}
@@ -178,7 +200,7 @@ impl StaticProvider {
178200
}
179201
}
180202

181-
#[spin_world::async_trait]
203+
#[async_trait]
182204
impl Provider for StaticProvider {
183205
async fn get(&self, key: &Key) -> anyhow::Result<Option<String>> {
184206
Ok(self.variables.get(key.as_str()).cloned().flatten())
@@ -192,7 +214,7 @@ impl Provider for StaticProvider {
192214
#[derive(Debug)]
193215
struct DynamicProvider;
194216

195-
#[spin_world::async_trait]
217+
#[async_trait]
196218
impl Provider for DynamicProvider {
197219
async fn get(&self, _key: &Key) -> anyhow::Result<Option<String>> {
198220
panic!("validation should never call get for a dynamic provider")

crates/trigger/src/cli/variable.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for VariablesValidatorHook {
1414
let variables_factor_app_state = configured_app.app_state::<VariablesFactor>()?;
1515

1616
let expression_resolver = variables_factor_app_state.expression_resolver();
17-
expression_resolver.validate_variables().await?;
17+
expression_resolver
18+
.ensure_required_variables_resolved()
19+
.await?;
1820

1921
Ok(())
2022
}

0 commit comments

Comments
 (0)