Skip to content

Commit 8d199db

Browse files
committed
Initial commit (WIP)
Signed-off-by: Charles d'Avernas <[email protected]>
1 parent 9e984bf commit 8d199db

File tree

16 files changed

+1916
-24
lines changed

16 files changed

+1916
-24
lines changed

.vscode/launch.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Launch",
9+
"type": "cppvsdbg",
10+
"request": "launch",
11+
"program": "${workspaceFolder}/target/debug/${workspaceRootFolderName}.exe",
12+
"args": [],
13+
"stopAtEntry": false,
14+
"cwd": "${workspaceFolder}",
15+
"environment": [],
16+
"externalConsole": true,
17+
"preLaunchTask": "cargo build"
18+
}
19+
]
20+
}

Cargo.lock

Lines changed: 17 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[workspace]
22
members = [
3-
"core"
3+
"core",
4+
"builders"
45
]

builders/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "serverless-workflow-builders"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
serverless_workflow_core = { path = "../core" }

builders/src/lib.rs

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
pub mod services;
2+
3+
#[cfg(test)]
4+
mod unit_tests {
5+
6+
use serverless_workflow_core::models::any::*;
7+
use serverless_workflow_core::models::duration::*;
8+
use serverless_workflow_core::models::error::OneOfErrorDefinitionOrReference;
9+
use crate::services::workflow::WorkflowBuilder;
10+
use serverless_workflow_core::models::task::*;
11+
use serverless_workflow_core::models::timeout::*;
12+
use std::collections::HashMap;
13+
14+
#[test]
15+
fn build_workflow_should_work() {
16+
//arrange
17+
let dsl_version = "1.0.0";
18+
let namespace = "namespace";
19+
let name = "fake-name";
20+
let version = "1.0.0";
21+
let title = "fake-title";
22+
let summary = "fake-summary";
23+
let tags: HashMap<String, String> = vec![
24+
("key1".to_string(), "value1".to_string()),
25+
("key2".to_string(), "value2".to_string())]
26+
.into_iter()
27+
.collect();
28+
let mut timeout_duration = Duration::default();
29+
timeout_duration.minutes = Some(69);
30+
let basic_name = "fake-basic";
31+
let username = "fake-username";
32+
let password = "fake-password";
33+
let call_task_name = "call-task";
34+
let call_function_name = "fake-function";
35+
let call_task_with: HashMap<String, AnyValue> = vec![
36+
("key1".to_string(), AnyValue::String("value1".to_string())),
37+
("key2".to_string(), AnyValue::String("value2".to_string()))]
38+
.into_iter()
39+
.collect();
40+
let do_task_name = "do-task";
41+
let emit_task_name = "emit-task";
42+
let emit_event_attributes: HashMap<String, AnyValue> = vec![
43+
("key1".to_string(), AnyValue::String("value1".to_string())),
44+
("key2".to_string(), AnyValue::String("value2".to_string()))]
45+
.into_iter()
46+
.collect();
47+
let for_task_name = "for-task";
48+
let for_each = "item";
49+
let for_each_in = "items";
50+
let for_each_at = "index";
51+
let fork_task_name = "fork-task";
52+
let listen_task_name = "listen-task";
53+
let raise_task_name = "raise-task-name";
54+
let raise_error_type = "error-type";
55+
let raise_error_status = AnyValue::Int16(400);
56+
let raise_error_title = "error-title";
57+
let raise_error_detail = "error-detail";
58+
let raise_error_instance = "error-instance";
59+
let run_task_name = "run-task-name";
60+
let set_task_name = "set-task-name";
61+
let switch_task_name = "switch-task-name";
62+
let try_task_name = "try-task-name";
63+
let wait_task_name = "wait-task";
64+
let wait_duration = OneOfDurationOrIso8601Expression::Duration(Duration::from_days(3));
65+
66+
//act
67+
let workflow = WorkflowBuilder::new()
68+
.use_dsl(dsl_version)
69+
.with_namespace(namespace)
70+
.with_name(name)
71+
.with_version(version)
72+
.with_title(title)
73+
.with_summary(summary)
74+
.with_tags(tags.clone())
75+
.with_timeout(|t| { t.after(timeout_duration.clone()); })
76+
.use_authentication(basic_name, |a| {
77+
a.basic()
78+
.with_username(username)
79+
.with_password(password);})
80+
.do_(call_task_name, |t| {
81+
t.call(call_function_name)
82+
.with_arguments(call_task_with.clone());
83+
})
84+
.do_(do_task_name, |t| {
85+
t.do_()
86+
.do_("fake-wait-task", |st| {
87+
st.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(25)));
88+
});
89+
})
90+
.do_(wait_task_name, |t| {
91+
t.wait(wait_duration.clone());
92+
})
93+
.do_(emit_task_name, |t| {
94+
t.emit(|e|{
95+
e.with_attributes(emit_event_attributes.clone());
96+
});
97+
})
98+
.do_(for_task_name, |t| {
99+
t.for_()
100+
.each(for_each)
101+
.in_(for_each_in)
102+
.at(for_each_at)
103+
.do_("fake-wait-task", |st| {
104+
st.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(25)));
105+
});
106+
})
107+
.do_(fork_task_name, |t| {
108+
t.fork()
109+
.branch(|b| {
110+
b.do_("fake-wait-task", |st| {
111+
st.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(25)));
112+
});
113+
});
114+
})
115+
.do_(listen_task_name, |t| {
116+
t.listen()
117+
.to(|e|{
118+
e.one()
119+
.with("key", AnyValue::String("value".to_string()));
120+
});
121+
})
122+
.do_(raise_task_name, |t| {
123+
t.raise()
124+
.error()
125+
.with_type(raise_error_type)
126+
.with_status(raise_error_status)
127+
.with_title(raise_error_title)
128+
.with_detail(raise_error_detail)
129+
.with_instance(raise_error_instance);
130+
})
131+
.build();
132+
133+
//assert
134+
assert_eq!(workflow.document.dsl, dsl_version);
135+
assert_eq!(workflow.document.namespace, namespace);
136+
assert_eq!(workflow.document.name, name);
137+
assert_eq!(workflow.document.version, version);
138+
assert_eq!(workflow.document.title, Some(title.to_string()));
139+
assert_eq!(workflow.document.summary, Some(summary.to_string()));
140+
assert_eq!(workflow.document.tags, Some(tags));
141+
assert_eq!(workflow.timeout
142+
.as_ref()
143+
.and_then(|t| match t {
144+
OneOfTimeoutDefinitionOrReference::Timeout(definition) => match &definition.after {
145+
OneOfDurationOrIso8601Expression::Duration(duration) => Some(duration),
146+
OneOfDurationOrIso8601Expression::Iso8601Expression(_) => None,
147+
},
148+
OneOfTimeoutDefinitionOrReference::Reference(_) => None}),
149+
Some(&timeout_duration));
150+
assert!(
151+
workflow.use_.as_ref()
152+
.and_then(|component_collection| component_collection.authentications.as_ref())
153+
.and_then(|authentications| authentications.get(basic_name))
154+
.map(|auth_policy| auth_policy.basic.is_some())
155+
.unwrap_or(false),
156+
"Expected authentications to contain an entry with the name '{}' and a non-null `basic` property.",
157+
basic_name);
158+
assert!(
159+
workflow.do_
160+
.entries
161+
.iter()
162+
.any(|entry| entry.get(&call_task_name.to_string()).map_or(false, |task| {
163+
if let TaskDefinition::Call(call_task) = task {
164+
call_task.call == call_function_name && call_task.with == Some(call_task_with.clone())
165+
} else {
166+
false
167+
}
168+
})),
169+
"Expected a task with key '{}' and a CallTaskDefinition with 'call'={} and 'with'={:?}",
170+
call_task_name,
171+
call_function_name,
172+
call_task_with);
173+
assert!(
174+
workflow.do_
175+
.entries
176+
.iter()
177+
.any(|entry| entry.get(&do_task_name.to_string()).map_or(false, |task| {
178+
if let TaskDefinition::Do(_do_task) = task {
179+
true
180+
} else {
181+
false
182+
}
183+
})),
184+
"Expected a do task with key '{}'",
185+
do_task_name);
186+
assert!(
187+
workflow.do_
188+
.entries
189+
.iter()
190+
.any(|entry| entry.get(&emit_task_name.to_string()).map_or(false, |task| {
191+
if let TaskDefinition::Emit(emit_task) = task {
192+
emit_task.emit.event.with == emit_event_attributes.clone()
193+
} else {
194+
false
195+
}
196+
})),
197+
"Expected a task with key '{}' and a EmitTaskDefinition with 'emit.event.with' matching supplied attributes",
198+
emit_task_name);
199+
assert!(
200+
workflow.do_
201+
.entries
202+
.iter()
203+
.any(|entry| entry.get(&for_task_name.to_string()).map_or(false, |task| {
204+
if let TaskDefinition::For(for_task) = task {
205+
for_task.for_.each == for_each && for_task.for_.in_ == for_each_in && for_task.for_.at == Some(for_each_at.to_string())
206+
} else {
207+
false
208+
}
209+
})),
210+
"Expected a task with key '{}' and a ForTaskDefinition with 'for.each'={}, 'for.in'={}' and 'for.at'={}'",
211+
for_task_name,
212+
for_each,
213+
for_each_in,
214+
for_each_at);
215+
assert!(
216+
workflow.do_
217+
.entries
218+
.iter()
219+
.any(|entry| entry.get(&fork_task_name.to_string()).map_or(false, |task| {
220+
if let TaskDefinition::Fork(_fork_task) = task {
221+
true
222+
} else {
223+
false
224+
}
225+
})),
226+
"Expected a fork task with key '{}'",
227+
fork_task_name,);
228+
assert!(
229+
workflow.do_
230+
.entries
231+
.iter()
232+
.any(|entry| entry.get(&listen_task_name.to_string()).map_or(false, |task| {
233+
if let TaskDefinition::Listen(_listen_task) = task {
234+
true
235+
} else {
236+
false
237+
}
238+
})),
239+
"Expected a listen task with key '{}'",
240+
listen_task_name);
241+
assert!(
242+
workflow.do_
243+
.entries
244+
.iter()
245+
.any(|entry| entry.get(&raise_task_name.to_string()).map_or(false, |task| {
246+
if let TaskDefinition::Raise(raise_task) = task {
247+
if let OneOfErrorDefinitionOrReference::Error(error) = &raise_task.raise.error {
248+
error.type_ == raise_error_type
249+
&& error.title == raise_error_title
250+
&& error.detail == Some(raise_error_detail.to_string())
251+
&& error.instance == Some(raise_error_instance.to_string())
252+
} else {
253+
false
254+
}
255+
} else {
256+
false
257+
}
258+
})),
259+
"Expected a task with key '{}' and a RaiseTaskDefinition with 'raise.error.type'={}, 'raise.error.title'={}, 'raise.error.detail'={} and 'raise.error.instance'={}",
260+
raise_task_name,
261+
raise_error_type,
262+
raise_error_title,
263+
raise_error_detail,
264+
raise_error_instance);
265+
assert!(
266+
workflow.do_
267+
.entries
268+
.iter()
269+
.any(|entry| entry.get(&wait_task_name.to_string()).map_or(false, |task| {
270+
if let TaskDefinition::Wait(wait_task) = task {
271+
wait_task.duration == wait_duration
272+
} else {
273+
false
274+
}
275+
})),
276+
"Expected a task with key '{}' and a WaitTaskDefinition with 'duration'={}",
277+
wait_task_name,
278+
wait_duration);
279+
}
280+
281+
}

0 commit comments

Comments
 (0)