Skip to content

Commit fbb84ac

Browse files
Merge pull request #228 from spolti/addKey
Key property is missing in the Workflow
2 parents 67fc9cb + 8fbc3bf commit fbb84ac

File tree

10 files changed

+276
-13
lines changed

10 files changed

+276
-13
lines changed

api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public void serialize(Workflow workflow, JsonGenerator gen, SerializerProvider p
5353
gen.writeStringField("id", generateUniqueId());
5454
}
5555

56+
if (workflow.getKey() != null) {
57+
gen.writeStringField("key", workflow.getKey());
58+
}
5659
gen.writeStringField("name", workflow.getName());
5760

5861
if (workflow.getDescription() != null && !workflow.getDescription().isEmpty()) {

api/src/main/resources/schema/workflow.json

+15-8
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
"properties": {
1212
"id": {
1313
"type": "string",
14-
"description": "Workflow unique identifier",
15-
"minLength": 1
14+
"description": "Workflow unique identifier"
15+
},
16+
"key": {
17+
"type": "string",
18+
"description": "Workflow Domain-specific identifier"
1619
},
1720
"name": {
1821
"type": "string",
@@ -156,10 +159,14 @@
156159
}
157160
}
158161
},
159-
"required": [
160-
"id",
161-
"name",
162-
"version",
163-
"states"
164-
]
162+
"required": [
163+
"name",
164+
"version",
165+
"states"
166+
],
167+
"dependencies":
168+
{
169+
"id": { "not": { "required": ["key"] } },
170+
"key": { "not": { "required": ["id"] } }
171+
}
165172
}

api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java

+42-1
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,11 @@ public void testSpecExamplesParsing(String workflowLocation) {
101101

102102
@ParameterizedTest
103103
@ValueSource(strings = {"/features/applicantrequest.json", "/features/applicantrequest.yml"})
104-
public void testSpecFreatureFunctionRef(String workflowLocation) {
104+
public void testSpecFeatureFunctionRef(String workflowLocation) {
105105
Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation));
106106

107107
assertNotNull(workflow);
108+
assertNull(workflow.getKey());
108109
assertNotNull(workflow.getId());
109110
assertNotNull(workflow.getName());
110111
assertNotNull(workflow.getStates());
@@ -114,6 +115,46 @@ public void testSpecFreatureFunctionRef(String workflowLocation) {
114115
assertEquals(1, workflow.getFunctions().getFunctionDefs().size());
115116
}
116117

118+
@ParameterizedTest
119+
@ValueSource(
120+
strings = {
121+
"/features/applicantrequest-with-key.json",
122+
"/features/applicantrequest-with-key.yml"
123+
})
124+
public void testSpecFeatureFunctionRefWithKey(String workflowLocation) {
125+
Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation));
126+
127+
assertNotNull(workflow);
128+
assertEquals("applicant-key-request", workflow.getKey());
129+
assertNull(workflow.getId());
130+
assertNotNull(workflow.getName());
131+
assertNotNull(workflow.getStates());
132+
assertTrue(workflow.getStates().size() > 0);
133+
134+
assertNotNull(workflow.getFunctions());
135+
assertEquals(1, workflow.getFunctions().getFunctionDefs().size());
136+
}
137+
138+
@ParameterizedTest
139+
@ValueSource(
140+
strings = {
141+
"/features/applicantrequest-with-id-and-key.json",
142+
"/features/applicantrequest-with-id-and-key.yml"
143+
})
144+
public void testSpecFeatureFunctionRefWithIdAndKey(String workflowLocation) {
145+
Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation));
146+
147+
assertNotNull(workflow);
148+
assertEquals("applicant-key-request", workflow.getKey());
149+
assertEquals("applicant-with-key-and-id", workflow.getId());
150+
assertNotNull(workflow.getName());
151+
assertNotNull(workflow.getStates());
152+
assertTrue(workflow.getStates().size() > 0);
153+
154+
assertNotNull(workflow.getFunctions());
155+
assertEquals(1, workflow.getFunctions().getFunctionDefs().size());
156+
}
157+
117158
@ParameterizedTest
118159
@ValueSource(strings = {"/features/vetappointment.json", "/features/vetappointment.yml"})
119160
public void testSpecFreatureEventRef(String workflowLocation) {

api/src/test/resources/examples/applicantrequest.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"id": "applicantrequest",
3+
"key": "applicant-key-request",
34
"version": "1.0",
45
"specVersion": "0.8",
56
"name": "Applicant Request Decision Workflow",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"id": "applicant-with-key-and-id",
3+
"key": "applicant-key-request",
4+
"version": "1.0",
5+
"specVersion": "0.8",
6+
"name": "Applicant Request Decision Workflow",
7+
"description": "Determine if applicant request is valid",
8+
"start": "CheckApplication",
9+
"functions": [
10+
{
11+
"name": "sendRejectionEmailFunction",
12+
"operation": "http://myapis.org/applicationapi.json#emailRejection"
13+
}
14+
],
15+
"states":[
16+
{
17+
"name":"CheckApplication",
18+
"type":"switch",
19+
"dataConditions": [
20+
{
21+
"condition": "${ .applicants | .age >= 18 }",
22+
"transition": "StartApplication"
23+
},
24+
{
25+
"condition": "${ .applicants | .age < 18 }",
26+
"transition": "RejectApplication"
27+
}
28+
],
29+
"defaultCondition": {
30+
"transition": "RejectApplication"
31+
}
32+
},
33+
{
34+
"name": "StartApplication",
35+
"type": "operation",
36+
"actions": [
37+
{
38+
"subFlowRef": "startApplicationWorkflowId"
39+
}
40+
],
41+
"end": true
42+
},
43+
{
44+
"name":"RejectApplication",
45+
"type":"operation",
46+
"actionMode":"sequential",
47+
"actions":[
48+
{
49+
"functionRef": {
50+
"refName": "sendRejectionEmailFunction",
51+
"arguments": {
52+
"applicant": "${ .applicant }"
53+
}
54+
}
55+
}
56+
],
57+
"end": true
58+
}
59+
]
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
id: applicant-with-key-and-id
2+
key: applicant-key-request
3+
version: '1.0'
4+
specVersion: '0.8'
5+
name: Applicant Request Decision Workflow
6+
description: Determine if applicant request is valid
7+
start: CheckApplication
8+
functions:
9+
- name: sendRejectionEmailFunction
10+
operation: http://myapis.org/applicationapi.json#emailRejection
11+
states:
12+
- name: CheckApplication
13+
type: switch
14+
dataConditions:
15+
- condition: "${ .applicants | .age >= 18 }"
16+
transition: StartApplication
17+
- condition: "${ .applicants | .age < 18 }"
18+
transition: RejectApplication
19+
defaultCondition:
20+
transition: RejectApplication
21+
- name: StartApplication
22+
type: operation
23+
actions:
24+
- subFlowRef: startApplicationWorkflowId
25+
end: true
26+
- name: RejectApplication
27+
type: operation
28+
actionMode: sequential
29+
actions:
30+
- functionRef:
31+
refName: sendRejectionEmailFunction
32+
arguments:
33+
applicant: "${ .applicant }"
34+
end: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"key": "applicant-key-request",
3+
"version": "1.0",
4+
"specVersion": "0.8",
5+
"name": "Applicant Request Decision Workflow",
6+
"description": "Determine if applicant request is valid",
7+
"start": "CheckApplication",
8+
"functions": [
9+
{
10+
"name": "sendRejectionEmailFunction",
11+
"operation": "http://myapis.org/applicationapi.json#emailRejection"
12+
}
13+
],
14+
"states":[
15+
{
16+
"name":"CheckApplication",
17+
"type":"switch",
18+
"dataConditions": [
19+
{
20+
"condition": "${ .applicants | .age >= 18 }",
21+
"transition": "StartApplication"
22+
},
23+
{
24+
"condition": "${ .applicants | .age < 18 }",
25+
"transition": "RejectApplication"
26+
}
27+
],
28+
"defaultCondition": {
29+
"transition": "RejectApplication"
30+
}
31+
},
32+
{
33+
"name": "StartApplication",
34+
"type": "operation",
35+
"actions": [
36+
{
37+
"subFlowRef": "startApplicationWorkflowId"
38+
}
39+
],
40+
"end": true
41+
},
42+
{
43+
"name":"RejectApplication",
44+
"type":"operation",
45+
"actionMode":"sequential",
46+
"actions":[
47+
{
48+
"functionRef": {
49+
"refName": "sendRejectionEmailFunction",
50+
"arguments": {
51+
"applicant": "${ .applicant }"
52+
}
53+
}
54+
}
55+
],
56+
"end": true
57+
}
58+
]
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
key: applicant-key-request
2+
version: '1.0'
3+
specVersion: '0.8'
4+
name: Applicant Request Decision Workflow
5+
description: Determine if applicant request is valid
6+
start: CheckApplication
7+
functions:
8+
- name: sendRejectionEmailFunction
9+
operation: http://myapis.org/applicationapi.json#emailRejection
10+
states:
11+
- name: CheckApplication
12+
type: switch
13+
dataConditions:
14+
- condition: "${ .applicants | .age >= 18 }"
15+
transition: StartApplication
16+
- condition: "${ .applicants | .age < 18 }"
17+
transition: RejectApplication
18+
defaultCondition:
19+
transition: RejectApplication
20+
- name: StartApplication
21+
type: operation
22+
actions:
23+
- subFlowRef: startApplicationWorkflowId
24+
end: true
25+
- name: RejectApplication
26+
type: operation
27+
actionMode: sequential
28+
actions:
29+
- functionRef:
30+
refName: sendRejectionEmailFunction
31+
arguments:
32+
applicant: "${ .applicant }"
33+
end: true

validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,10 @@ public List<ValidationError> validate() {
112112
List<EventDefinition> events =
113113
workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null;
114114

115-
if (workflow.getId() == null || workflow.getId().trim().isEmpty()) {
116-
addValidationError("Workflow id should not be empty", ValidationError.WORKFLOW_VALIDATION);
115+
if ((workflow.getId() == null || workflow.getId().trim().isEmpty())
116+
&& (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) {
117+
addValidationError(
118+
"Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION);
117119
}
118120

119121
if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) {

validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java

+25-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ public void testIncompleteJsonWithSchemaValidation() {
4444
public void testIncompleteYamlWithSchemaValidation() {
4545
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
4646
List<ValidationError> validationErrors =
47-
workflowValidator.setSource("---\n" + "id: abc\n").validate();
47+
workflowValidator.setSource("---\n" + "key: abc\n").validate();
4848
Assertions.assertNotNull(validationErrors);
49+
System.out.println(validationErrors);
4950
Assertions.assertEquals(3, validationErrors.size());
5051
}
5152

@@ -93,6 +94,27 @@ public void testWorkflowMissingStates() {
9394
Assertions.assertEquals("No states found", validationErrors.get(0).getMessage());
9495
}
9596

97+
@Test
98+
public void testWorkflowMissingStatesIdAndKey() {
99+
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
100+
List<ValidationError> validationErrors =
101+
workflowValidator
102+
.setSource(
103+
"{\n"
104+
+ "\t\"name\": \"test workflow\",\n"
105+
+ " \"version\": \"1.0\",\n"
106+
+ " \"start\": \"SomeState\",\n"
107+
+ " \"states\": []\n"
108+
+ "}")
109+
.validate();
110+
Assertions.assertNotNull(validationErrors);
111+
Assertions.assertEquals(2, validationErrors.size());
112+
113+
Assertions.assertEquals(
114+
"Workflow id or key should not be empty", validationErrors.get(0).getMessage());
115+
Assertions.assertEquals("No states found", validationErrors.get(1).getMessage());
116+
}
117+
96118
@Test
97119
public void testOperationStateNoFunctionRef() {
98120
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
@@ -101,7 +123,7 @@ public void testOperationStateNoFunctionRef() {
101123
.setSource(
102124
"{\n"
103125
+ "\"id\": \"checkInbox\",\n"
104-
+ " \"name\": \"Check Inbox Workflow\",\n"
126+
+ "\"name\": \"Check Inbox Workflow\",\n"
105127
+ "\"description\": \"Periodically Check Inbox\",\n"
106128
+ "\"version\": \"1.0\",\n"
107129
+ "\"start\": \"CheckInbox\",\n"
@@ -140,6 +162,7 @@ public void testOperationStateNoFunctionRef() {
140162
Assertions.assertNotNull(validationErrors);
141163
Assertions.assertEquals(1, validationErrors.size());
142164

165+
// validationErrors.stream().forEach(v -> System.out.println(v.toString()));
143166
Assertions.assertEquals(
144167
"Operation State action functionRef does not reference an existing workflow function definition",
145168
validationErrors.get(0).getMessage());

0 commit comments

Comments
 (0)