Skip to content

[4.0.x] Key property is missing in the Workflow #234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public void serialize(Workflow workflow, JsonGenerator gen, SerializerProvider p
gen.writeStringField("id", generateUniqueId());
}

if (workflow.getKey() != null) {
gen.writeStringField("key", workflow.getKey());
}
gen.writeStringField("name", workflow.getName());

if (workflow.getDescription() != null && !workflow.getDescription().isEmpty()) {
Expand Down
25 changes: 16 additions & 9 deletions api/src/main/resources/schema/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
"properties": {
"id": {
"type": "string",
"description": "Workflow unique identifier",
"minLength": 1
"description": "Workflow unique identifier"
},
"key": {
"type": "string",
"description": "Workflow Domain-specific identifier"
},
"name": {
"type": "string",
Expand Down Expand Up @@ -155,10 +158,14 @@
}
}
},
"required": [
"id",
"name",
"version",
"states"
]
}
"required": [
"name",
"version",
"states"
],
"dependencies":
{
"id": { "not": { "required": ["key"] } },
"key": { "not": { "required": ["id"] } }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@ public void testSpecExamplesParsing(String workflowLocation) {

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

assertNotNull(workflow);
assertNull(workflow.getKey());
assertNotNull(workflow.getId());
assertNotNull(workflow.getName());
assertNotNull(workflow.getStates());
Expand All @@ -118,6 +119,46 @@ public void testSpecFreatureFunctionRef(String workflowLocation) {
assertEquals(1, workflow.getFunctions().getFunctionDefs().size());
}

@ParameterizedTest
@ValueSource(
strings = {
"/features/applicantrequest-with-key.json",
"/features/applicantrequest-with-key.yml"
})
public void testSpecFeatureFunctionRefWithKey(String workflowLocation) {
Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation));

assertNotNull(workflow);
assertEquals("applicant-key-request", workflow.getKey());
assertNull(workflow.getId());
assertNotNull(workflow.getName());
assertNotNull(workflow.getStates());
assertTrue(workflow.getStates().size() > 0);

assertNotNull(workflow.getFunctions());
assertEquals(1, workflow.getFunctions().getFunctionDefs().size());
}

@ParameterizedTest
@ValueSource(
strings = {
"/features/applicantrequest-with-id-and-key.json",
"/features/applicantrequest-with-id-and-key.yml"
})
public void testSpecFeatureFunctionRefWithIdAndKey(String workflowLocation) {
Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation));

assertNotNull(workflow);
assertEquals("applicant-key-request", workflow.getKey());
assertEquals("applicant-with-key-and-id", workflow.getId());
assertNotNull(workflow.getName());
assertNotNull(workflow.getStates());
assertTrue(workflow.getStates().size() > 0);

assertNotNull(workflow.getFunctions());
assertEquals(1, workflow.getFunctions().getFunctionDefs().size());
}

@ParameterizedTest
@ValueSource(strings = {"/features/vetappointment.json", "/features/vetappointment.yml"})
public void testSpecFreatureEventRef(String workflowLocation) {
Expand Down
1 change: 1 addition & 0 deletions api/src/test/resources/examples/applicantrequest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"id": "applicantrequest",
"key": "applicant-key-request",
"version": "1.0",
"specVersion": "0.8",
"name": "Applicant Request Decision Workflow",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"id": "applicant-with-key-and-id",
"key": "applicant-key-request",
"version": "1.0",
"specVersion": "0.8",
"name": "Applicant Request Decision Workflow",
"description": "Determine if applicant request is valid",
"start": "CheckApplication",
"functions": [
{
"name": "sendRejectionEmailFunction",
"operation": "http://myapis.org/applicationapi.json#emailRejection"
}
],
"states":[
{
"name":"CheckApplication",
"type":"switch",
"dataConditions": [
{
"condition": "${ .applicants | .age >= 18 }",
"transition": "StartApplication"
},
{
"condition": "${ .applicants | .age < 18 }",
"transition": "RejectApplication"
}
],
"defaultCondition": {
"transition": "RejectApplication"
}
},
{
"name": "StartApplication",
"type": "operation",
"actions": [
{
"subFlowRef": "startApplicationWorkflowId"
}
],
"end": true
},
{
"name":"RejectApplication",
"type":"operation",
"actionMode":"sequential",
"actions":[
{
"functionRef": {
"refName": "sendRejectionEmailFunction",
"arguments": {
"applicant": "${ .applicant }"
}
}
}
],
"end": true
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
id: applicant-with-key-and-id
key: applicant-key-request
version: '1.0'
specVersion: '0.8'
name: Applicant Request Decision Workflow
description: Determine if applicant request is valid
start: CheckApplication
functions:
- name: sendRejectionEmailFunction
operation: http://myapis.org/applicationapi.json#emailRejection
states:
- name: CheckApplication
type: switch
dataConditions:
- condition: "${ .applicants | .age >= 18 }"
transition: StartApplication
- condition: "${ .applicants | .age < 18 }"
transition: RejectApplication
defaultCondition:
transition: RejectApplication
- name: StartApplication
type: operation
actions:
- subFlowRef: startApplicationWorkflowId
end: true
- name: RejectApplication
type: operation
actionMode: sequential
actions:
- functionRef:
refName: sendRejectionEmailFunction
arguments:
applicant: "${ .applicant }"
end: true
59 changes: 59 additions & 0 deletions api/src/test/resources/features/applicantrequest-with-key.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"key": "applicant-key-request",
"version": "1.0",
"specVersion": "0.8",
"name": "Applicant Request Decision Workflow",
"description": "Determine if applicant request is valid",
"start": "CheckApplication",
"functions": [
{
"name": "sendRejectionEmailFunction",
"operation": "http://myapis.org/applicationapi.json#emailRejection"
}
],
"states":[
{
"name":"CheckApplication",
"type":"switch",
"dataConditions": [
{
"condition": "${ .applicants | .age >= 18 }",
"transition": "StartApplication"
},
{
"condition": "${ .applicants | .age < 18 }",
"transition": "RejectApplication"
}
],
"defaultCondition": {
"transition": "RejectApplication"
}
},
{
"name": "StartApplication",
"type": "operation",
"actions": [
{
"subFlowRef": "startApplicationWorkflowId"
}
],
"end": true
},
{
"name":"RejectApplication",
"type":"operation",
"actionMode":"sequential",
"actions":[
{
"functionRef": {
"refName": "sendRejectionEmailFunction",
"arguments": {
"applicant": "${ .applicant }"
}
}
}
],
"end": true
}
]
}
33 changes: 33 additions & 0 deletions api/src/test/resources/features/applicantrequest-with-key.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
key: applicant-key-request
version: '1.0'
specVersion: '0.8'
name: Applicant Request Decision Workflow
description: Determine if applicant request is valid
start: CheckApplication
functions:
- name: sendRejectionEmailFunction
operation: http://myapis.org/applicationapi.json#emailRejection
states:
- name: CheckApplication
type: switch
dataConditions:
- condition: "${ .applicants | .age >= 18 }"
transition: StartApplication
- condition: "${ .applicants | .age < 18 }"
transition: RejectApplication
defaultCondition:
transition: RejectApplication
- name: StartApplication
type: operation
actions:
- subFlowRef: startApplicationWorkflowId
end: true
- name: RejectApplication
type: operation
actionMode: sequential
actions:
- functionRef:
refName: sendRejectionEmailFunction
arguments:
applicant: "${ .applicant }"
end: true
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@ public List<ValidationError> validate() {
List<EventDefinition> events =
workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null;

if (workflow.getId() == null || workflow.getId().trim().isEmpty()) {
addValidationError("Workflow id should not be empty", ValidationError.WORKFLOW_VALIDATION);
if ((workflow.getId() == null || workflow.getId().trim().isEmpty())
&& (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) {
addValidationError(
"Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION);
}

if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ public void testIncompleteJsonWithSchemaValidation() {
public void testIncompleteYamlWithSchemaValidation() {
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
List<ValidationError> validationErrors =
workflowValidator.setSource("---\n" + "id: abc\n").validate();
workflowValidator.setSource("---\n" + "key: abc\n").validate();
Assertions.assertNotNull(validationErrors);
System.out.println(validationErrors);
Assertions.assertEquals(3, validationErrors.size());
}

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

@Test
public void testWorkflowMissingStatesIdAndKey() {
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
List<ValidationError> validationErrors =
workflowValidator
.setSource(
"{\n"
+ "\t\"name\": \"test workflow\",\n"
+ " \"version\": \"1.0\",\n"
+ " \"start\": \"SomeState\",\n"
+ " \"states\": []\n"
+ "}")
.validate();
Assertions.assertNotNull(validationErrors);
Assertions.assertEquals(2, validationErrors.size());

Assertions.assertEquals(
"Workflow id or key should not be empty", validationErrors.get(0).getMessage());
Assertions.assertEquals("No states found", validationErrors.get(1).getMessage());
}

@Test
public void testOperationStateNoFunctionRef() {
WorkflowValidator workflowValidator = new WorkflowValidatorImpl();
Expand All @@ -101,7 +123,7 @@ public void testOperationStateNoFunctionRef() {
.setSource(
"{\n"
+ "\"id\": \"checkInbox\",\n"
+ " \"name\": \"Check Inbox Workflow\",\n"
+ "\"name\": \"Check Inbox Workflow\",\n"
+ "\"description\": \"Periodically Check Inbox\",\n"
+ "\"version\": \"1.0\",\n"
+ "\"start\": \"CheckInbox\",\n"
Expand Down Expand Up @@ -140,6 +162,7 @@ public void testOperationStateNoFunctionRef() {
Assertions.assertNotNull(validationErrors);
Assertions.assertEquals(1, validationErrors.size());

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