using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Extensions;
namespace Elsa.Activities.UnitTests.Flow;
///
/// Unit tests for the activity.
///
public class ForkTests
{
[Fact(DisplayName = "Fork schedules all branches")]
public async Task Fork_SchedulesAllBranches()
{
// Arrange
var branches = CreateBranches(3);
var fork = new Fork
{
JoinMode = ForkJoinMode.WaitAll,
Branches = branches.Cast().ToList()
};
// Act
var context = await ExecuteForkAsync(fork);
// Assert
foreach (var branch in branches)
{
Assert.True(context.HasScheduledActivity(branch), $"{branch.Id} should be scheduled");
}
}
[Fact(DisplayName = "Fork with no branches completes immediately")]
public async Task Fork_WithNoBranchesCompletesImmediately()
{
// Arrange
var fork = new Fork { JoinMode = ForkJoinMode.WaitAll };
// Act
var context = await ExecuteForkAsync(fork);
// Assert
Assert.Equal(ActivityStatus.Completed, context.Status);
}
[Theory(DisplayName = "Fork respects join mode")]
[InlineData(ForkJoinMode.WaitAll)]
[InlineData(ForkJoinMode.WaitAny)]
public async Task Fork_RespectsJoinMode(ForkJoinMode joinMode)
{
// Arrange
var branch = new WriteLine("Test Branch");
var fork = new Fork
{
JoinMode = joinMode,
Branches = { branch }
};
// Act
var context = await ExecuteForkAsync(fork);
// Assert
Assert.Equal(joinMode, fork.JoinMode);
Assert.True(context.HasScheduledActivity(branch));
}
[Fact(DisplayName = "Fork resumes when completed activity IDs are restored as a list")]
public async Task Fork_Resumes_WhenCompletedActivityIdsAreRestoredAsList()
{
// Arrange
var branches = CreateBranches(2);
var fork = new Fork
{
JoinMode = ForkJoinMode.WaitAll,
Branches = branches.Cast().ToList()
};
var fixture = new ActivityTestFixture(fork);
var targetContext = await fixture.BuildAsync();
await fixture.ExecuteAsync(targetContext);
targetContext.SetProperty("Completed", new List { branches[0].Id });
var childContext = await targetContext.WorkflowExecutionContext.CreateActivityExecutionContextAsync(branches[1]);
// Act
await CompleteChildAsync(fork, targetContext, childContext);
// Assert
Assert.Equal(ActivityStatus.Completed, targetContext.Status);
var completedActivityIds = targetContext.GetProperty>("Completed");
Assert.NotNull(completedActivityIds);
Assert.True(completedActivityIds.SetEquals([branches[0].Id, branches[1].Id]));
}
private static Task ExecuteForkAsync(Fork fork) =>
new ActivityTestFixture(fork).ExecuteAsync();
private static async Task CompleteChildAsync(Fork fork, ActivityExecutionContext targetContext, ActivityExecutionContext childContext)
{
var childNode = targetContext.WorkflowExecutionContext.FindNodeByActivity(childContext.Activity);
Assert.NotNull(childNode);
targetContext.WorkflowExecutionContext.AddCompletionCallback(targetContext, childNode!, fork.GetActivityCompletionCallback("CompleteChildAsync"));
var callback = targetContext.WorkflowExecutionContext.PopCompletionCallback(targetContext, childNode!);
Assert.NotNull(callback?.CompletionCallback);
await callback!.CompletionCallback!(new ActivityCompletedContext(targetContext, childContext));
}
private static WriteLine[] CreateBranches(int count) =>
Enumerable.Range(1, count)
.Select(i => new WriteLine($"Branch {i}") { Id = $"branch-{i}" })
.ToArray();
}