From 2db059da3d26bdbaeec138f07c085e87edcfe7d5 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sun, 8 Jun 2025 22:05:46 +0200 Subject: [PATCH] Enables activity test run to return results Updates the activity test run endpoint to return activity execution results such as outputs, outcomes, exceptions, and status. This allows users to inspect the results of test runs for activities, providing valuable insights into their behavior. --- .../Endpoints/Activities/TestRun/Endpoint.cs | 26 ++++++++++++++++++- .../Contracts/IActivityInvoker.cs | 2 +- .../Services/ActivityInvoker.cs | 4 ++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/Activities/TestRun/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/Activities/TestRun/Endpoint.cs index 406c1234d..a3f9764b9 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/Activities/TestRun/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/Activities/TestRun/Endpoint.cs @@ -1,6 +1,10 @@ using Elsa.Abstractions; +using Elsa.Extensions; using Elsa.Workflows.Management; using Elsa.Workflows.Models; +using Elsa.Workflows.Runtime; +using Elsa.Workflows.Runtime.Entities; +using Elsa.Workflows.State; namespace Elsa.Workflows.Api.Endpoints.Activities.TestRun; @@ -11,6 +15,7 @@ namespace Elsa.Workflows.Api.Endpoints.Activities.TestRun; internal class Endpoint( IWorkflowDefinitionService workflowDefinitionService, IActivityInvoker activityInvoker, + IActivityExecutionMapper activityExecutionMapper, IIdentityGenerator identityGenerator, IServiceProvider serviceProvider) : ElsaEndpoint @@ -45,7 +50,18 @@ internal class Endpoint( return; } - await activityInvoker.InvokeAsync(workflowExecutionContext, activity); + var activityExecutionContext = await activityInvoker.InvokeAsync(workflowExecutionContext, activity); + var record = activityExecutionMapper.Map(activityExecutionContext); + var outcomes = record.Payload != null && record.Payload.TryGetValue("Outcomes", out var outcomesObj) ? outcomesObj as ICollection : null; + var response = new Response + { + Outputs = record.Outputs, + Outcomes = outcomes, + Exception = record.Exception, + Status = record.Status + }; + + await SendOkAsync(response, cancellationToken); } } @@ -53,4 +69,12 @@ public class Request { public WorkflowDefinitionHandle WorkflowDefinitionHandle { get; set; } = null!; public ActivityHandle ActivityHandle { get; set; } = null!; +} + +public class Response +{ + public IDictionary? Outputs { get; set; } + public ICollection? Outcomes { get; set; } + public ExceptionState? Exception { get; set; } + public ActivityStatus Status { get; set; } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityInvoker.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityInvoker.cs index a3cd9af2f..6b9267cc8 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IActivityInvoker.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityInvoker.cs @@ -13,7 +13,7 @@ public interface IActivityInvoker /// The workflow execution context. /// The activity to invoke. /// - Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = default); + Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = null); /// /// Invokes the specified activity execution context. diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs index a7d86aa5d..4560f6974 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs @@ -12,7 +12,7 @@ public class ActivityInvoker( { /// - public async Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = null) + public async Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = null) { // Setup an activity execution context, potentially reusing an existing one if requested. var existingActivityExecutionContext = options?.ExistingActivityExecutionContext; @@ -34,6 +34,8 @@ public class ActivityInvoker( // Execute the activity execution pipeline. await InvokeAsync(activityExecutionContext); + + return activityExecutionContext; } ///