Skip to content

Commit 7e7ee09

Browse files
committed
more tests against validation logic
Signed-off-by: Aminu Oluwaseun Joshua <[email protected]>
1 parent 44988ff commit 7e7ee09

File tree

4 files changed

+262
-122
lines changed

4 files changed

+262
-122
lines changed

Cargo.lock

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

crates/expressions/Cargo.toml

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

1414
[dev-dependencies]
15+
spin-world = { path = "../world" }
1516
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
1617
toml = { workspace = true }
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
use spin_expressions::{provider::ProviderVariableKind, Key, Provider, ProviderResolver};
2+
use spin_locked_app::Variable;
3+
4+
fn initialize_provider_resolver(
5+
variable_key: Option<String>,
6+
default: Option<String>,
7+
providers: Vec<Box<dyn Provider>>,
8+
) -> anyhow::Result<ProviderResolver> {
9+
let mut provider_resolver = ProviderResolver::new(if let Some(key) = variable_key {
10+
vec![(
11+
key.to_string(),
12+
Variable {
13+
description: None,
14+
default,
15+
secret: false,
16+
},
17+
)]
18+
} else {
19+
vec![]
20+
})?;
21+
22+
for provider in providers {
23+
provider_resolver.add_provider(provider as _);
24+
}
25+
26+
Ok(provider_resolver)
27+
}
28+
29+
struct StaticProvider {
30+
resolver: ProviderResolver,
31+
}
32+
33+
impl StaticProvider {
34+
fn with_variables(
35+
variable_key: Option<String>,
36+
default: Option<String>,
37+
other_providers: Option<Box<dyn Provider>>,
38+
) -> Self {
39+
let resolver = initialize_provider_resolver(
40+
variable_key,
41+
default,
42+
if other_providers.is_some() {
43+
vec![Box::new(StaticMockProvider), other_providers.unwrap()]
44+
} else {
45+
vec![Box::new(StaticMockProvider)]
46+
},
47+
)
48+
.unwrap();
49+
50+
Self { resolver }
51+
}
52+
}
53+
54+
struct DynamicProvider {
55+
resolver: ProviderResolver,
56+
}
57+
58+
impl DynamicProvider {
59+
fn with_variables(
60+
variable_key: Option<String>,
61+
default: Option<String>,
62+
other_providers: Option<Box<dyn Provider>>,
63+
) -> Self {
64+
let resolver = initialize_provider_resolver(
65+
variable_key,
66+
default,
67+
if other_providers.is_some() {
68+
vec![Box::new(DynamicMockProvider), other_providers.unwrap()]
69+
} else {
70+
vec![Box::new(DynamicMockProvider)]
71+
},
72+
)
73+
.unwrap();
74+
75+
Self { resolver }
76+
}
77+
}
78+
79+
#[tokio::test(flavor = "multi_thread")]
80+
async fn single_static_provider_with_no_variable_provided_is_valid() -> anyhow::Result<()> {
81+
let static_provider = StaticProvider::with_variables(None, None, None);
82+
83+
static_provider
84+
.resolver
85+
.validate_variable_existence()
86+
.await?;
87+
88+
Ok(())
89+
}
90+
91+
#[tokio::test(flavor = "multi_thread")]
92+
async fn if_single_static_provider_has_variable_value_validation_succeeds() -> anyhow::Result<()> {
93+
let static_provider = StaticProvider::with_variables(Some("foo".to_string()), None, None);
94+
95+
static_provider
96+
.resolver
97+
.validate_variable_existence()
98+
.await?;
99+
100+
Ok(())
101+
}
102+
103+
#[tokio::test(flavor = "multi_thread")]
104+
async fn if_there_is_a_single_static_provider_and_it_does_not_contain_a_required_variable_then_validation_fails(
105+
) -> anyhow::Result<()> {
106+
let static_provider = StaticProvider::with_variables(Some("bar".to_string()), None, None);
107+
108+
assert!(static_provider
109+
.resolver
110+
.validate_variable_existence()
111+
.await
112+
.is_err());
113+
114+
Ok(())
115+
}
116+
117+
#[tokio::test(flavor = "multi_thread")]
118+
async fn if_there_is_a_dynamic_provider_then_validation_succeeds_even_if_a_static_provider_without_the_variable_is_in_play(
119+
) -> anyhow::Result<()> {
120+
let dynamic_provider = DynamicProvider::with_variables(Some("baz".to_string()), None, None);
121+
122+
dynamic_provider
123+
.resolver
124+
.validate_variable_existence()
125+
.await?;
126+
127+
Ok(())
128+
}
129+
130+
#[tokio::test(flavor = "multi_thread")]
131+
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(
132+
) -> anyhow::Result<()> {
133+
let dynamic_provider = DynamicProvider::with_variables(
134+
Some("baz".to_string()),
135+
None,
136+
Some(Box::new(StaticMockProvider)),
137+
);
138+
139+
dynamic_provider
140+
.resolver
141+
.validate_variable_existence()
142+
.await?;
143+
144+
Ok(())
145+
}
146+
147+
#[tokio::test(flavor = "multi_thread")]
148+
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(
149+
) -> anyhow::Result<()> {
150+
let dynamic_provider = DynamicProvider::with_variables(
151+
Some("baz".to_string()),
152+
Some("foo".to_string()),
153+
Some(Box::new(StaticMockProvider)),
154+
);
155+
156+
dynamic_provider
157+
.resolver
158+
.validate_variable_existence()
159+
.await?;
160+
161+
Ok(())
162+
}
163+
164+
#[tokio::test(flavor = "multi_thread")]
165+
async fn static_provider_with_two_static_providers() -> anyhow::Result<()> {
166+
let static_provider = StaticProvider::with_variables(
167+
Some("bar".to_string()),
168+
Some("hay".to_string()),
169+
Some(Box::new(StaticMockProvider)),
170+
);
171+
172+
static_provider
173+
.resolver
174+
.validate_variable_existence()
175+
.await?;
176+
177+
Ok(())
178+
}
179+
180+
#[tokio::test(flavor = "multi_thread")]
181+
async fn static_provider_with_two_static_providers_where_first_provider_does_not_have_data_while_second_provider_does(
182+
) -> anyhow::Result<()> {
183+
let static_provider = StaticProvider::with_variables(
184+
Some("bar".to_string()),
185+
None,
186+
Some(Box::new(ExtraStaticMockProvider)),
187+
);
188+
189+
static_provider
190+
.resolver
191+
.validate_variable_existence()
192+
.await?;
193+
194+
Ok(())
195+
}
196+
197+
#[tokio::test(flavor = "multi_thread")]
198+
async fn static_provider_with_two_static_providers_neither_has_data() -> anyhow::Result<()> {
199+
let static_provider = StaticProvider::with_variables(
200+
Some("hello".to_string()),
201+
None,
202+
Some(Box::new(ExtraStaticMockProvider)),
203+
);
204+
205+
assert!(static_provider
206+
.resolver
207+
.validate_variable_existence()
208+
.await
209+
.is_err());
210+
211+
Ok(())
212+
}
213+
214+
#[derive(Debug)]
215+
struct StaticMockProvider;
216+
217+
#[spin_world::async_trait]
218+
impl Provider for StaticMockProvider {
219+
async fn get(&self, key: &Key) -> anyhow::Result<Option<String>> {
220+
match key.as_str() {
221+
"foo" => Ok(Some("bar".to_string())),
222+
_ => Ok(None),
223+
}
224+
}
225+
226+
fn kind(&self) -> ProviderVariableKind {
227+
ProviderVariableKind::Static
228+
}
229+
}
230+
231+
#[derive(Debug)]
232+
struct ExtraStaticMockProvider;
233+
234+
#[spin_world::async_trait]
235+
impl Provider for ExtraStaticMockProvider {
236+
async fn get(&self, key: &Key) -> anyhow::Result<Option<String>> {
237+
match key.as_str() {
238+
"bar" => Ok(Some("hey".to_string())),
239+
_ => Ok(None),
240+
}
241+
}
242+
243+
fn kind(&self) -> ProviderVariableKind {
244+
ProviderVariableKind::Static
245+
}
246+
}
247+
248+
#[derive(Debug)]
249+
struct DynamicMockProvider;
250+
251+
#[spin_world::async_trait]
252+
impl Provider for DynamicMockProvider {
253+
async fn get(&self, _key: &Key) -> anyhow::Result<Option<String>> {
254+
Ok(None)
255+
}
256+
257+
fn kind(&self) -> ProviderVariableKind {
258+
ProviderVariableKind::Dynamic
259+
}
260+
}

0 commit comments

Comments
 (0)