2025-11-03 13:01:07 +00:00
|
|
|
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]
|
2025-12-15 09:15:39 +00:00
|
|
|
[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)
|
2025-11-03 13:01:07 +00:00
|
|
|
{
|
2025-11-04 09:24:16 +00:00
|
|
|
// Arrange & Act
|
2025-12-15 09:15:39 +00:00
|
|
|
var context = await ExecuteWithFlowModeAsync(executionMode, joinMode);
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
// Assert
|
|
|
|
|
Assert.True(context.IsCompleted);
|
2025-11-03 13:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Theory]
|
2025-12-15 09:15:39 +00:00
|
|
|
[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)
|
2025-11-03 13:01:07 +00:00
|
|
|
{
|
2025-11-04 09:24:16 +00:00
|
|
|
// Arrange & Act
|
2025-12-15 09:15:39 +00:00
|
|
|
var (context, flowJoin) = await ExecuteInFlowchartWithFlowModeAsync(executionMode, joinMode);
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
// Assert
|
|
|
|
|
Assert.NotNull(context);
|
|
|
|
|
|
2025-12-15 09:15:39 +00:00
|
|
|
var expectedMessage = executionMode == FlowchartExecutionMode.TokenBased
|
2025-11-04 09:24:16 +00:00
|
|
|
? $"Token flow mode with {joinMode} should schedule the join activity"
|
|
|
|
|
: $"Counter flow mode with {joinMode} should schedule the join activity as start";
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
Assert.True(context.HasScheduledActivity(flowJoin), expectedMessage);
|
2025-11-03 13:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
[Fact]
|
|
|
|
|
public async Task Should_Demonstrate_Token_vs_Counter_Flow_Differences()
|
2025-11-03 13:01:07 +00:00
|
|
|
{
|
|
|
|
|
// Arrange
|
2025-11-04 09:24:16 +00:00
|
|
|
var joinMode = FlowJoinMode.WaitAll; // Use WaitAll to highlight differences
|
|
|
|
|
|
|
|
|
|
// Act
|
2025-12-15 09:15:39 +00:00
|
|
|
var tokenContext = await ExecuteWithFlowModeAsync(FlowchartExecutionMode.TokenBased, joinMode);
|
|
|
|
|
var counterContext = await ExecuteWithFlowModeAsync(FlowchartExecutionMode.CounterBased, joinMode);
|
2025-11-04 09:24:16 +00:00
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
|
Assert.True(tokenContext.IsCompleted, "Token flow should always complete");
|
|
|
|
|
Assert.True(counterContext.IsCompleted, "Counter flow should complete without parent context");
|
|
|
|
|
}
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a FlowJoin activity with the specified mode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static FlowJoin CreateFlowJoin(FlowJoinMode joinMode) => new() { Mode = new(joinMode) };
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
/// <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>
|
2025-12-15 09:15:39 +00:00
|
|
|
/// Executes a FlowJoin activity with the specified flow mode.
|
2025-11-04 09:24:16 +00:00
|
|
|
/// </summary>
|
2025-12-15 09:15:39 +00:00
|
|
|
private static async Task<ActivityExecutionContext> ExecuteWithFlowModeAsync(FlowchartExecutionMode executionMode, FlowJoinMode joinMode)
|
2025-11-04 09:24:16 +00:00
|
|
|
{
|
2025-12-15 09:15:39 +00:00
|
|
|
var flowJoin = CreateFlowJoin(joinMode);
|
|
|
|
|
return await ExecuteAsync(flowJoin, executionMode);
|
2025-11-04 09:24:16 +00:00
|
|
|
}
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Executes a FlowJoin activity within a flowchart context with the specified flow mode.
|
|
|
|
|
/// </summary>
|
2025-12-15 09:15:39 +00:00
|
|
|
private static async Task<(ActivityExecutionContext context, FlowJoin flowJoin)> ExecuteInFlowchartWithFlowModeAsync(FlowchartExecutionMode executionMode, FlowJoinMode joinMode)
|
2025-11-04 09:24:16 +00:00
|
|
|
{
|
2025-12-15 09:15:39 +00:00
|
|
|
var flowJoin = CreateFlowJoin(joinMode);
|
|
|
|
|
var flowchart = CreateSimpleFlowchart(flowJoin);
|
|
|
|
|
var context = await ExecuteFlowchartAsync(flowchart, executionMode);
|
|
|
|
|
return (context, flowJoin);
|
2025-11-03 13:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
/// <summary>
|
2025-12-15 09:15:39 +00:00
|
|
|
/// Executes a flowchart using the ActivityTestFixture with the specified execution mode.
|
2025-11-04 09:24:16 +00:00
|
|
|
/// </summary>
|
2025-12-15 09:15:39 +00:00
|
|
|
private static Task<ActivityExecutionContext> ExecuteFlowchartAsync(Flowchart flowchart, FlowchartExecutionMode? executionMode = null)
|
2025-11-03 13:01:07 +00:00
|
|
|
{
|
2025-12-15 09:15:39 +00:00
|
|
|
return ExecuteAsync(flowchart, executionMode);
|
2025-11-03 13:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-04 09:24:16 +00:00
|
|
|
/// <summary>
|
2025-12-15 09:15:39 +00:00
|
|
|
/// Executes an activity using the ActivityTestFixture with the specified execution mode.
|
2025-11-04 09:24:16 +00:00
|
|
|
/// </summary>
|
2025-12-15 09:15:39 +00:00
|
|
|
private static async Task<ActivityExecutionContext> ExecuteAsync(IActivity activity, FlowchartExecutionMode? executionMode = null)
|
2025-11-03 13:01:07 +00:00
|
|
|
{
|
2025-12-15 09:15:39 +00:00
|
|
|
var fixture = new ActivityTestFixture(activity);
|
2025-11-03 13:01:07 +00:00
|
|
|
|
2025-12-15 09:15:39 +00:00
|
|
|
if (executionMode.HasValue)
|
|
|
|
|
{
|
|
|
|
|
fixture.ConfigureContext(context =>
|
|
|
|
|
{
|
|
|
|
|
context.WorkflowExecutionContext.Properties[Flowchart.ExecutionModePropertyKey] = executionMode.Value;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await fixture.ExecuteAsync();
|
2025-11-03 13:01:07 +00:00
|
|
|
}
|
|
|
|
|
}
|