From fb12f797fd1e0dc8966d419616c9805004b6648d Mon Sep 17 00:00:00 2001 From: Charles d'Avernas Date: Mon, 8 Jul 2024 09:51:18 +0200 Subject: [PATCH] fix(Runner): Fixed the WorkflowExecutor to pass the context of the previous task instead of the workflow context when creating a new task executor Signed-off-by: Charles d'Avernas --- .../Services/WorkflowExecutor.cs | 2 +- .../Cases/Runner/RunnerTestsBase.cs | 3 +- .../Cases/Runner/WorkflowExecutorTests.cs | 67 +++++++++++++++++++ .../MockWorkflowExecutionContextFactory.cs | 5 +- 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 tests/Synapse.UnitTests/Cases/Runner/WorkflowExecutorTests.cs diff --git a/src/runner/Synapse.Runner/Services/WorkflowExecutor.cs b/src/runner/Synapse.Runner/Services/WorkflowExecutor.cs index a653f645a..dd034b699 100644 --- a/src/runner/Synapse.Runner/Services/WorkflowExecutor.cs +++ b/src/runner/Synapse.Runner/Services/WorkflowExecutor.cs @@ -278,7 +278,7 @@ protected virtual async Task OnTaskCompletedAsync(ITaskExecutor executor, Cancel return; } var nextTask = await this.Workflow.CreateTaskAsync(nextDefinition.Value, nextDefinition.Key, completedTask.Output ?? new { }, cancellationToken: cancellationToken).ConfigureAwait(false); - var nextExecutor = await this.CreateTaskExecutorAsync(nextTask, nextDefinition.Value, this.Workflow.ContextData, this.Workflow.Arguments, cancellationToken).ConfigureAwait(false); + var nextExecutor = await this.CreateTaskExecutorAsync(nextTask, nextDefinition.Value, executor.Task.ContextData, this.Workflow.Arguments, cancellationToken).ConfigureAwait(false); await nextExecutor.ExecuteAsync(cancellationToken).ConfigureAwait(false); } diff --git a/tests/Synapse.UnitTests/Cases/Runner/RunnerTestsBase.cs b/tests/Synapse.UnitTests/Cases/Runner/RunnerTestsBase.cs index 2faeb6e63..7f154d42c 100644 --- a/tests/Synapse.UnitTests/Cases/Runner/RunnerTestsBase.cs +++ b/tests/Synapse.UnitTests/Cases/Runner/RunnerTestsBase.cs @@ -12,7 +12,6 @@ // limitations under the License. using Docker.DotNet; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Moq; using Neuroglia.Data.Expressions.JQ; @@ -22,6 +21,7 @@ using Neuroglia.Data.PatchModel.Services; using Neuroglia.Eventing.CloudEvents.Infrastructure; using Neuroglia.Security.Services; +using ServerlessWorkflow.Sdk.IO; using StackExchange.Redis; using Synapse.Api.Client.Services; using Synapse.Core.Infrastructure.Containers; @@ -57,6 +57,7 @@ protected virtual IServiceCollection ConfigureServices(IServiceCollection servic services.AddSerialization(); services.AddJsonSerializer(); services.AddJQExpressionEvaluator(); + services.AddServerlessWorkflowIO(); services.AddSingleton(); services.AddSingleton(); services.AddMemoryCacheRepository(); diff --git a/tests/Synapse.UnitTests/Cases/Runner/WorkflowExecutorTests.cs b/tests/Synapse.UnitTests/Cases/Runner/WorkflowExecutorTests.cs new file mode 100644 index 000000000..b09162601 --- /dev/null +++ b/tests/Synapse.UnitTests/Cases/Runner/WorkflowExecutorTests.cs @@ -0,0 +1,67 @@ +// Copyright © 2024-Present The Synapse Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"), +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using ServerlessWorkflow.Sdk.IO; +using Synapse.Runner.Services; +using System.Text; + +namespace Synapse.UnitTests.Cases.Runner; + +public class WorkflowExecutorTests + : RunnerTestsBase +{ + + [Fact] + public async Task Run_Workflow_Should_Work() + { + //arrange + var yaml = @" +document: + dsl: '0.1' + namespace: default + name: hello-chain + version: '0.2.4' +do: +- say-hello-1: + set: + greetings: ${ ""Hello "" + (. // ""world"") } + input: + from: ${ $workflow.input.name1 } + export: + as: + greetings: ${ $output.greetings } +- say-hello-2: + set: + greetings: ${ $context.greetings + "" and "" + (. // ""world"") } + input: + from: ${ $workflow.input.name2 } +"; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(yaml)); + var definition = await this.ServiceProvider.GetRequiredService() + .ReadAsync(stream); + var input = new Neuroglia.EquatableDictionary() + { + new("name1", "John Doe"), + new("name2", "Jane Doe") + }; + var context = await MockWorkflowExecutionContextFactory.CreateAsync(this.ServiceProvider, definition, input); + var executor = ActivatorUtilities.CreateInstance(ServiceProvider, context); + + //act + await executor.ExecuteAsync(); + + //assert + context.Output.Should().NotBeNull(); + } + +} diff --git a/tests/Synapse.UnitTests/Services/MockWorkflowExecutionContextFactory.cs b/tests/Synapse.UnitTests/Services/MockWorkflowExecutionContextFactory.cs index a8171af77..616ef5538 100644 --- a/tests/Synapse.UnitTests/Services/MockWorkflowExecutionContextFactory.cs +++ b/tests/Synapse.UnitTests/Services/MockWorkflowExecutionContextFactory.cs @@ -15,6 +15,7 @@ using Neuroglia.Data.Infrastructure.ResourceOriented; using Neuroglia.Data.Infrastructure.ResourceOriented.Services; using Neuroglia.Data.Infrastructure.Services; +using Neuroglia; namespace Synapse.UnitTests.Services; @@ -23,7 +24,7 @@ internal static class MockWorkflowExecutionContextFactory internal static IWorkflowExecutionContext Create(IServiceProvider services, WorkflowDefinition definition, WorkflowInstance instance) => ActivatorUtilities.CreateInstance(services, definition, instance); - internal static async Task CreateAsync(IServiceProvider services, WorkflowDefinition? workflowDefinition = null) + internal static async Task CreateAsync(IServiceProvider services, WorkflowDefinition? workflowDefinition = null, EquatableDictionary? input = null) { var resources = services.GetRequiredService(); var documents = services.GetRequiredService>(); @@ -56,7 +57,7 @@ internal static async Task CreateAsync(IServiceProvid Namespace = workflow.GetNamespace()!, Version = workflowDefinition.Document.Version }, - Input = [] + Input = input ?? [] }, Status = new() {