Merge remote-tracking branch 'origin/blueberry'
This commit is contained in:
commit
3208be7b89
|
|
@ -8,7 +8,12 @@ public class SignalManager
|
|||
|
||||
public async Task<T> WaitAsync<T>(object signal, int millisecondsTimeout = 8000)
|
||||
{
|
||||
return await WaitAsync(signal, millisecondsTimeout) is T result ? result : throw new InvalidCastException($"Signal '{signal}' was not of type '{typeof(T).Name}'.");
|
||||
var result = await WaitAsync(signal, millisecondsTimeout);
|
||||
|
||||
if(result is not T typedResult)
|
||||
throw new InvalidCastException($"Signal '{signal}' was not of type '{typeof(T).Name}'.");
|
||||
|
||||
return typedResult;
|
||||
}
|
||||
|
||||
public async Task<object?> WaitAsync(object signal, int millisecondsTimeout = 8000)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class ClrWorkflowMaterializer : IWorkflowMaterializer
|
|||
public async ValueTask<Workflow> MaterializeAsync(WorkflowDefinition definition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var providerContext = _payloadSerializer.Deserialize<ClrWorkflowMaterializerContext>(definition.MaterializerContext!);
|
||||
var workflowBuilderType = providerContext.WorkflowBuilderType;
|
||||
var workflowBuilderType = providerContext.WorkflowBuilderType == null! ? typeof(NotFoundWorkflowbuilder) : providerContext.WorkflowBuilderType;
|
||||
var workflowBuilder = (IWorkflow)ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, workflowBuilderType);
|
||||
var workflowDefinitionBuilder = _workflowBuilderFactory.CreateBuilder();
|
||||
var workflow = await workflowDefinitionBuilder.BuildWorkflowAsync(workflowBuilder, cancellationToken);
|
||||
|
|
@ -56,4 +56,11 @@ public class ClrWorkflowMaterializer : IWorkflowMaterializer
|
|||
/// Provides context for the CLR workflow materializer.
|
||||
/// </summary>
|
||||
/// <param name="WorkflowBuilderType">The type of the workflow builder.</param>
|
||||
public record ClrWorkflowMaterializerContext(Type WorkflowBuilderType);
|
||||
public record ClrWorkflowMaterializerContext(Type WorkflowBuilderType);
|
||||
|
||||
/// <summary>
|
||||
/// A workflow builder that is used when the workflow builder type is not found.
|
||||
/// </summary>
|
||||
public class NotFoundWorkflowbuilder : WorkflowBase
|
||||
{
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ public class BulkDispatchWorkflows : Activity
|
|||
Arguments = itemDictionary
|
||||
};
|
||||
|
||||
var inputDictionary = item as IDictionary<string, object> ?? new Dictionary<string, object>();
|
||||
var inputDictionary = item as IDictionary<string, object> ?? itemDictionary;
|
||||
input["ParentInstanceId"] = parentInstanceId;
|
||||
input.Merge(inputDictionary);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers_005Ccontracts/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers_005Ceventargs/@EntryIndexedValue">True</s:Boolean>
|
||||
</wpf:ResourceDictionary>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Memory;
|
||||
using Elsa.Workflows.Models;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Activities;
|
||||
|
||||
public class TriggerSignal : CodeActivity
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[JsonConstructor]
|
||||
private TriggerSignal(string? source = default, int? line = default) : base(source, line)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(string eventName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new Literal<string>(eventName), source, line)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(Func<string> eventName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
|
||||
: this(Expression.DelegateExpression(eventName), source, line)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(Func<ExpressionExecutionContext, string?> eventName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
|
||||
: this(Expression.DelegateExpression(eventName), source, line)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(Variable<string> variable, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) => EventName = new Input<string>(variable);
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(Literal<string> literal, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) => EventName = new Input<string>(literal);
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(Expression expression, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) => EventName = new Input<string>(expression, new MemoryBlockReference());
|
||||
|
||||
/// <inheritdoc />
|
||||
public TriggerSignal(Input<string> eventName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) => EventName = eventName;
|
||||
|
||||
public Input<string> EventName { get; set; }
|
||||
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
var testEventManager = context.GetRequiredService<ISignalManager>();
|
||||
var eventName = EventName.Get(context);
|
||||
testEventManager.Trigger(eventName);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Elsa.Common.Models;
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Testing.Shared.Services;
|
||||
using Elsa.Workflows.ComponentTests.Helpers;
|
||||
|
|
@ -15,7 +15,7 @@ public class BulkDispatchWorkflowsTests : AppComponentTest
|
|||
private readonly WorkflowEvents _workflowEvents;
|
||||
private readonly SignalManager _signalManager;
|
||||
private readonly IWorkflowRuntime _workflowRuntime;
|
||||
private static readonly object ParentWorkflowCompletedSignal = new();
|
||||
private static readonly object GreetEmployeesWorkflowCompletedSignal = new();
|
||||
|
||||
public BulkDispatchWorkflowsTests(App app) : base(app)
|
||||
{
|
||||
|
|
@ -35,10 +35,22 @@ public class BulkDispatchWorkflowsTests : AppComponentTest
|
|||
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(GreetEmployeesWorkflow.DefinitionId, VersionOptions.Published)
|
||||
});
|
||||
await workflowClient.RunInstanceAsync(RunWorkflowInstanceRequest.Empty);
|
||||
var parentWorkflowInstanceArgs = await _signalManager.WaitAsync<WorkflowInstanceSavedEventArgs>(ParentWorkflowCompletedSignal);
|
||||
var parentWorkflowInstanceArgs = await _signalManager.WaitAsync<WorkflowInstanceSavedEventArgs>(GreetEmployeesWorkflowCompletedSignal);
|
||||
|
||||
Assert.Equal(WorkflowStatus.Finished, parentWorkflowInstanceArgs.WorkflowInstance.Status);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Individual items are sent as input to child workflows.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task DispatchWorkflows_ChildWorkflowsShouldReceiveCurrentItem()
|
||||
{
|
||||
await _workflowRuntime.StartWorkflowAsync(MixFruitsWorkflow.DefinitionId);
|
||||
await _signalManager.WaitAsync("Apple");
|
||||
await _signalManager.WaitAsync("Banana");
|
||||
await _signalManager.WaitAsync("Cherry");
|
||||
}
|
||||
|
||||
private void OnWorkflowInstanceSaved(object? sender, WorkflowInstanceSavedEventArgs e)
|
||||
{
|
||||
|
|
@ -46,7 +58,7 @@ public class BulkDispatchWorkflowsTests : AppComponentTest
|
|||
return;
|
||||
|
||||
if(e.WorkflowInstance.DefinitionId == GreetEmployeesWorkflow.DefinitionId)
|
||||
_signalManager.Trigger(ParentWorkflowCompletedSignal, e);
|
||||
_signalManager.Trigger(GreetEmployeesWorkflowCompletedSignal, e);
|
||||
}
|
||||
|
||||
protected override void OnDispose()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.ComponentTests.Activities;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Hangfire.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows.Workflows;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class FruitWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
var item = builder.WithInput<string>("Item");
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine(x => $"Mixing {x.GetInput<string>(item)}"),
|
||||
new TriggerSignal(x => x.GetInput<string>(item))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Contracts;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows.Workflows;
|
||||
|
||||
public class MixFruitsWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
var fruits = new[]
|
||||
{
|
||||
"Apple", "Banana", "Cherry"
|
||||
};
|
||||
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Runtime.Activities.BulkDispatchWorkflows
|
||||
{
|
||||
WorkflowDefinitionId = new(FruitWorkflow.DefinitionId),
|
||||
Items = new(fruits),
|
||||
WaitForCompletion = new(true)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue