From 4b91326935355c1480716ea9c1d8ea2969637906 Mon Sep 17 00:00:00 2001 From: Jack Schofield Date: Tue, 20 Sep 2022 13:15:17 +0100 Subject: [PATCH 1/5] add multiple conditions to task destinations Signed-off-by: Jack Schofield --- .../Parser/ConditionalParameterParser.cs | 24 +++++++--- .../Parser/IConditionalParameterParser.cs | 24 ++++++++++ .../Contracts/Models/TaskDestination.cs | 3 +- src/WorkflowManager/Logging/Logging/Log.cs | 3 ++ .../Storage/Services/DicomService.cs | 2 +- .../Services/WorkflowExecuterService.cs | 8 ++-- .../TestData/WorkflowRevisionTestData.cs | 46 +++++++++---------- 7 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs b/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs index ec89c1e77..9b91af24f 100644 --- a/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs +++ b/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs @@ -92,6 +92,24 @@ private set } } + public bool TryParse(string[] conditions, WorkflowInstance workflowInstance) + { + Guard.Against.NullOrEmpty(conditions); + Guard.Against.Null(workflowInstance); + try + { + var joinedConditions = string.Join(" AND ", conditions); + joinedConditions = ResolveParameters(joinedConditions, workflowInstance); + var conditionalGroup = ConditionalGroup.Create(joinedConditions); + return conditionalGroup.Evaluate(); + } + catch (Exception ex) + { + _logger.LogWarning($"Failure attemping to parse condition - {conditions}", ex); + return false; + } + } + public bool TryParse(string conditions, WorkflowInstance workflowInstance) { Guard.Against.NullOrEmpty(conditions); @@ -109,12 +127,6 @@ public bool TryParse(string conditions, WorkflowInstance workflowInstance) } } - /// - /// Resolves parameters in query string. - /// - /// The query string Example: {{ context.executions.task['other task'].'Fred' }} - /// workflow instance to resolve metadata parameter - /// public string ResolveParameters(string conditions, WorkflowInstance workflowInstance) { Guard.Against.NullOrEmpty(conditions); diff --git a/src/WorkflowManager/ConditionsResolver/Parser/IConditionalParameterParser.cs b/src/WorkflowManager/ConditionsResolver/Parser/IConditionalParameterParser.cs index c4cd352bc..ac9ec009e 100644 --- a/src/WorkflowManager/ConditionsResolver/Parser/IConditionalParameterParser.cs +++ b/src/WorkflowManager/ConditionsResolver/Parser/IConditionalParameterParser.cs @@ -20,10 +20,34 @@ namespace Monai.Deploy.WorkflowManager.ConditionsResolver.Parser { public interface IConditionalParameterParser { + /// + /// Resolves parameters in query string. + /// + /// The query string Example: {{ context.executions.other_task.'Fred' }} + /// workflow instance to resolve metadata parameter + /// string ResolveParameters(string conditions, WorkflowInstance workflowInstance); + /// + /// Resolves parameters in query string. + /// + /// The query string Example: {{ context.executions.other_task.'Fred' }} + /// workflow instance id to resolve metadata parameter + /// string ResolveParameters(string conditions, string workflowInstanceId); + /// + /// Verifies if an array of strings of conditions evaluates to true. + /// + /// An array of strings of conditions. + /// The workflow instance of the task. + bool TryParse(string[] conditions, WorkflowInstance workflowInstance); + + /// + /// Verifies if a string of conditions evaluates to true. + /// + /// A string of conditions. + /// The workflow instance of the task. bool TryParse(string conditions, WorkflowInstance workflowInstance); } } diff --git a/src/WorkflowManager/Contracts/Models/TaskDestination.cs b/src/WorkflowManager/Contracts/Models/TaskDestination.cs index 19cc916ef..b4dc8e823 100644 --- a/src/WorkflowManager/Contracts/Models/TaskDestination.cs +++ b/src/WorkflowManager/Contracts/Models/TaskDestination.cs @@ -14,6 +14,7 @@ * limitations under the License. */ +using System; using Newtonsoft.Json; namespace Monai.Deploy.WorkflowManager.Contracts.Models @@ -24,6 +25,6 @@ public class TaskDestination public string Name { get; set; } = string.Empty; [JsonProperty(PropertyName = "conditions")] - public string Conditions { get; set; } = string.Empty; + public string[] Conditions { get; set; } = Array.Empty(); } } diff --git a/src/WorkflowManager/Logging/Logging/Log.cs b/src/WorkflowManager/Logging/Logging/Log.cs index 33862c13b..821450247 100644 --- a/src/WorkflowManager/Logging/Logging/Log.cs +++ b/src/WorkflowManager/Logging/Logging/Log.cs @@ -162,5 +162,8 @@ public static void LogControllerEndTime(this ILogger logger, ResultExecutedConte [LoggerMessage(EventId = 32, Level = LogLevel.Debug, Message = "Verifying artifact existence on bucket {bucket}: {artifactKey}={artifactValue}.")] public static partial void VerifyArtifactExistence(this ILogger logger, string bucket, string artifactKey, string artifactValue); + + [LoggerMessage(EventId = 33, Level = LogLevel.Debug, Message = "Task destination condition for task {taskId} with condition: {conditions} resolved to false.")] + public static partial void TaskDestinationConditionFalse(this ILogger logger, string conditions, string taskId); } } diff --git a/src/WorkflowManager/Storage/Services/DicomService.cs b/src/WorkflowManager/Storage/Services/DicomService.cs index 53c6f53ce..1eab4db26 100644 --- a/src/WorkflowManager/Storage/Services/DicomService.cs +++ b/src/WorkflowManager/Storage/Services/DicomService.cs @@ -243,7 +243,7 @@ private static string GetPatientName(object[] values) } } - if(resultStr.Any() is true) + if (resultStr.Any() is true) { return string.Concat(resultStr); } diff --git a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs index 87d0fef43..b0771f335 100644 --- a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs +++ b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs @@ -507,10 +507,12 @@ private async Task> CreateTaskDestinations(WorkflowInstance foreach (var taskDest in currentTaskDestinations) { //Evaluate Conditional - if (!string.IsNullOrEmpty(taskDest.Conditions) - && taskDest.Conditions != string.Empty - && !_conditionalParameterParser.TryParse(taskDest.Conditions, workflowInstance)) + if (taskDest.Conditions.IsNullOrEmpty() is false + && taskDest.Conditions.All(c => c.Equals(string.Empty) is false) + && _conditionalParameterParser.TryParse(taskDest.Conditions, workflowInstance) is false) { + _logger.TaskDestinationConditionFalse(string.Join(" AND ", taskDest.Conditions), taskDest.Name); + continue; } diff --git a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs index ef89112cd..736f7c245 100644 --- a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs +++ b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs @@ -672,7 +672,7 @@ public static class WorkflowRevisionsTestData { new TaskDestination() { - Conditions = "{{ context.dicom.series.any('0010','0040') }} == 'lordge'", + Conditions = new string[] { "{{ context.dicom.series.any('0010','0040') }} == 'lordge'" }, Name = "cake" } } @@ -722,7 +722,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'true'=='true'" + Conditions = new string[] {"'true'=='true'"} }, } }, @@ -773,7 +773,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "{{ context.input.patient_details.name }} == 'Steve Jobs'" + Conditions = new string[] {"{{ context.input.patient_details.name }} == 'Steve Jobs'"} }, } }, @@ -824,7 +824,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "{{ context.input.patient_details.name }} == null" + Conditions = new string[] { "{{ context.input.patient_details.name }} == null" } }, } }, @@ -869,7 +869,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'false'=='true'" + Conditions = new string[] { "'false'=='true'" } }, } }, @@ -920,7 +920,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "{{ context.input.patient_details.name }} == 'Incorrect Name'" + Conditions = new string[] { "{{ context.input.patient_details.name }} == 'Incorrect Name'" } }, } }, @@ -965,17 +965,17 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'true'=='true'" + Conditions = new string[] { "'true'=='true'" } }, new TaskDestination() { Name = "e12849f3-247d-47eb-95c8-5aa16f551f62", - Conditions = "'true'=='true'" + Conditions = new string[] { "'true'=='true'" } }, new TaskDestination() { Name = "d2e5219d-9ccb-4584-b078-5216ee4b9b8b", - Conditions = "'true'=='true'" + Conditions = new string[] { "'true'=='true'" } }, } }, @@ -1034,7 +1034,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'false'=='true'" + Conditions = new string[] { "'false'=='true'" } }, } }, @@ -1079,17 +1079,17 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'true'=='true'" + Conditions = new string[] { "'true'=='true'" } }, new TaskDestination() { Name = "e12849f3-247d-47eb-95c8-5aa16f551f62", - Conditions = "'true'=='true'" + Conditions = new string[] { "'true'=='true'" } }, new TaskDestination() { Name = "d2e5219d-9ccb-4584-b078-5216ee4b9b8b", - Conditions = "'true'=='true'" + Conditions = new string[] {"'true'=='true'" } }, } }, @@ -1148,17 +1148,17 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'false'=='true'" + Conditions = new string[] { "'false'=='true'" } }, new TaskDestination() { Name = "e12849f3-247d-47eb-95c8-5aa16f551f62", - Conditions = "'false'=='true'" + Conditions = new string[] { "'false'=='true'" } }, new TaskDestination() { Name = "d2e5219d-9ccb-4584-b078-5216ee4b9b8b", - Conditions = "'false'=='true'" + Conditions = new string[] { "'false'=='true'" } }, } }, @@ -1211,12 +1211,12 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'true'=='true'" + Conditions = new string[] { "'true'=='true'" } }, new TaskDestination() { Name = "e12849f3-247d-47eb-95c8-5aa16f551f62", - Conditions = "'false'=='true'" + Conditions = new string[] { "'false'=='true'" } }, } }, @@ -1268,7 +1268,7 @@ public static class WorkflowRevisionsTestData new TaskDestination() { Name = "b9964b10-acb4-4050-a610-374fdbe2100d", - Conditions = "'invalid'>'false'" + Conditions = new string[] { "'invalid'>'false'" } }, } }, @@ -1400,8 +1400,8 @@ public static class WorkflowRevisionsTestData Artifacts = new ArtifactMap(), TaskDestinations = new TaskDestination[] { - new TaskDestination { Name = "taskdest1", Conditions = "'true'=='true'" }, - new TaskDestination { Name = "taskdest2", Conditions = "'false'=='true'" } + new TaskDestination { Name = "taskdest1", Conditions = new string[] { "'true'=='true'" } }, + new TaskDestination { Name = "taskdest2", Conditions = new string[] { "'false'=='true'" } } } }, new TaskObject @@ -1449,8 +1449,8 @@ public static class WorkflowRevisionsTestData Artifacts = new ArtifactMap(), TaskDestinations = new TaskDestination[] { - new TaskDestination { Name = "taskdest1", Conditions = "'false'=='true'" }, - new TaskDestination { Name = "taskdest2", Conditions = "'false'=='true'" } + new TaskDestination { Name = "taskdest1", Conditions = new string[] { "'false'=='true'" } }, + new TaskDestination { Name = "taskdest2", Conditions = new string[] { "'false'=='true'" } } } }, new TaskObject From 2f13ee52ca3e626ded41ce70f6bc92df82159255 Mon Sep 17 00:00:00 2001 From: Jack Schofield Date: Tue, 20 Sep 2022 13:48:51 +0100 Subject: [PATCH 2/5] add brackets extensions Signed-off-by: Jack Schofield --- .../Extensions/StringExtensions.cs | 27 +++++++++++++++++++ .../Parser/ConditionalParameterParser.cs | 3 ++- .../Services/WorkflowExecuterService.cs | 5 ++-- .../ConditionalParameterParserTests.cs | 14 +++++----- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs b/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs index 9ec8c103b..ef8ad35e7 100644 --- a/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs +++ b/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs @@ -53,5 +53,32 @@ public static string TrimStartExt(this string input, string prefixToRemove, Stri } return string.Empty; } + + /// + /// Adds brackets to multiple conditions. + /// + /// Array of conditions. + /// + public static string CombineConditionString(this string[] input) + { + var value = string.Empty; + + if (input.Length == 1) + { + return input.First(); + } + + for (var i = 0; i < input.Length; i++) + { + value += $"({input[i]})"; + + if (i != input.Length - 1) + { + value += " AND "; + } + } + + return value; + } } } diff --git a/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs b/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs index 9b91af24f..f23e73329 100644 --- a/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs +++ b/src/WorkflowManager/ConditionsResolver/Parser/ConditionalParameterParser.cs @@ -19,6 +19,7 @@ using Microsoft.Extensions.Logging; using Monai.Deploy.WorkflowManager.Common.Interfaces; using Monai.Deploy.WorkflowManager.ConditionsResolver.Constants; +using Monai.Deploy.WorkflowManager.ConditionsResolver.Extensions; using Monai.Deploy.WorkflowManager.ConditionsResolver.Resolver; using Monai.Deploy.WorkflowManager.Contracts.Models; using Monai.Deploy.WorkflowManager.Storage.Services; @@ -98,7 +99,7 @@ public bool TryParse(string[] conditions, WorkflowInstance workflowInstance) Guard.Against.Null(workflowInstance); try { - var joinedConditions = string.Join(" AND ", conditions); + var joinedConditions = conditions.CombineConditionString(); joinedConditions = ResolveParameters(joinedConditions, workflowInstance); var conditionalGroup = ConditionalGroup.Create(joinedConditions); return conditionalGroup.Evaluate(); diff --git a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs index b0771f335..693540d88 100644 --- a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs +++ b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs @@ -24,6 +24,7 @@ using Monai.Deploy.Storage.Configuration; using Monai.Deploy.WorkflowManager.Common.Extensions; using Monai.Deploy.WorkflowManager.Common.Interfaces; +using Monai.Deploy.WorkflowManager.ConditionsResolver.Extensions; using Monai.Deploy.WorkflowManager.ConditionsResolver.Parser; using Monai.Deploy.WorkflowManager.Configuration; using Monai.Deploy.WorkflowManager.Contracts.Constants; @@ -508,10 +509,10 @@ private async Task> CreateTaskDestinations(WorkflowInstance { //Evaluate Conditional if (taskDest.Conditions.IsNullOrEmpty() is false - && taskDest.Conditions.All(c => c.Equals(string.Empty) is false) + && taskDest.Conditions.Any(c => c.Equals(string.Empty) is false) && _conditionalParameterParser.TryParse(taskDest.Conditions, workflowInstance) is false) { - _logger.TaskDestinationConditionFalse(string.Join(" AND ", taskDest.Conditions), taskDest.Name); + _logger.TaskDestinationConditionFalse(taskDest.Conditions.CombineConditionString(), taskDest.Name); continue; } diff --git a/tests/UnitTests/WorkflowExecuter.Tests/Services/ConditionalParameterParserTests.cs b/tests/UnitTests/WorkflowExecuter.Tests/Services/ConditionalParameterParserTests.cs index 492051ec0..51439253e 100644 --- a/tests/UnitTests/WorkflowExecuter.Tests/Services/ConditionalParameterParserTests.cs +++ b/tests/UnitTests/WorkflowExecuter.Tests/Services/ConditionalParameterParserTests.cs @@ -46,17 +46,17 @@ public ConditionalParameterParserTests() } [Theory] - [InlineData("{{ context.dicom.series.all('0010','0040') }} == 'lordge' AND " + - "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'Fred' }} == 'Bob' AND " + - "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'fred' }} == 'lowercasefred'", true, "lordge")] + [InlineData(new string[] {"{{ context.dicom.series.all('0010','0040') }} == 'lordge'", + "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'Fred' }} == 'Bob'", + "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'fred' }} == 'lowercasefred'" }, true, "lordge")] [InlineData( - "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'Fred' }} == 'Bob' AND " + - "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'fred' }} == 'lowercasefred' AND " + + new string[] {"{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'Fred' }} == 'Bob'", + "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'fred' }} == 'lowercasefred'", "{{ context.executions.2dbd1af7-b699-4467-8e99-05a0c22422b4.result.'Sandra' }} == 'YassQueen' OR " + "{{ context.executions.other_task.result.'Fred' }} >= '32' OR " + "{{ context.executions.other_task.result.'Sandra' }} == 'other YassQueen' OR " + - "{{ context.executions.other_task.result.'Derick' }} == 'lordge'", true)] - public void ConditionalParameterParser_WhenGivenCorrectResultMetadataString_ShouldEvaluate(string input, bool expectedResult, string? expectedDicomReturn = null) + "{{ context.executions.other_task.result.'Derick' }} == 'lordge'" }, true)] + public void ConditionalParameterParser_WhenGivenCorrectResultMetadataString_MultiConditionShouldEvaluate(string[] input, bool expectedResult, string? expectedDicomReturn = null) { if (expectedDicomReturn is not null) { From 37028969d5fa63c90640f69bae192cb4f8fa37c0 Mon Sep 17 00:00:00 2001 From: Jack Schofield Date: Tue, 20 Sep 2022 14:39:55 +0100 Subject: [PATCH 3/5] fix code smells Signed-off-by: Jack Schofield --- .../ConditionsResolver/Extensions/StringExtensions.cs | 10 ++++++---- .../Services/WorkflowExecuterService.cs | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs b/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs index ef8ad35e7..29ecb0df9 100644 --- a/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs +++ b/src/WorkflowManager/ConditionsResolver/Extensions/StringExtensions.cs @@ -14,6 +14,8 @@ * limitations under the License. */ +using System.Text; + namespace Monai.Deploy.WorkflowManager.ConditionsResolver.Extensions { public static class StringExtensions @@ -61,7 +63,7 @@ public static string TrimStartExt(this string input, string prefixToRemove, Stri /// public static string CombineConditionString(this string[] input) { - var value = string.Empty; + var value = new StringBuilder(); if (input.Length == 1) { @@ -70,15 +72,15 @@ public static string CombineConditionString(this string[] input) for (var i = 0; i < input.Length; i++) { - value += $"({input[i]})"; + value.Append($"({input[i]})"); if (i != input.Length - 1) { - value += " AND "; + value.Append(" AND "); } } - return value; + return value.ToString(); } } } diff --git a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs index 693540d88..1e04a184f 100644 --- a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs +++ b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs @@ -509,7 +509,7 @@ private async Task> CreateTaskDestinations(WorkflowInstance { //Evaluate Conditional if (taskDest.Conditions.IsNullOrEmpty() is false - && taskDest.Conditions.Any(c => c.Equals(string.Empty) is false) + && taskDest.Conditions.Any(c => string.IsNullOrWhiteSpace(c) is false) && _conditionalParameterParser.TryParse(taskDest.Conditions, workflowInstance) is false) { _logger.TaskDestinationConditionFalse(taskDest.Conditions.CombineConditionString(), taskDest.Name); From e030ed1ebba120166638339feb52ea127f1ce764 Mon Sep 17 00:00:00 2001 From: Jack Schofield Date: Tue, 20 Sep 2022 15:13:56 +0100 Subject: [PATCH 4/5] update workflow spec Signed-off-by: Jack Schofield --- guidelines/mwm-workflow-spec.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/guidelines/mwm-workflow-spec.md b/guidelines/mwm-workflow-spec.md index d267a34d6..dcfcfd698 100644 --- a/guidelines/mwm-workflow-spec.md +++ b/guidelines/mwm-workflow-spec.md @@ -373,6 +373,34 @@ Example (run my-task-id when the patient is female): } ``` +The following examples both function the same and act as an AND condition. + +```json +{ + ...task... + "task_destinations": [ + { + "name": "my-task-id", + "conditions": ["{{context.input.dicom.series.all('0010','0040')}} == 'F' AND {{context.input.dicom.series.all('0010','0040')}} == 'M'"] + }, + ], + ... +} +``` + +```json +{ + ...task... + "task_destinations": [ + { + "name": "my-task-id", + "conditions": ["{{context.input.dicom.series.all('0010','0040')}} == 'F'", "{{context.input.dicom.series.all('0010','0040')}} == 'M'"] + }, + ], + ... +} +``` + ### Retention Policies _Future version: TBD_ From 242bacee3aa7318856d24e964a46e4ebaba50f5b Mon Sep 17 00:00:00 2001 From: Jack Schofield Date: Wed, 21 Sep 2022 10:41:56 +0100 Subject: [PATCH 5/5] add int tests Signed-off-by: Jack Schofield --- .../Features/TaskDestinations.feature | 18 +++- .../TestData/TaskUpdateTestData.cs | 32 +++++++ .../TestData/WorkflowInstanceTestData.cs | 56 ++++++++++++ .../TestData/WorkflowRevisionTestData.cs | 90 +++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) diff --git a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/Features/TaskDestinations.feature b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/Features/TaskDestinations.feature index 2210b089f..e2f71fe35 100644 --- a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/Features/TaskDestinations.feature +++ b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/Features/TaskDestinations.feature @@ -114,7 +114,23 @@ Scenario: Workflow instance status remains created when any task status is eithe And Workflow Instance status is Created @TaskDestinationConditions -Scenario: Workflow instance status is failed when a condition is invalid +Scenario: Single task destinations with multiple conditions true, single task dispatch message sent + Given I have a clinical workflow Multi_Task_Workflow_Destination_Single_Multi_Condition_True + And I have a Workflow Instance WFI_Task_Destination_Multi_Condition_True with no artifacts + When I publish a Task Update Message Task_Update_Task_Destination_Multi_Condition_True with status Succeeded + Then 1 Task Dispatch event is published + And Workflow Instance status is Created + +@TaskDestinationConditions +Scenario: Single task destinations with one condition true and one false, workflow instance status is succeeded + Given I have a clinical workflow Multi_Task_Workflow_Destination_Single_Multi_Condition_False + And I have a Workflow Instance WFI_Task_Destination_Multi_Condition_False with no artifacts + When I publish a Task Update Message Task_Update_Task_Destination_Multi_Condition_False with status Succeeded + Then A Task Dispatch event is not published + And Workflow Instance status is Succeeded + +@TaskDestinationConditions +Scenario: Workflow instance status is succeeded when a condition is invalid Given I have a clinical workflow Multi_Task_Workflow_Task_Destination_Invalid_Condition And I have a Workflow Instance WFI_Task_Destination_Invalid_Condition with no artifacts When I publish a Task Update Message Task_Update_Task_Destination_Invalid_Condition with status Succeeded diff --git a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/TaskUpdateTestData.cs b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/TaskUpdateTestData.cs index cbe89b8dc..9b91a4b38 100644 --- a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/TaskUpdateTestData.cs +++ b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/TaskUpdateTestData.cs @@ -444,6 +444,38 @@ public static TaskUpdateEvent CreateTaskUpdateEvent(string workflowInstanceName) } }, new TaskUpdateTestData() + { + Name = "Task_Update_Task_Destination_Multi_Condition_True", + TaskUpdateEvent = new TaskUpdateEvent() + { + WorkflowInstanceId = Helper.GetWorkflowInstanceByName("WFI_Task_Destination_Multi_Condition_True").WorkflowInstance.Id, + ExecutionId = Helper.GetWorkflowInstanceByName("WFI_Task_Destination_Multi_Condition_True").WorkflowInstance.Tasks[0].ExecutionId, + CorrelationId = Guid.NewGuid().ToString(), + Reason = FailureReason.None, + Message = "Task Message", + TaskId = Helper.GetWorkflowInstanceByName("WFI_Task_Destination_Multi_Condition_True").WorkflowInstance.Tasks[0].TaskId, + Metadata = new Dictionary() + { + } + } + }, + new TaskUpdateTestData() + { + Name = "Task_Update_Task_Destination_Multi_Condition_False", + TaskUpdateEvent = new TaskUpdateEvent() + { + WorkflowInstanceId = Helper.GetWorkflowInstanceByName("WFI_Task_Destination_Multi_Condition_False").WorkflowInstance.Id, + ExecutionId = Helper.GetWorkflowInstanceByName("WFI_Task_Destination_Multi_Condition_False").WorkflowInstance.Tasks[0].ExecutionId, + CorrelationId = Guid.NewGuid().ToString(), + Reason = FailureReason.None, + Message = "Task Message", + TaskId = Helper.GetWorkflowInstanceByName("WFI_Task_Destination_Multi_Condition_False").WorkflowInstance.Tasks[0].TaskId, + Metadata = new Dictionary() + { + } + } + }, + new TaskUpdateTestData() { Name = "Task_Update_Task_Destination_Metadata_Condition_True", TaskUpdateEvent = new TaskUpdateEvent() diff --git a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowInstanceTestData.cs b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowInstanceTestData.cs index 10b7d9e3c..96abbe99c 100644 --- a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowInstanceTestData.cs +++ b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowInstanceTestData.cs @@ -759,6 +759,62 @@ public static WorkflowInstance CreateWorkflowInstance(string workflowName) } }, new WorkflowInstanceTestData() + { + Name = "WFI_Task_Destination_Multi_Condition_True", + WorkflowInstance = new WorkflowInstance() + { + Id = Guid.NewGuid().ToString(), + AeTitle = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_True")?.WorkflowRevision?.Workflow?.InformaticsGateway?.AeTitle, + WorkflowId = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_True")?.WorkflowRevision?.WorkflowId ?? "", + PayloadId = Guid.NewGuid().ToString(), + StartTime = DateTime.Now, + Status = Status.Created, + BucketId = "bucket_1", + InputMetaData = new Dictionary() + { + { "", "" } + }, + Tasks = new List + { + new TaskExecution() + { + ExecutionId = Guid.NewGuid().ToString(), + TaskId = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_True")?.WorkflowRevision?.Workflow?.Tasks.FirstOrDefault()?.Id, + TaskType = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_True")?.WorkflowRevision?.Workflow?.Tasks.FirstOrDefault()?.Type, + Status = TaskExecutionStatus.Dispatched + } + } + } + }, + new WorkflowInstanceTestData() + { + Name = "WFI_Task_Destination_Multi_Condition_False", + WorkflowInstance = new WorkflowInstance() + { + Id = Guid.NewGuid().ToString(), + AeTitle = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_False")?.WorkflowRevision?.Workflow?.InformaticsGateway?.AeTitle, + WorkflowId = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_False")?.WorkflowRevision?.WorkflowId ?? "", + PayloadId = Guid.NewGuid().ToString(), + StartTime = DateTime.Now, + Status = Status.Created, + BucketId = "bucket_1", + InputMetaData = new Dictionary() + { + { "", "" } + }, + Tasks = new List + { + new TaskExecution() + { + ExecutionId = Guid.NewGuid().ToString(), + TaskId = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_False")?.WorkflowRevision?.Workflow?.Tasks.FirstOrDefault()?.Id, + TaskType = Helper.GetWorkflowByName("Multi_Task_Workflow_Destination_Single_Multi_Condition_False")?.WorkflowRevision?.Workflow?.Tasks.FirstOrDefault()?.Type, + Status = TaskExecutionStatus.Dispatched + } + } + } + }, + new WorkflowInstanceTestData() { Name = "WFI_Task_Destination_Metadata_Condition_False", WorkflowInstance = new WorkflowInstance() diff --git a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs index 736f7c245..77188f802 100644 --- a/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs +++ b/tests/IntegrationTests/WorkflowExecutor.IntegrationTests/TestData/WorkflowRevisionTestData.cs @@ -742,6 +742,96 @@ public static class WorkflowRevisionsTestData } }, new WorkflowRevisionTestData() + { + Name = "Multi_Task_Workflow_Destination_Single_Multi_Condition_True", + WorkflowRevision = new WorkflowRevision() + { + Id = Guid.NewGuid().ToString(), + WorkflowId = Guid.NewGuid().ToString(), + Revision = 1, + Workflow = new Workflow() + { + Name = "Multi Task workflow 3", + Description = "Multi Task workflow 3", + Version = "1", + Tasks = new TaskObject[] + { + new TaskObject + { + Id = "36d29b9d-d496-4568-a305-f0775c0f2084", + Type = "Multi_task", + Description = "Multiple request task 1", + Artifacts = new ArtifactMap(), + TaskDestinations = new TaskDestination[] + { + new TaskDestination() + { + Name = "b9964b10-acb4-4050-a610-374fdbe2100d", + Conditions = new string[] {"'true'=='true'", "'true'=='true'" } + }, + } + }, + new TaskObject + { + Id = "b9964b10-acb4-4050-a610-374fdbe2100d", + Type = "Multi_task", + Description = "Multiple request task 1", + Artifacts = new ArtifactMap(), + }, + }, + InformaticsGateway = new InformaticsGateway() + { + AeTitle = "Multi_Task_3" + } + } + } + }, + new WorkflowRevisionTestData() + { + Name = "Multi_Task_Workflow_Destination_Single_Multi_Condition_False", + WorkflowRevision = new WorkflowRevision() + { + Id = Guid.NewGuid().ToString(), + WorkflowId = Guid.NewGuid().ToString(), + Revision = 1, + Workflow = new Workflow() + { + Name = "Multi Task workflow 3", + Description = "Multi Task workflow 3", + Version = "1", + Tasks = new TaskObject[] + { + new TaskObject + { + Id = "36d29b9d-d496-4568-a305-f0775c0f2084", + Type = "Multi_task", + Description = "Multiple request task 1", + Artifacts = new ArtifactMap(), + TaskDestinations = new TaskDestination[] + { + new TaskDestination() + { + Name = "b9964b10-acb4-4050-a610-374fdbe2100d", + Conditions = new string[] {"'true'=='true'", "'true'=='false'" } + }, + } + }, + new TaskObject + { + Id = "b9964b10-acb4-4050-a610-374fdbe2100d", + Type = "Multi_task", + Description = "Multiple request task 1", + Artifacts = new ArtifactMap(), + }, + }, + InformaticsGateway = new InformaticsGateway() + { + AeTitle = "Multi_Task_3" + } + } + } + }, + new WorkflowRevisionTestData() { Name = "Multi_Task_Workflow_Destination_Single_Metadata_Condition_True", WorkflowRevision = new WorkflowRevision()