elsa-core/test/unit/Elsa.Activities.UnitTests/Branching/FlowJoinTests.cs
Sipke Schoorstra 4bbdd6f3a7
Configures Flowchart Execution via DI (#7141)
* Introduce `FlowchartExecutionMode` to streamline flowchart execution logic.

- Added `FlowchartExecutionMode` enum to represent execution modes (Default, TokenBased, CounterBased).
- Updated flowchart-related integration and unit tests to use the new execution mode.
- Removed the global `UseTokenFlow` flag in favor of execution-specific configuration via `RunWorkflowOptions`.
- Refactored flowchart-related APIs and test helpers for improved flexibility and modularity.

* Add support for configuring flowchart execution behavior via `FlowchartOptions` and DI.

- Introduced extensions for `FlowchartFeature` to simplify configuration.
- Added DI support for setting default execution modes.
- Refactored flowchart execution logic to prioritize configuration.

* Update default Flowchart execution settings to align with version 3.5.2 behavior

- Changed `DefaultExecutionMode` to `CounterBased`.
- Updated `UseTokenFlow` default to `false`.

* Update src/modules/Elsa.Workflows.Core/Activities/Flowchart/Models/FlowchartExecutionMode.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/Elsa.Workflows.Core/Activities/Flowchart/Extensions/FlowchartFeatureExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update test/integration/Elsa.Workflows.IntegrationTests/Scenarios/FlowchartNextActivity/Tests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/Elsa.Workflows.Core/Activities/Flowchart/Extensions/RunWorkflowOptionsExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Refactor flowchart integration tests for improved formatting and consistency

* Refactor workflow tests and related services to improve reusability and align with updated Flowchart execution behavior

* Update src/modules/Elsa.Workflows.Core/Activities/Flowchart/Options/FlowchartOptions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Refactor flowchart execution logic to use `FlowchartExecutionMode` enum, replacing boolean checks for improved clarity and extensibility.

* Refactor tests and workflow logic to replace boolean `useTokenFlow` with `FlowchartExecutionMode` enum for clarity and consistency.

* Refactor flowchart execution logic to centralize mode-based behavior handling and simplify implementation.

* Remove unnecessary whitespace in Flowchart.cs to improve code formatting

* Remove unnecessary whitespace in FlowJoinTests.cs to improve code formatting

* Update src/common/Elsa.Testing.Shared.Integration/WorkflowTestFixture.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 10:15:39 +01:00

122 lines
4.9 KiB
C#

using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;
namespace Elsa.Activities.UnitTests.Branching;
/// <summary>
/// Unit tests for FlowJoin activity covering both token flow and counter flow modes.
/// </summary>
public class FlowJoinTests
{
[Theory]
[InlineData(FlowchartExecutionMode.TokenBased, FlowJoinMode.WaitAny)]
[InlineData(FlowchartExecutionMode.TokenBased, FlowJoinMode.WaitAll)]
[InlineData(FlowchartExecutionMode.CounterBased, FlowJoinMode.WaitAny)]
[InlineData(FlowchartExecutionMode.CounterBased, FlowJoinMode.WaitAll)]
public async Task Should_Complete_In_All_Flow_Mode_Combinations(FlowchartExecutionMode executionMode, FlowJoinMode joinMode)
{
// Arrange & Act
var context = await ExecuteWithFlowModeAsync(executionMode, joinMode);
// Assert
Assert.True(context.IsCompleted);
}
[Theory]
[InlineData(FlowchartExecutionMode.TokenBased, FlowJoinMode.WaitAny)]
[InlineData(FlowchartExecutionMode.TokenBased, FlowJoinMode.WaitAll)]
[InlineData(FlowchartExecutionMode.CounterBased, FlowJoinMode.WaitAny)]
[InlineData(FlowchartExecutionMode.CounterBased, FlowJoinMode.WaitAll)]
public async Task Should_Execute_In_Flowchart_Context_For_All_Combinations(FlowchartExecutionMode executionMode, FlowJoinMode joinMode)
{
// Arrange & Act
var (context, flowJoin) = await ExecuteInFlowchartWithFlowModeAsync(executionMode, joinMode);
// Assert
Assert.NotNull(context);
var expectedMessage = executionMode == FlowchartExecutionMode.TokenBased
? $"Token flow mode with {joinMode} should schedule the join activity"
: $"Counter flow mode with {joinMode} should schedule the join activity as start";
Assert.True(context.HasScheduledActivity(flowJoin), expectedMessage);
}
[Fact]
public async Task Should_Demonstrate_Token_vs_Counter_Flow_Differences()
{
// Arrange
var joinMode = FlowJoinMode.WaitAll; // Use WaitAll to highlight differences
// Act
var tokenContext = await ExecuteWithFlowModeAsync(FlowchartExecutionMode.TokenBased, joinMode);
var counterContext = await ExecuteWithFlowModeAsync(FlowchartExecutionMode.CounterBased, joinMode);
// Assert
Assert.True(tokenContext.IsCompleted, "Token flow should always complete");
Assert.True(counterContext.IsCompleted, "Counter flow should complete without parent context");
}
/// <summary>
/// Creates a FlowJoin activity with the specified mode.
/// </summary>
private static FlowJoin CreateFlowJoin(FlowJoinMode joinMode) => new() { Mode = new(joinMode) };
/// <summary>
/// Creates a simple flowchart with the FlowJoin as the start activity.
/// </summary>
private static Flowchart CreateSimpleFlowchart(FlowJoin flowJoin) => new()
{
Start = flowJoin,
Activities = { flowJoin }
};
/// <summary>
/// Executes a FlowJoin activity with the specified flow mode.
/// </summary>
private static async Task<ActivityExecutionContext> ExecuteWithFlowModeAsync(FlowchartExecutionMode executionMode, FlowJoinMode joinMode)
{
var flowJoin = CreateFlowJoin(joinMode);
return await ExecuteAsync(flowJoin, executionMode);
}
/// <summary>
/// Executes a FlowJoin activity within a flowchart context with the specified flow mode.
/// </summary>
private static async Task<(ActivityExecutionContext context, FlowJoin flowJoin)> ExecuteInFlowchartWithFlowModeAsync(FlowchartExecutionMode executionMode, FlowJoinMode joinMode)
{
var flowJoin = CreateFlowJoin(joinMode);
var flowchart = CreateSimpleFlowchart(flowJoin);
var context = await ExecuteFlowchartAsync(flowchart, executionMode);
return (context, flowJoin);
}
/// <summary>
/// Executes a flowchart using the ActivityTestFixture with the specified execution mode.
/// </summary>
private static Task<ActivityExecutionContext> ExecuteFlowchartAsync(Flowchart flowchart, FlowchartExecutionMode? executionMode = null)
{
return ExecuteAsync(flowchart, executionMode);
}
/// <summary>
/// Executes an activity using the ActivityTestFixture with the specified execution mode.
/// </summary>
private static async Task<ActivityExecutionContext> ExecuteAsync(IActivity activity, FlowchartExecutionMode? executionMode = null)
{
var fixture = new ActivityTestFixture(activity);
if (executionMode.HasValue)
{
fixture.ConfigureContext(context =>
{
context.WorkflowExecutionContext.Properties[Flowchart.ExecutionModePropertyKey] = executionMode.Value;
});
}
return await fixture.ExecuteAsync();
}
}