Skip to content

Commit c0b19fe

Browse files
committed
Added missing UnitTests
1 parent c9b683b commit c0b19fe

File tree

72 files changed

+1681
-58
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1681
-58
lines changed

README.md

Lines changed: 121 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# Serverless Workflow Specification - .NET SDK
55

6-
Provides .NET 6.0 API/SPI and Model Validation for the [Serverless Workflow Specification](https://github.com/serverlessworkflow/specification)
6+
Provides .NET 7.0 API/SPI and Model Validation for the [Serverless Workflow Specification](https://github.com/serverlessworkflow/specification)
77

88
With the SDK, you can:
99

@@ -15,7 +15,7 @@ With the SDK, you can:
1515

1616
| Latest Releases | Conformance to spec version |
1717
| :---: | :---: |
18-
| [0.8.0.10](https://github.com/serverlessworkflow/sdk-net/releases/) | [v0.8](https://github.com/serverlessworkflow/specification/tree/0.8.x) |
18+
| [0.8.0.10](https://github.com/serverlessworkflow/sdk-net/releases/) | [0.8](https://github.com/serverlessworkflow/specification/tree/0.8.x) |
1919

2020
### Getting Started
2121

@@ -27,9 +27,9 @@ dotnet nuget add package ServerlessWorkflow.Sdk
2727
services.AddServerlessWorkflow();
2828
```
2929

30-
### How to use
30+
### Usage
3131

32-
#### Building workflows programatically
32+
#### Build workflows programatically
3333

3434
```csharp
3535
var workflow = WorkflowDefinition.Create("MyWorkflow", "MyWorkflow", "1.0")
@@ -60,7 +60,7 @@ var workflow = WorkflowDefinition.Create("MyWorkflow", "MyWorkflow", "1.0")
6060
.Build();
6161
```
6262

63-
#### Reading workflows
63+
#### Read workflows
6464

6565
```csharp
6666
var reader = WorkflowReader.Create();
@@ -70,7 +70,7 @@ using(Stream stream = File.OpenRead("myWorkflow.json"))
7070
}
7171
```
7272

73-
#### Writing workflows
73+
#### Write workflows
7474

7575
```csharp
7676
var writer = WorkflowWriter.Create();
@@ -88,9 +88,123 @@ using(Stream stream = File.OpenRead("myWorkflow.json"))
8888
}
8989
```
9090

91-
#### Validating workflows
91+
#### Validate workflows
9292

9393
```csharp
9494
var validator = serviceProvider.GetRequiredService<IValidator<WorkflowDefinition>>();
9595
var validationResult = validator.Validate(myWorkflow);
9696
```
97+
98+
#### Extend Workflows
99+
100+
The SDK allows extending the Serverless Workflow in two ways, possibly combined: via metadata and via extensions.
101+
102+
#### Metadata
103+
104+
Workflow components that support metadata, such as `WorkflowDefinition` or `StateDefinition`, expose a `metadata` property,
105+
which is a dynamic name/value mapping of properties used to enrich the serverless workflow model with information beyond its core definitions.
106+
107+
It has the advantage of being an easy, cross-compatible way of declaring additional data, but lacks well-defined, well-documented schema of the data, thus loosing the ability to validate it
108+
without custom implementation.
109+
110+
```csharp
111+
var workflow = new WorkflowBuilder()
112+
...
113+
.WithMetadata(new Dictionary<string, object>() { { "metadataPropertyName", metadataPropertyValue } })
114+
...
115+
.Build();
116+
```
117+
118+
#### Extension
119+
120+
Users have the ability to define extensions, providing the ability to extend, override or replace parts of the Serverless Workflow schema.
121+
122+
To do so, you must first create a file containing the JsonSchema of your extension, then reference it in your workflow definition.
123+
124+
*Schema of a sample extension that adds a new `greet` `functionType`:*
125+
<table>
126+
<tr>
127+
<th>JSON</th>
128+
<th>YAML</th>
129+
</tr>
130+
<tr>
131+
<td valign="top">
132+
133+
```json
134+
{
135+
"$defs": {
136+
"functions": {
137+
"definitions": {
138+
"function": {
139+
"type": "object",
140+
"properties": {
141+
"type": {
142+
"type": "string",
143+
"description": "Defines the function type. Is either `rest`, `asyncapi, `rpc`, `graphql`, `odata`, `expression` or `greet`. Default is `rest`",
144+
"enum": [
145+
"rest",
146+
"asyncapi",
147+
"rpc",
148+
"graphql",
149+
"odata",
150+
"expression",
151+
"custom",
152+
"greet"
153+
],
154+
"default": "rest"
155+
}
156+
}
157+
}
158+
}
159+
}
160+
}
161+
}
162+
```
163+
164+
</td>
165+
166+
<td valign="top">
167+
168+
```yaml
169+
'$defs':
170+
functions:
171+
definitions:
172+
function:
173+
type: object
174+
properties:
175+
type:
176+
type: string
177+
description: Defines the function type. Is either `rest`, `asyncapi, `rpc`,
178+
`graphql`, `odata`, `expression` or `greet`. Default is `rest`
179+
enum:
180+
- rest
181+
- asyncapi
182+
- rpc
183+
- graphql
184+
- odata
185+
- expression
186+
- custom
187+
- greet
188+
default: rest
189+
```
190+
191+
</td>
192+
</tr>
193+
</table>
194+
195+
The above example refers to `/$defs/functions`, because upon validation the SDK bundles all the Serverless Workflow Specification's schemas into the `$defs` property of a single schema.
196+
197+
*In this case, `functions` is the extensionless name of the schema file we want to override (https://serverlessworkflow.io/schemas/latest/functions.json).
198+
199+
A [Json Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386) is performed sequentially on the bundled schema with the defined extensions, in declaring order.
200+
201+
*In this case, the above schema will patch the object defined at `/functions/definitions/function` in file https://serverlessworkflow.io/schemas/latest/functions.json*
202+
203+
*Extending a workflow:*
204+
```csharp
205+
var workflow = new WorkflowBuilder()
206+
...
207+
.UseExtension("extensionId", new Uri("file://.../extensions/greet-function-type.json"))
208+
...
209+
.Build();
210+
```
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using ServerlessWorkflow.Sdk.Services.IO;
2+
3+
namespace ServerlessWorkflow.Sdk.UnitTests.Cases.IO;
4+
5+
public class WorkflowReaderTests
6+
{
7+
8+
protected IWorkflowReader Reader { get; } = WorkflowReader.Create();
9+
10+
[Fact]
11+
public async Task Read_Yaml_ShouldWork()
12+
{
13+
//arrange
14+
var yaml = File.ReadAllText(Path.Combine("Resources", "Workflows", "operation.yaml"));
15+
16+
//act
17+
var parsedWorkflow = await this.Reader.ParseAsync(yaml);
18+
19+
//assert
20+
parsedWorkflow
21+
.Should()
22+
.NotBeNull();
23+
parsedWorkflow.Events
24+
.Should()
25+
.NotBeEmpty();
26+
parsedWorkflow.Functions
27+
.Should()
28+
.NotBeEmpty();
29+
parsedWorkflow.States
30+
.Should()
31+
.NotBeEmpty();
32+
parsedWorkflow.Metadata
33+
.Should()
34+
.NotBeNull();
35+
parsedWorkflow.Metadata!["podSize"]
36+
.Should()
37+
.Be("small");
38+
}
39+
40+
[Fact]
41+
public async Task Read_Json_ShouldWork()
42+
{
43+
//arrange
44+
var yaml = File.ReadAllText(Path.Combine("Resources", "Workflows", "operation.json"));
45+
46+
//act
47+
var parsedWorkflow = await this.Reader.ParseAsync(yaml);
48+
49+
//assert
50+
parsedWorkflow
51+
.Should()
52+
.NotBeNull();
53+
parsedWorkflow.Events
54+
.Should()
55+
.NotBeEmpty();
56+
parsedWorkflow.Functions
57+
.Should()
58+
.NotBeEmpty();
59+
parsedWorkflow.States
60+
.Should()
61+
.NotBeEmpty();
62+
parsedWorkflow.Metadata
63+
.Should()
64+
.NotBeNull();
65+
parsedWorkflow.Metadata!["podSize"]
66+
.Should()
67+
.Be("small");
68+
}
69+
70+
[Fact]
71+
public async Task Read_Yaml_ExternalDefinitions_ShouldWork()
72+
{
73+
//arrange
74+
var yaml = File.ReadAllText(Path.Combine("Resources", "Workflows", "externalref.yaml"));
75+
76+
//act
77+
var workflow = await this.Reader.ParseAsync(yaml);
78+
79+
//assert
80+
workflow
81+
.Should()
82+
.NotBeNull();
83+
workflow.ConstantsUri
84+
.Should()
85+
.NotBeNull();
86+
workflow.SecretsUri
87+
.Should()
88+
.NotBeNull();
89+
workflow.DataInputSchemaUri
90+
.Should()
91+
.NotBeNull();
92+
workflow.EventsUri
93+
.Should()
94+
.NotBeNull();
95+
workflow.FunctionsUri
96+
.Should()
97+
.NotBeNull();
98+
workflow.RetriesUri
99+
.Should()
100+
.NotBeNull();
101+
}
102+
103+
[Fact]
104+
public async Task Read_Json_ExternalDefinitions_ShouldWork()
105+
{
106+
//arrange
107+
var yaml = File.ReadAllText(Path.Combine("Resources", "Workflows", "externalref.json"));
108+
109+
//act
110+
var workflow = await this.Reader.ParseAsync(yaml, new WorkflowReaderOptions() { LoadExternalDefinitions = true });
111+
112+
//assert
113+
workflow
114+
.Should()
115+
.NotBeNull();
116+
workflow.Constants
117+
.Should()
118+
.NotBeNull();
119+
workflow.Secrets
120+
.Should()
121+
.NotBeEmpty();
122+
workflow.DataInputSchema
123+
.Should()
124+
.NotBeNull();
125+
workflow.Events
126+
.Should()
127+
.NotBeEmpty();
128+
workflow.Functions
129+
.Should()
130+
.NotBeEmpty();
131+
workflow.Retries
132+
.Should()
133+
.NotBeEmpty();
134+
}
135+
136+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using ServerlessWorkflow.Sdk.Services.IO;
2+
3+
namespace ServerlessWorkflow.Sdk.UnitTests.Cases.Services;
4+
5+
public class WorkflowWriterTests
6+
{
7+
8+
protected IWorkflowWriter Writer { get; } = WorkflowWriter.Create();
9+
10+
protected IWorkflowReader Reader { get; } = WorkflowReader.Create();
11+
12+
protected static WorkflowDefinition BuildWorkflow()
13+
{
14+
return WorkflowDefinition.Create("MyWorkflow", "MyWorkflow", "1.0")
15+
.WithExecutionTimeout(timeout =>
16+
timeout.After(new TimeSpan(30, 2, 0, 0)))
17+
.StartsWith("inject", flow =>
18+
flow.Inject(new { username = "test", password = "123456"/*, scopes = new string[] { "api", "test" }*/ }))
19+
.Then("operation", flow =>
20+
flow.Execute("fakeApiFunctionCall", action =>
21+
{
22+
action.Invoke(function =>
23+
function.WithName("fakeFunction")
24+
.ForOperation(new Uri("https://fake.com/swagger.json#fake")))
25+
.WithArgument("username", "${ .username }")
26+
.WithArgument("password", "${ .password }");
27+
})
28+
.Execute("fakeEventTrigger", action =>
29+
{
30+
action
31+
.Consume(e =>
32+
e.WithName("fakeEvent")
33+
.WithSource(new Uri("https://fakesource.com"))
34+
.WithType("fakeType"))
35+
.ThenProduce(e =>
36+
e.WithName("otherEvent")
37+
.WithSource(new Uri("https://fakesource.com"))
38+
.WithType("fakeType"));
39+
}))
40+
.End()
41+
.Build();
42+
}
43+
44+
[Fact(Skip = "YAML parsing issue for non-complex properties (ex: externalRefs)")]
45+
public async Task Write_Yaml_ShouldWork()
46+
{
47+
var workflow = BuildWorkflow();
48+
using Stream stream = new MemoryStream();
49+
this.Writer.Write(workflow, stream);
50+
stream.Flush();
51+
stream.Position = 0;
52+
using StreamReader reader = new(stream);
53+
string yaml = reader.ReadToEnd();
54+
stream.Position = 0;
55+
workflow = await this.Reader.ReadAsync(stream);
56+
Assert.NotNull(workflow);
57+
}
58+
59+
[Fact]
60+
public async Task Write_Json_ShoudlWork()
61+
{
62+
var toSerialize = BuildWorkflow();
63+
using var stream = new MemoryStream();
64+
this.Writer.Write(toSerialize, stream, WorkflowDefinitionFormat.Json);
65+
stream.Flush();
66+
using StreamReader reader = new(stream);
67+
string json = reader.ReadToEnd();
68+
stream.Position = 0;
69+
var deserialized = await this.Reader.ReadAsync(stream);
70+
Assert.NotNull(deserialized);
71+
}
72+
73+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy