Add project files.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.FlowJoins;
|
||||
|
||||
public class Tests(App app) : AppComponentTest(app)
|
||||
{
|
||||
// https://github.com/elsa-workflows/elsa-core/issues/5348
|
||||
[Fact]
|
||||
public async Task FlowchartWithSingleFlowJoin_ShouldExecuteSuccessfully()
|
||||
{
|
||||
var workflowRunner = Scope.ServiceProvider.GetRequiredService<IWorkflowRunner>();
|
||||
var result = await workflowRunner.RunAsync<SingleJoinWorkflow>();
|
||||
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowState.SubStatus);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using Elsa.Workflows.Activities.Flowchart.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.FlowJoins;
|
||||
|
||||
public class SingleJoinWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.Root = new Elsa.Workflows.Activities.Flowchart.Activities.Flowchart
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new FlowJoin()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using System.Net;
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
|
||||
using Elsa.Testing.Shared.Extensions;
|
||||
using Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Execute;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.BasicWorkflows;
|
||||
|
||||
public class HelloWorldTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Fact]
|
||||
public async Task HelloWorldWorkflow_ShouldReturnOk()
|
||||
{
|
||||
var client = WorkflowServer.CreateApiClient<IExecuteWorkflowApi>();
|
||||
using var response = await client.ExecuteAsync("1590068018aa4f0a");
|
||||
var model = await response.ReadAsJsonAsync<Response>(WorkflowServer.Services);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(WorkflowSubStatus.Finished, model.WorkflowState.SubStatus);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"id": "1590068018aa4f0a",
|
||||
"definitionId": "1590068018aa4f0a",
|
||||
"name": "Hello World",
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "969b0703a9379c3b",
|
||||
"nodeId": "Workflow1:969b0703a9379c3b",
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Hello World!"
|
||||
}
|
||||
},
|
||||
"id": "b039045bb7443e57",
|
||||
"nodeId": "Workflow1:969b0703a9379c3b:b039045bb7443e57",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -231.796875,
|
||||
"y": 269
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Testing.Shared.Services;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows.Workflows;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Messages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows;
|
||||
|
||||
public class BulkDispatchWorkflowsTests : AppComponentTest
|
||||
{
|
||||
private readonly SignalManager _signalManager;
|
||||
private readonly IWorkflowRuntime _workflowRuntime;
|
||||
|
||||
public BulkDispatchWorkflowsTests(App app) : base(app)
|
||||
{
|
||||
_workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
|
||||
_signalManager = Scope.ServiceProvider.GetRequiredService<SignalManager>();
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Dispatches and waits for child workflows to complete.
|
||||
// /// </summary>
|
||||
// [Fact(Skip = "This test is flaky and needs to be fixed.")]
|
||||
// public async Task DispatchAndWaitWorkflow_ShouldWaitForChildWorkflowToComplete()
|
||||
// {
|
||||
// var workflowClient = await _workflowRuntime.CreateClientAsync();
|
||||
// await workflowClient.CreateInstanceAsync(new CreateWorkflowInstanceRequest
|
||||
// {
|
||||
// WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(GreetEmployeesWorkflow.DefinitionId, VersionOptions.Published)
|
||||
// });
|
||||
// await workflowClient.RunInstanceAsync(RunWorkflowInstanceRequest.Empty);
|
||||
// await _signalManager.WaitAsync<string>("Completed");
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Individual items are sent as input to child workflows.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task DispatchWorkflows_ChildWorkflowsShouldReceiveCurrentItem()
|
||||
{
|
||||
var workflowClient = await _workflowRuntime.CreateClientAsync();
|
||||
var request = new CreateAndRunWorkflowInstanceRequest
|
||||
{
|
||||
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(MixFruitsWorkflow.DefinitionId, VersionOptions.Published)
|
||||
};
|
||||
await workflowClient.CreateAndRunInstanceAsync(request);
|
||||
|
||||
await _signalManager.WaitAsync("Apple");
|
||||
await _signalManager.WaitAsync("Banana");
|
||||
await _signalManager.WaitAsync("Cherry");
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Hangfire.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows.Workflows;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class EmployeeGreetingWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
var employeeName = builder.WithInput<string>("Employee");
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine(x => $"Hello {x.GetInput<string>(employeeName)}")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.ComponentTests.Activities;
|
||||
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))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Elsa.Testing.Shared.Activities;
|
||||
using Elsa.Workflows.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows.Workflows;
|
||||
|
||||
public class GreetEmployeesWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
var employeeNames = new[]
|
||||
{
|
||||
"Alice", "Bob", "Charlie"
|
||||
};
|
||||
|
||||
var inputEntries = employeeNames.Select(x => new Dictionary<string, object>
|
||||
{
|
||||
["Employee"] = x
|
||||
});
|
||||
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Runtime.Activities.BulkDispatchWorkflows
|
||||
{
|
||||
WorkflowDefinitionId = new(EmployeeGreetingWorkflow.DefinitionId),
|
||||
Items = new(inputEntries),
|
||||
WaitForCompletion = new(true)
|
||||
},
|
||||
new TriggerSignal("Completed")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
using Elsa.Workflows.Activities;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.CachingAndWorkflowDefinitionActivity;
|
||||
|
||||
// Tests the behavior of the WorkflowDefinitionActivity.
|
||||
// See https://github.com/elsa-workflows/elsa-core/issues/5314
|
||||
public class WorkflowDefinitionActivityTests : AppComponentTest
|
||||
{
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
private const string GrandChildDefinitionId = "29595e7b37a4836d";
|
||||
|
||||
private readonly IWorkflowDefinitionCacheManager _workflowDefinitionCacheManager;
|
||||
private readonly IWorkflowInstanceStore _workflowInstanceStore;
|
||||
private readonly HttpClient _httpWorkflowClient;
|
||||
|
||||
public WorkflowDefinitionActivityTests(App app, ITestOutputHelper testOutputHelper) : base(app)
|
||||
{
|
||||
_testOutputHelper = testOutputHelper;
|
||||
_httpWorkflowClient = WorkflowServer.CreateHttpWorkflowClient();
|
||||
_workflowDefinitionCacheManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
|
||||
_workflowInstanceStore = Scope.ServiceProvider.GetRequiredService<IWorkflowInstanceStore>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendHttpRequest_WhileEvictingCache_ShouldNotGenerateFaults()
|
||||
{
|
||||
var requestTasks = Enumerable.Range(0, 200).Select(SendRequestAsync).ToList();
|
||||
await Task.WhenAll(requestTasks);
|
||||
|
||||
var filter = new WorkflowInstanceFilter
|
||||
{
|
||||
WorkflowSubStatus = WorkflowSubStatus.Faulted
|
||||
};
|
||||
var faultedWorkflows = (await _workflowInstanceStore.FindManyAsync(filter)).ToList();
|
||||
var faultCount = faultedWorkflows.Count;
|
||||
|
||||
foreach (var faultedWorkflow in faultedWorkflows)
|
||||
foreach (var incident in faultedWorkflow.WorkflowState.Incidents)
|
||||
_testOutputHelper.WriteLine(incident.Message);
|
||||
|
||||
Assert.Equal(0, faultCount);
|
||||
}
|
||||
|
||||
private async Task SendRequestAsync(int index = 0)
|
||||
{
|
||||
var requestTask = _httpWorkflowClient.PostAsync("parent", new StringContent("{}"));
|
||||
var evictionTask = _workflowDefinitionCacheManager.EvictWorkflowDefinitionAsync(GrandChildDefinitionId);
|
||||
await Task.WhenAll(requestTask, evictionTask);
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"id": "26d186d68deb1250",
|
||||
"definitionId": "a3390d1f4c2594a8",
|
||||
"name": "Child",
|
||||
"createdAt": "2024-04-30T08:22:44.543407+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "e6c941b6f2292fcf",
|
||||
"nodeId": "Workflow2:e6c941b6f2292fcf",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"workflowDefinitionId": "29595e7b37a4836d",
|
||||
"workflowDefinitionVersionId": "f36dc264f14be3c6",
|
||||
"latestAvailablePublishedVersion": 1,
|
||||
"latestAvailablePublishedVersionId": "f36dc264f14be3c6",
|
||||
"id": "377b23f4235ec26d",
|
||||
"nodeId": "Workflow2:e6c941b6f2292fcf:377b23f4235ec26d",
|
||||
"name": "GrandChild1",
|
||||
"type": "GrandChild",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -193.95703125,
|
||||
"y": 23
|
||||
},
|
||||
"size": {
|
||||
"width": 115.1875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"id": "f36dc264f14be3c6",
|
||||
"definitionId": "29595e7b37a4836d",
|
||||
"name": "Grand Child",
|
||||
"createdAt": "2024-04-30T08:22:44.537237+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "29044d8e2ba192c0",
|
||||
"nodeId": "Workflow1:29044d8e2ba192c0",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Grand Child"
|
||||
}
|
||||
},
|
||||
"id": "fb00878500fde1d3",
|
||||
"nodeId": "Workflow1:29044d8e2ba192c0:fb00878500fde1d3",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -234.796875,
|
||||
"y": -191
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"id": "9178b94f961b1cf",
|
||||
"definitionId": "189be5173f90b1f6",
|
||||
"name": "Parent",
|
||||
"createdAt": "2024-04-30T08:42:17.838484+00:00",
|
||||
"version": 6,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "96f60810318a6a89",
|
||||
"nodeId": "Workflow3:96f60810318a6a89",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"path": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "parent"
|
||||
}
|
||||
},
|
||||
"supportedMethods": {
|
||||
"typeName": "String[]",
|
||||
"expression": {
|
||||
"type": "Object",
|
||||
"value": "[\u0022POST\u0022]"
|
||||
}
|
||||
},
|
||||
"authorize": {
|
||||
"typeName": "Boolean",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal"
|
||||
}
|
||||
},
|
||||
"requestTimeout": null,
|
||||
"requestSizeLimit": null,
|
||||
"fileSizeLimit": null,
|
||||
"allowedFileExtensions": null,
|
||||
"blockedFileExtensions": null,
|
||||
"allowedMimeTypes": null,
|
||||
"exposeRequestTooLargeOutcome": false,
|
||||
"exposeFileTooLargeOutcome": false,
|
||||
"exposeInvalidFileExtensionOutcome": false,
|
||||
"exposeInvalidFileMimeTypeOutcome": false,
|
||||
"parsedContent": null,
|
||||
"files": null,
|
||||
"routeData": null,
|
||||
"queryStringData": null,
|
||||
"headers": null,
|
||||
"result": null,
|
||||
"id": "7e20498ffc94dbc6",
|
||||
"nodeId": "Workflow3:96f60810318a6a89:7e20498ffc94dbc6",
|
||||
"name": "HttpEndpoint1",
|
||||
"type": "Elsa.HttpEndpoint",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": true,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -520,
|
||||
"y": -120
|
||||
},
|
||||
"size": {
|
||||
"width": 176.390625,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"workflowDefinitionId": "a3390d1f4c2594a8",
|
||||
"workflowDefinitionVersionId": "26d186d68deb1250",
|
||||
"latestAvailablePublishedVersion": 1,
|
||||
"latestAvailablePublishedVersionId": "26d186d68deb1250",
|
||||
"id": "ed6a03040f651906",
|
||||
"nodeId": "Workflow3:96f60810318a6a89:ed6a03040f651906",
|
||||
"name": "Child1",
|
||||
"type": "Child",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -236.5810546875,
|
||||
"y": -120
|
||||
},
|
||||
"size": {
|
||||
"width": 67.7734375,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "7e20498ffc94dbc6",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "ed6a03040f651906",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Models;
|
||||
using Elsa.Workflows.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.ClusteredHosting;
|
||||
|
||||
public class ActivityRegistrySyncTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
private readonly IServiceScope _pod1Scope = app.Cluster.Pod1.Services.CreateScope();
|
||||
private readonly IServiceScope _pod2Scope = app.Cluster.Pod2.Services.CreateScope();
|
||||
private readonly IServiceScope _pod3Scope = app.Cluster.Pod3.Services.CreateScope();
|
||||
|
||||
[Fact(Skip = "Not yet implemented")]
|
||||
public async Task ImportWorkflowActivity_ShouldUpdateOtherPods()
|
||||
{
|
||||
var pod1ActivityRegistry = _pod1Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
var pod2ActivityRegistry = _pod2Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
var pod3ActivityRegistry = _pod3Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
|
||||
var sub1Descriptor = pod1ActivityRegistry.Find("Sub");
|
||||
Assert.Null(sub1Descriptor);
|
||||
|
||||
var importer = _pod1Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionImporter>();
|
||||
var request = new SaveWorkflowDefinitionRequest
|
||||
{
|
||||
Model = new WorkflowDefinitionModel
|
||||
{
|
||||
Name = "Sub",
|
||||
DefinitionId = "Sub",
|
||||
Options = new WorkflowOptions
|
||||
{
|
||||
UsableAsActivity = true,
|
||||
AutoUpdateConsumingWorkflows = true
|
||||
}
|
||||
},
|
||||
Publish = true
|
||||
};
|
||||
await importer.ImportAsync(request);
|
||||
|
||||
sub1Descriptor = pod1ActivityRegistry.Find("Sub");
|
||||
Assert.NotNull(sub1Descriptor);
|
||||
|
||||
sub1Descriptor = pod2ActivityRegistry.Find("Sub");
|
||||
Assert.NotNull(sub1Descriptor);
|
||||
|
||||
sub1Descriptor = pod3ActivityRegistry.Find("Sub");
|
||||
Assert.NotNull(sub1Descriptor);
|
||||
}
|
||||
|
||||
protected override void OnDispose()
|
||||
{
|
||||
_pod1Scope.Dispose();
|
||||
_pod2Scope.Dispose();
|
||||
_pod3Scope.Dispose();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Testing.Shared.Services;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.ComponentTests.Scenarios.DispatchWorkflows.Workflows;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Messages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.DispatchWorkflows;
|
||||
|
||||
public class DispatchWorkflowsTests : AppComponentTest
|
||||
{
|
||||
private readonly SignalManager _signalManager;
|
||||
private readonly IWorkflowRuntime _workflowRuntime;
|
||||
|
||||
public DispatchWorkflowsTests(App app) : base(app)
|
||||
{
|
||||
_workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
|
||||
_signalManager = Scope.ServiceProvider.GetRequiredService<SignalManager>();
|
||||
}
|
||||
|
||||
[Fact (Skip = "This test is flaky and needs to be fixed.")]
|
||||
public async Task DispatchAndWaitWorkflow_ShouldWaitForChildWorkflowToComplete()
|
||||
{
|
||||
var workflowClient = await _workflowRuntime.CreateClientAsync();
|
||||
await workflowClient.CreateInstanceAsync(new CreateWorkflowInstanceRequest
|
||||
{
|
||||
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(DispatchAndWaitWorkflow.DefinitionId, VersionOptions.Published)
|
||||
});
|
||||
await workflowClient.RunInstanceAsync(RunWorkflowInstanceRequest.Empty);
|
||||
await _signalManager.WaitAsync<string>("Completed");
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using Elsa.Scheduling.Activities;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Hangfire.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.DispatchWorkflows.Workflows;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class ChildWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Delay(TimeSpan.FromMilliseconds(250)),
|
||||
new WriteLine("Hello from Child!")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using Elsa.Testing.Shared.Activities;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Runtime.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.DispatchWorkflows.Workflows;
|
||||
|
||||
public class DispatchAndWaitWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new DispatchWorkflow
|
||||
{
|
||||
WorkflowDefinitionId = new(ChildWorkflow.DefinitionId),
|
||||
WaitForCompletion = new (true)
|
||||
},
|
||||
new TriggerSignal("Completed")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.ComponentTests.Scenarios.ExecuteWorkflows.Workflows;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Messages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.ExecuteWorkflows;
|
||||
|
||||
public class ExecuteWorkflowsTests : AppComponentTest
|
||||
{
|
||||
private readonly IWorkflowRuntime _workflowRuntime;
|
||||
|
||||
public ExecuteWorkflowsTests(App app) : base(app)
|
||||
{
|
||||
_workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteWorkflow_ShouldExecuteWorkflow()
|
||||
{
|
||||
var workflowClient = await _workflowRuntime.CreateClientAsync();
|
||||
await workflowClient.CreateInstanceAsync(new CreateWorkflowInstanceRequest
|
||||
{
|
||||
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(MainWorkflow.DefinitionId, VersionOptions.Published)
|
||||
});
|
||||
await workflowClient.RunInstanceAsync(RunWorkflowInstanceRequest.Empty);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.ExecuteWorkflows.Workflows;
|
||||
|
||||
public class MainWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
var workflowResult = builder.WithVariable<ExecuteWorkflowResult>();
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new ExecuteWorkflow
|
||||
{
|
||||
WorkflowDefinitionId = new(SubroutineWorkflow.DefinitionId),
|
||||
Input = new(new Dictionary<string, object>
|
||||
{
|
||||
["Value"] = 21
|
||||
}),
|
||||
Result = new(workflowResult)
|
||||
},
|
||||
new WriteLine(context => $"Subroutine output: {JsonSerializer.Serialize(workflowResult.Get(context))}")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Management.Activities.SetOutput;
|
||||
using Hangfire.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.ExecuteWorkflows.Workflows;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class SubroutineWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
var valueInput = builder.WithInput<double>("Value");
|
||||
var output = builder.WithOutput<double>("Output");
|
||||
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine(context => $"Running subroutine on value {context.GetInput<double>(valueInput)}..."),
|
||||
new SetOutput
|
||||
{
|
||||
OutputName = new(output.Name),
|
||||
OutputValue = new(context => context.GetInput<double>(valueInput) * 2)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.HttpWorkflows;
|
||||
|
||||
public class HttpHelloWorldTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Fact]
|
||||
public async Task HelloWorldWorkflow_ShouldRespondWithHelloWorld()
|
||||
{
|
||||
var client = WorkflowServer.CreateHttpWorkflowClient();
|
||||
var response = await client.GetStringAsync("hello-world");
|
||||
Assert.Equal("Hello World!", response);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
using System.Net;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.HttpWorkflows;
|
||||
|
||||
public class ResumeSpecificHttpWorkflowInstanceTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("workflowInstanceId")]
|
||||
[InlineData("correlationId")]
|
||||
public async Task ResumingSpecificWorkflow_ShouldResumeSpecifiedWorkflow(string identifierKey)
|
||||
{
|
||||
var client = WorkflowServer.CreateHttpWorkflowClient();
|
||||
|
||||
// Start 3 instances.
|
||||
var workflowInstanceId1 = await StartWorkflowAsync(client, identifierKey);
|
||||
var workflowInstanceId2 = await StartWorkflowAsync(client, identifierKey);
|
||||
var workflowInstanceId3 = await StartWorkflowAsync(client, identifierKey);
|
||||
|
||||
// Resume the 2nd instance.
|
||||
var response = await ResumeWorkflowAsync(client, identifierKey, workflowInstanceId2);
|
||||
|
||||
// Response should be OK.
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
private async Task<string> StartWorkflowAsync(HttpClient client, string identifierKey)
|
||||
{
|
||||
var identityGenerator = Scope.ServiceProvider.GetRequiredService<IIdentityGenerator>();
|
||||
var identifierValue = identityGenerator.GenerateId();
|
||||
await client.GetStringAsync($"simple-http-api/start?{identifierKey}={identifierValue}");
|
||||
return identifierValue;
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> ResumeWorkflowAsync(HttpClient client, string identifierKey, string identifierValue)
|
||||
{
|
||||
return await client.GetAsync($"simple-http-api/resume?{identifierKey}={identifierValue}");
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.HttpWorkflows;
|
||||
|
||||
public class RouteDataTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Fact]
|
||||
public async Task RouteDataWorkflow_ShouldRespondWithRouteData()
|
||||
{
|
||||
var client = WorkflowServer.CreateHttpWorkflowClient();
|
||||
var response = await client.GetStringAsync("orders/42");
|
||||
Assert.Equal("42", response);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
using Elsa.Http;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.HttpWorkflows.Workflows;
|
||||
|
||||
public class RouteDataWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
var routeDataVariable = builder.WithVariable<IDictionary<string, object>>();
|
||||
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
[
|
||||
new HttpEndpoint
|
||||
{
|
||||
Path = new("orders/{id}"),
|
||||
SupportedMethods = new([HttpMethods.Get]),
|
||||
CanStartWorkflow = true,
|
||||
RouteData = new(routeDataVariable)
|
||||
},
|
||||
new WriteHttpResponse
|
||||
{
|
||||
Content = new(context => routeDataVariable.Get(context)!["id"].ToString()),
|
||||
ContentType = new("text/plain")
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
using Elsa.Http;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.HttpWorkflows.Workflows;
|
||||
|
||||
public class SimpleHttpApiWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
[
|
||||
new HttpEndpoint
|
||||
{
|
||||
Path = new("simple-http-api/start"),
|
||||
SupportedMethods = new([HttpMethods.Get]),
|
||||
CanStartWorkflow = true
|
||||
},
|
||||
new HttpEndpoint
|
||||
{
|
||||
Path = new("simple-http-api/resume"),
|
||||
SupportedMethods = new([HttpMethods.Get])
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"id": "a86a9f668817dcb6",
|
||||
"definitionId": "f926beb0afc8505e",
|
||||
"name": "HTTP Hello World",
|
||||
"createdAt": "2024-04-20T17:14:34.118307+00:00",
|
||||
"version": 2,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "95a12c8ee4e8c5fc",
|
||||
"nodeId": "Workflow1:95a12c8ee4e8c5fc",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"path": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "hello-world"
|
||||
}
|
||||
},
|
||||
"supportedMethods": {
|
||||
"typeName": "String[]",
|
||||
"expression": {
|
||||
"type": "Object",
|
||||
"value": "[\u0022GET\u0022]"
|
||||
}
|
||||
},
|
||||
"authorize": {
|
||||
"typeName": "Boolean",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal"
|
||||
}
|
||||
},
|
||||
"requestTimeout": null,
|
||||
"requestSizeLimit": null,
|
||||
"fileSizeLimit": null,
|
||||
"allowedFileExtensions": null,
|
||||
"blockedFileExtensions": null,
|
||||
"allowedMimeTypes": null,
|
||||
"exposeRequestTooLargeOutcome": false,
|
||||
"exposeFileTooLargeOutcome": false,
|
||||
"exposeInvalidFileExtensionOutcome": false,
|
||||
"exposeInvalidFileMimeTypeOutcome": false,
|
||||
"parsedContent": null,
|
||||
"files": null,
|
||||
"routeData": null,
|
||||
"queryStringData": null,
|
||||
"headers": null,
|
||||
"result": null,
|
||||
"id": "90c3d3b2ea1f6ddc",
|
||||
"nodeId": "Workflow1:95a12c8ee4e8c5fc:90c3d3b2ea1f6ddc",
|
||||
"name": "HttpEndpoint1",
|
||||
"type": "Elsa.HttpEndpoint",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": true,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -262.796875,
|
||||
"y": 264
|
||||
},
|
||||
"size": {
|
||||
"width": 176.390625,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"statusCode": {
|
||||
"typeName": "System.Net.HttpStatusCode, System.Net.Primitives",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "OK"
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Hello World!"
|
||||
}
|
||||
},
|
||||
"contentType": null,
|
||||
"responseHeaders": {
|
||||
"typeName": "Elsa.Http.Models.HttpHeaders, Elsa.Http",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "{}"
|
||||
}
|
||||
},
|
||||
"id": "3048105347912af5",
|
||||
"nodeId": "Workflow1:95a12c8ee4e8c5fc:3048105347912af5",
|
||||
"name": "WriteHttpResponse1",
|
||||
"type": "Elsa.WriteHttpResponse",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 35.203125,
|
||||
"y": 264
|
||||
},
|
||||
"size": {
|
||||
"width": 183.640625,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "90c3d3b2ea1f6ddc",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "3048105347912af5",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.InputOutput;
|
||||
|
||||
public class InputOutputTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Fact(DisplayName = "Input should be received by the Provider and should in turn be able to send it back to the Consumer.")]
|
||||
public async Task InputShouldBeOutput()
|
||||
{
|
||||
const string workflowDefinitionVersionId = "4e993ab1b3d4e4a1";
|
||||
var workflowDefinitionService = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionService>();
|
||||
var workflowInvoker = Scope.ServiceProvider.GetRequiredService<IWorkflowInvoker>();
|
||||
var variableManager = Scope.ServiceProvider.GetRequiredService<IWorkflowInstanceVariableManager>();
|
||||
var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(workflowDefinitionVersionId);
|
||||
var result = await workflowInvoker.InvokeAsync(workflowGraph!);
|
||||
var variables = await variableManager.GetVariablesAsync(result.WorkflowState.Id);
|
||||
var variableValue = variables.First().Value;
|
||||
|
||||
Assert.Equal("Hello World!", variableValue);
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"$schema": "https://elsaworkflows.io/schemas/workflow-definition/v3.0.0/schema.json",
|
||||
"id": "4e993ab1b3d4e4a1",
|
||||
"definitionId": "58dbd7bffa85a761",
|
||||
"name": "Consumer",
|
||||
"createdAt": "2024-12-04T16:49:20.593932\u002B00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.3.0.0",
|
||||
"variables": [
|
||||
{
|
||||
"id": "67fcb9870af4c28e",
|
||||
"name": "Variable1",
|
||||
"typeName": "String",
|
||||
"isArray": false,
|
||||
"value": "",
|
||||
"storageDriverTypeName": "Elsa.Workflows.WorkflowInstanceStorageDriver, Elsa.Workflows.Core"
|
||||
}
|
||||
],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"logPersistenceConfig": {
|
||||
"default": {
|
||||
"evaluationMode": "Strategy",
|
||||
"strategyType": "Elsa.Workflows.LogPersistence.Strategies.Inherit, Elsa.Workflows.Core",
|
||||
"expression": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"id": "938f2c91bb759a6a",
|
||||
"nodeId": "Workflow2:938f2c91bb759a6a",
|
||||
"name": "Flowchart1",
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {},
|
||||
"activities": [
|
||||
{
|
||||
"workflowDefinitionId": "780fbf96f1bb1e7e",
|
||||
"workflowDefinitionVersionId": "640867552fc865d",
|
||||
"latestAvailablePublishedVersion": 3,
|
||||
"latestAvailablePublishedVersionId": "640867552fc865d",
|
||||
"id": "8c1127e1193cd6e8",
|
||||
"nodeId": "Workflow2:938f2c91bb759a6a:8c1127e1193cd6e8",
|
||||
"name": "Output1",
|
||||
"type": "Provider",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -160,
|
||||
"y": -280
|
||||
},
|
||||
"size": {
|
||||
"width": 89.6953125,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
"input1": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Hello World!"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "8c1127e1193cd6e8:input-input-1"
|
||||
}
|
||||
},
|
||||
"output1": {
|
||||
"typeName": "Object",
|
||||
"memoryReference": {
|
||||
"id": "67fcb9870af4c28e"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"variables": [],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"$schema": "https://elsaworkflows.io/schemas/workflow-definition/v3.0.0/schema.json",
|
||||
"id": "5ba5a7e36d60549b",
|
||||
"definitionId": "780fbf96f1bb1e7e",
|
||||
"name": "Provider",
|
||||
"createdAt": "2024-12-04T16:22:39.064075\u002B00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.3.0.0",
|
||||
"variables": [],
|
||||
"inputs": [
|
||||
{
|
||||
"uiHint": "singleline",
|
||||
"storageDriverType": "Elsa.Workflows.WorkflowInstanceStorageDriver, Elsa.Workflows.Core",
|
||||
"type": "Object",
|
||||
"name": "Input1",
|
||||
"displayName": "Input 1",
|
||||
"description": "",
|
||||
"category": "Primitives",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Output1",
|
||||
"displayName": "Output 1",
|
||||
"description": "",
|
||||
"category": "Primitives",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"logPersistenceConfig": {
|
||||
"default": {
|
||||
"evaluationMode": "Strategy",
|
||||
"strategyType": "Elsa.Workflows.LogPersistence.Strategies.Inherit, Elsa.Workflows.Core",
|
||||
"expression": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": false,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"id": "85a5e1d9e487bfa4",
|
||||
"nodeId": "Workflow1:85a5e1d9e487bfa4",
|
||||
"name": "Flowchart1",
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {},
|
||||
"activities": [
|
||||
{
|
||||
"outputName": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Output1"
|
||||
}
|
||||
},
|
||||
"outputValue": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "return getInput1()"
|
||||
}
|
||||
},
|
||||
"id": "985eb3bfb8d4dd3f",
|
||||
"nodeId": "Workflow1:85a5e1d9e487bfa4:985eb3bfb8d4dd3f",
|
||||
"name": "SetOutput1",
|
||||
"type": "Elsa.SetOutput",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -380,
|
||||
"y": -220
|
||||
},
|
||||
"size": {
|
||||
"width": 107.3203125,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"variables": [],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.JavaScriptVariables;
|
||||
|
||||
public class JavaScriptVariablesWorkflow1 : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WithVariable("MagicNumber", 3).WithWorkflowStorage();
|
||||
builder.Root = new RunJavaScript("setMagicNumber(42)", null, null);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.JavaScriptVariables;
|
||||
|
||||
public class JavaScriptVariablesWorkflow2 : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WithVariable("MagicNumber", 3).WithWorkflowStorage();
|
||||
builder.Root = new RunJavaScript("variables.MagicNumber = 42", null, null);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.JavaScriptVariables;
|
||||
|
||||
public class JavaScriptVariablesWorkflow3 : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WithVariable("MagicNumber", 3).WithWorkflowStorage();
|
||||
builder.Root = new RunJavaScript("setVariable('MagicNumber', 42)", null, null);
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
using Elsa.Expressions.Helpers;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Messages;
|
||||
using Elsa.Workflows.State;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.JavaScriptVariables;
|
||||
|
||||
public class JavaScriptVariablesWorkflowTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Theory(DisplayName = "SetVariable JS function sets a variable and does not get overridden by variables API")]
|
||||
[MemberData(nameof(GetWorkflowDefinitions))]
|
||||
public async Task SetVariableRetainsValue(string workflowDefinitionId)
|
||||
{
|
||||
var workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
|
||||
var workflowInstanceStore = Scope.ServiceProvider.GetRequiredService<IWorkflowInstanceStore>();
|
||||
var workflowClient = await workflowRuntime.CreateClientAsync();
|
||||
var runAndCreateRequest = new CreateAndRunWorkflowInstanceRequest
|
||||
{
|
||||
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(workflowDefinitionId)
|
||||
};
|
||||
var runResponse = await workflowClient.CreateAndRunInstanceAsync(runAndCreateRequest);
|
||||
var workflowInstanceId = runResponse.WorkflowInstanceId;
|
||||
var workflowInstance = await workflowInstanceStore.FindAsync(workflowInstanceId);
|
||||
var workflowState = workflowInstance!.WorkflowState;
|
||||
var rootWorkflowActivityExecutionContext = workflowState.ActivityExecutionContexts.Single(x => x.ParentContextId == null);
|
||||
var variables = GetVariablesDictionary(rootWorkflowActivityExecutionContext);
|
||||
var magicNumber = variables["magicNumberVariable"].ConvertTo<int>();
|
||||
Assert.Equal(42, magicNumber);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetWorkflowDefinitions()
|
||||
{
|
||||
return
|
||||
[
|
||||
[JavaScriptVariablesWorkflow1.DefinitionId],
|
||||
[JavaScriptVariablesWorkflow2.DefinitionId],
|
||||
[JavaScriptVariablesWorkflow3.DefinitionId]
|
||||
];
|
||||
}
|
||||
|
||||
private VariablesDictionary GetVariablesDictionary(ActivityExecutionContextState context)
|
||||
{
|
||||
return context.Properties.GetOrAdd(WorkflowInstanceStorageDriver.VariablesDictionaryStateKey, () => new VariablesDictionary());
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Responses;
|
||||
using Elsa.Api.Client.Resources.WorkflowInstances.Models;
|
||||
using Elsa.Common.Entities;
|
||||
using Elsa.Testing.Shared.Extensions;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Helpers;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.OrderDefinitions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Open.Linq.AsyncExtensions;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.LogPersistenceModes;
|
||||
|
||||
public class InputOutputLoggingTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("input-output-logging-1", true, false, true, false)]
|
||||
[InlineData("input-output-logging-2", true, false, true, false)]
|
||||
public async Task Workflow_ShouldHonorSettings_WhenExecuting(string workflowDefinitionId, params bool[] shouldBeIncludedArray)
|
||||
{
|
||||
var workflowState = await ExecuteWorkflowAsync(workflowDefinitionId);
|
||||
var workflowInstanceId = workflowState.Id;
|
||||
var writeLineActivityTypeName = ActivityTypeNameHelper.GenerateTypeName<WriteLine>();
|
||||
var activityExecutionRecords = await GetActivityExecutionRecordsAsync(workflowInstanceId, x => x.ActivityType == writeLineActivityTypeName).ToList();
|
||||
|
||||
for (var i = 0; i < shouldBeIncludedArray.Length; i++)
|
||||
{
|
||||
var activityExecutionRecord = activityExecutionRecords[i];
|
||||
var shouldBeIncluded = shouldBeIncludedArray[i];
|
||||
var isIncluded = activityExecutionRecord.ActivityState?.ContainsKey(nameof(WriteLine.Text)) == true;
|
||||
Assert.Equal(shouldBeIncluded, isIncluded);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WorkflowAsActivity_ShouldHonorSettings_WhenExecuting()
|
||||
{
|
||||
await ExecuteWorkflowAsync("input-output-logging-3");
|
||||
var activityExecutionRecord = await GetRecordByActivityNameAsync("InputOutputLogging3-Child1");
|
||||
var output1IsIncluded = activityExecutionRecord.Outputs!.ContainsKey("Output1");
|
||||
var output2IsIncluded = activityExecutionRecord.Outputs!.ContainsKey("Output2");
|
||||
|
||||
Assert.True(output1IsIncluded);
|
||||
Assert.True(output2IsIncluded);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Although this functionality works in practice, the component test fails from time to time for no clear reason (yet).")]
|
||||
public async Task WorkflowAsActivityInternal_ShouldHonorSettings_WhenExecuting()
|
||||
{
|
||||
await ExecuteWorkflowAsync("input-output-logging-3");
|
||||
var setOutput1Record = await GetRecordByActivityNameAsync("SetOutput1");
|
||||
var setOutput2Record = await GetRecordByActivityNameAsync("SetOutput2");
|
||||
var output1IsIncluded = setOutput1Record.ActivityState?.ContainsKey("OutputName") == true;
|
||||
var output2IsIncluded = setOutput2Record.ActivityState?.ContainsKey("OutputName") == true;
|
||||
|
||||
Assert.False(output1IsIncluded);
|
||||
Assert.True(output2IsIncluded);
|
||||
}
|
||||
|
||||
private async Task<WorkflowState> ExecuteWorkflowAsync(string workflowDefinitionId)
|
||||
{
|
||||
var client = WorkflowServer.CreateApiClient<IExecuteWorkflowApi>();
|
||||
using var response = await client.ExecuteAsync(workflowDefinitionId);
|
||||
var model = await response.ReadAsJsonAsync<ExecuteWorkflowDefinitionResponse>(WorkflowServer.Services);
|
||||
return model.WorkflowState;
|
||||
}
|
||||
|
||||
private Task<IEnumerable<ActivityExecutionRecord>> GetActivityExecutionRecordsAsync(string workflowInstanceId, Func<ActivityExecutionRecord, bool> predicate)
|
||||
{
|
||||
var activityExecutionRecordFilter = new ActivityExecutionRecordFilter
|
||||
{
|
||||
WorkflowInstanceId = workflowInstanceId,
|
||||
};
|
||||
return GetActivityExecutionRecordsAsync(activityExecutionRecordFilter, predicate);
|
||||
}
|
||||
|
||||
private Task<ActivityExecutionRecord> GetRecordByActivityNameAsync(string name)
|
||||
{
|
||||
var filter = new ActivityExecutionRecordFilter
|
||||
{
|
||||
Name = name
|
||||
};
|
||||
return GetActivityExecutionRecordAsync(filter);
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ActivityExecutionRecord>> GetActivityExecutionRecordsAsync(ActivityExecutionRecordFilter filter, Func<ActivityExecutionRecord, bool>? predicate = null)
|
||||
{
|
||||
var activityExecutionStore = Scope.ServiceProvider.GetRequiredService<IActivityExecutionStore>();
|
||||
var orderBy = new ActivityExecutionRecordOrder<DateTimeOffset>(x => x.StartedAt, OrderDirection.Ascending);
|
||||
var activityExecutionRecords = await activityExecutionStore.FindManyAsync(filter, orderBy);
|
||||
return predicate == null ? activityExecutionRecords : activityExecutionRecords.Where(predicate);
|
||||
}
|
||||
|
||||
private async Task<ActivityExecutionRecord> GetActivityExecutionRecordAsync(ActivityExecutionRecordFilter filter)
|
||||
{
|
||||
var activityExecutionStore = Scope.ServiceProvider.GetRequiredService<IActivityExecutionStore>();
|
||||
var result = await activityExecutionStore.FindAsync(filter);
|
||||
|
||||
if(result == null)
|
||||
throw new InvalidOperationException($"Activity execution record not found.");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
{
|
||||
"id": "94f11e583299383b",
|
||||
"definitionId": "input-output-logging-1",
|
||||
"name": "Input Output Logging 1",
|
||||
"createdAt": "2024-04-21T11:34:17.423214+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "482993d55270a5e7",
|
||||
"nodeId": "Workflow1:482993d55270a5e7",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This input should be stored"
|
||||
}
|
||||
},
|
||||
"id": "ea21b3863867ebb3",
|
||||
"nodeId": "Workflow1:482993d55270a5e7:ea21b3863867ebb3",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -440,
|
||||
"y": -140
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This input should not be stored"
|
||||
}
|
||||
},
|
||||
"id": "4726389b3d516c40",
|
||||
"nodeId": "Workflow1:482993d55270a5e7:4726389b3d516c40",
|
||||
"name": "WriteLine2",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Exclude",
|
||||
"inputs": {
|
||||
"text": "Inherit"
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -220,
|
||||
"y": -140
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This input should be stored"
|
||||
}
|
||||
},
|
||||
"id": "e13b09839d4244b9",
|
||||
"nodeId": "Workflow1:482993d55270a5e7:e13b09839d4244b9",
|
||||
"name": "WriteLine3",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Exclude",
|
||||
"inputs": {
|
||||
"text": "Include"
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -16,
|
||||
"y": -140
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This input should not be stored"
|
||||
}
|
||||
},
|
||||
"id": "1ba2922db9052ce9",
|
||||
"nodeId": "Workflow1:482993d55270a5e7:1ba2922db9052ce9",
|
||||
"name": "WriteLine4",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Include",
|
||||
"inputs": {
|
||||
"text": "Exclude"
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 188,
|
||||
"y": -140
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "ea21b3863867ebb3",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "4726389b3d516c40",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "4726389b3d516c40",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "e13b09839d4244b9",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "e13b09839d4244b9",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "1ba2922db9052ce9",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
{
|
||||
"id": "a7499c4c7888fafb",
|
||||
"definitionId": "input-output-logging-2",
|
||||
"name": "Input Output Logging 2",
|
||||
"createdAt": "2024-04-21T11:39:57.182662+00:00",
|
||||
"version": 2,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": [],
|
||||
"logPersistenceMode": {
|
||||
"default": "Exclude"
|
||||
}
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "4dce3806d9c7af92",
|
||||
"nodeId": "Workflow1:4dce3806d9c7af92",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This should be logged"
|
||||
}
|
||||
},
|
||||
"id": "30d32d634c1ddbfa",
|
||||
"nodeId": "Workflow1:4dce3806d9c7af92:30d32d634c1ddbfa",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Include",
|
||||
"inputs": {
|
||||
"text": "Inherit"
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -380,
|
||||
"y": -120
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This should not be logged"
|
||||
}
|
||||
},
|
||||
"id": "50fcb804a7ace442",
|
||||
"nodeId": "Workflow1:4dce3806d9c7af92:50fcb804a7ace442",
|
||||
"name": "WriteLine2",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -156,
|
||||
"y": -120
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This should be logged"
|
||||
}
|
||||
},
|
||||
"id": "3f00f1de3ec2862b",
|
||||
"nodeId": "Workflow1:4dce3806d9c7af92:3f00f1de3ec2862b",
|
||||
"name": "WriteLine3",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Inherit",
|
||||
"inputs": {
|
||||
"text": "Include"
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 60,
|
||||
"y": -120
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "This should not be logged"
|
||||
}
|
||||
},
|
||||
"id": "3dcff307781b3707",
|
||||
"nodeId": "Workflow1:4dce3806d9c7af92:3dcff307781b3707",
|
||||
"name": "WriteLine4",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Inherit",
|
||||
"inputs": {
|
||||
"text": "Exclude"
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 264,
|
||||
"y": -120
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "3f00f1de3ec2862b",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "3dcff307781b3707",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "30d32d634c1ddbfa",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "50fcb804a7ace442",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "50fcb804a7ace442",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "3f00f1de3ec2862b",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"id": "4cf7c10c7a2901d6",
|
||||
"definitionId": "input-output-logging-3-child",
|
||||
"name": "Input Output Logging 3 - Child",
|
||||
"createdAt": "2024-04-22T13:11:07.146222+00:00",
|
||||
"version": 4,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Output1",
|
||||
"displayName": "Output 1",
|
||||
"category": "Primitives",
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Output2",
|
||||
"displayName": "Output 2",
|
||||
"category": "Primitives",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"logPersistenceMode": {
|
||||
"default": "Exclude"
|
||||
},
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "5f72efc9043753fa",
|
||||
"nodeId": "Workflow1:5f72efc9043753fa",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"outputName": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Output1"
|
||||
}
|
||||
},
|
||||
"outputValue": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Output value 1"
|
||||
}
|
||||
},
|
||||
"id": "402076f12c1220a9",
|
||||
"nodeId": "Workflow1:5f72efc9043753fa:402076f12c1220a9",
|
||||
"name": "SetOutput1",
|
||||
"type": "Elsa.SetOutput",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false,
|
||||
"logPersistenceMode": {
|
||||
"default": "Inherit",
|
||||
"inputs": {
|
||||
"outputName": "Inherit",
|
||||
"outputValue": "Inherit"
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -221.4757080078125,
|
||||
"y": 264.861083984375
|
||||
},
|
||||
"size": {
|
||||
"width": 107.734375,
|
||||
"height": 50.2256965637207
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"outputName": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Output2"
|
||||
}
|
||||
},
|
||||
"outputValue": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Output value 2"
|
||||
}
|
||||
},
|
||||
"id": "db1d1c02cbfac590",
|
||||
"nodeId": "Workflow1:5f72efc9043753fa:db1d1c02cbfac590",
|
||||
"name": "SetOutput2",
|
||||
"type": "Elsa.SetOutput",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false,
|
||||
"logPersistenceMode": {
|
||||
"default": "Inherit",
|
||||
"inputs": {
|
||||
"outputName": "Include",
|
||||
"outputValue": "Include"
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 58.5242919921875,
|
||||
"y": 264.861083984375
|
||||
},
|
||||
"size": {
|
||||
"width": 107.734375,
|
||||
"height": 50.2256965637207
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "402076f12c1220a9",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "db1d1c02cbfac590",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"id": "6da18530316aee2e",
|
||||
"definitionId": "input-output-logging-3",
|
||||
"name": "Input Output Logging 3",
|
||||
"createdAt": "2024-04-21T20:08:17.495551+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "9aec3fea5a39cccd",
|
||||
"nodeId": "Workflow2:9aec3fea5a39cccd",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"workflowDefinitionId": "input-output-logging-3-child",
|
||||
"workflowDefinitionVersionId": "4cf7c10c7a2901d6",
|
||||
"latestAvailablePublishedVersion": 4,
|
||||
"latestAvailablePublishedVersionId": "4cf7c10c7a2901d6",
|
||||
"id": "6bf4016d6074831f",
|
||||
"nodeId": "Workflow2:9aec3fea5a39cccd:6bf4016d6074831f",
|
||||
"name": "InputOutputLogging3-Child1",
|
||||
"type": "InputOutputLogging3-Child",
|
||||
"version": 4,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -360,
|
||||
"y": -320
|
||||
},
|
||||
"size": {
|
||||
"width": 246.375,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Multitenancy;
|
||||
|
||||
public class MultitenancyTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Fact(Skip = "Multitenancy disabled. This test doesn't work because not all workflows are assigned the Tenant1 tenant.")]
|
||||
public async Task LoadingWorkflows_ShouldReturnWorkflows_FromCurrentTenant()
|
||||
{
|
||||
var store = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionStore>();
|
||||
var filter = new WorkflowDefinitionFilter
|
||||
{
|
||||
IsSystem = false,
|
||||
VersionOptions = VersionOptions.Latest
|
||||
};
|
||||
var workflows = await store.FindManyAsync(filter);
|
||||
Assert.All(workflows, workflow => Assert.Equal("Tenant1", workflow.TenantId));
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using Elsa.Workflows.Activities;
|
||||
using Hangfire.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Multitenancy.Workflows;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class WorkflowForTenant1 : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WithTenantId("Tenant1");
|
||||
builder.Root = new WriteLine("Tenant1");
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using Elsa.Workflows.Activities;
|
||||
using Hangfire.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Multitenancy.Workflows;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class WorkflowForTenant2 : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WithTenantId("Tenant2");
|
||||
builder.Root = new WriteLine("Tenant2");
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
using Elsa.Extensions;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Variables.Activities;
|
||||
|
||||
public class CountdownStep : Activity
|
||||
{
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
var counter = context.GetVariable<int>("Counter");
|
||||
context.SetVariable("Counter", counter - 1);
|
||||
context?.CreateBookmark();
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Expressions.Helpers;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.ComponentTests.Scenarios.Variables.Workflows;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.Messages;
|
||||
using Elsa.Workflows.State;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Variables;
|
||||
|
||||
public class CountdownWorkflowTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Fact(DisplayName = "Variable is persisted across workflow runs")]
|
||||
public async Task VariableIsPersistedAcrossWorkflowRuns()
|
||||
{
|
||||
var workflowRuntime = Scope.ServiceProvider.GetRequiredService<IWorkflowRuntime>();
|
||||
var workflowClient = await workflowRuntime.CreateClientAsync();
|
||||
var workflowInstanceStore = Scope.ServiceProvider.GetRequiredService<IWorkflowInstanceStore>();
|
||||
var bookmarkStore = Scope.ServiceProvider.GetRequiredService<IBookmarkStore>();
|
||||
var runAndCreateRequest = new CreateAndRunWorkflowInstanceRequest
|
||||
{
|
||||
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(CountdownWorkflow.DefinitionId, VersionOptions.Latest),
|
||||
};
|
||||
var runResponse = await workflowClient.CreateAndRunInstanceAsync(runAndCreateRequest);
|
||||
var workflowInstanceId = runResponse.WorkflowInstanceId;
|
||||
var createdBookmarks = await bookmarkStore.FindManyAsync(new()
|
||||
{
|
||||
WorkflowInstanceId = workflowInstanceId
|
||||
});
|
||||
var bookmarks = new Stack<StoredBookmark>(createdBookmarks);
|
||||
var expectedCounter = 3;
|
||||
|
||||
while (bookmarks.Any())
|
||||
{
|
||||
var workflowInstance = await workflowInstanceStore.FindAsync(workflowInstanceId);
|
||||
var workflowState = workflowInstance!.WorkflowState;
|
||||
var rootWorkflowActivityExecutionContext = workflowState.ActivityExecutionContexts.Single(x => x.ParentContextId == null);
|
||||
var variables = GetVariablesDictionary(rootWorkflowActivityExecutionContext);
|
||||
var actualCounter = variables["counterVariable"].ConvertTo<int>();
|
||||
Assert.Equal(--expectedCounter, actualCounter);
|
||||
|
||||
var bookmark = bookmarks.Pop();
|
||||
var runRequest = new RunWorkflowInstanceRequest
|
||||
{
|
||||
BookmarkId = bookmark.Id,
|
||||
};
|
||||
|
||||
await workflowClient.RunInstanceAsync(runRequest);
|
||||
|
||||
createdBookmarks = await bookmarkStore.FindManyAsync(new()
|
||||
{
|
||||
WorkflowInstanceId = workflowInstanceId
|
||||
});
|
||||
|
||||
foreach (var newBookmark in createdBookmarks)
|
||||
bookmarks.Push(newBookmark);
|
||||
}
|
||||
}
|
||||
|
||||
private VariablesDictionary GetVariablesDictionary(ActivityExecutionContextState context)
|
||||
{
|
||||
return context.Properties.GetOrAdd(WorkflowInstanceStorageDriver.VariablesDictionaryStateKey, () => new VariablesDictionary());
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.ComponentTests.Scenarios.Variables.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.Variables.Workflows;
|
||||
|
||||
public class CountdownWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
var counter = builder.WithVariable("Counter", 3).WithWorkflowStorage();
|
||||
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new While(context => counter.Get(context) > 0)
|
||||
{
|
||||
Body = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine(context => $"Counter: {counter.Get(context)}"),
|
||||
new CountdownStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
using Elsa.Http;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Testing.Shared.Services;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Filters;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities;
|
||||
|
||||
public class AutoUpdateTests : AppComponentTest
|
||||
{
|
||||
private const string ParentDefinitionVersionId = "4b584e249fdca951";
|
||||
private const string ParentDefinitionId = "878770f04439a55d";
|
||||
private const string ChildDefinitionId = "f353742a9ef6af4";
|
||||
|
||||
private static readonly object HttpChangeTokenSignal = new();
|
||||
private static readonly object TriggerChangeTokenSignal = new();
|
||||
private static readonly object GraphChangeTokenSignal = new();
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly TriggerChangeTokenSignalEvents _changeTokenEvents;
|
||||
private readonly IWorkflowDefinitionCacheManager _definitionCacheManager;
|
||||
private readonly IHasher _hasher;
|
||||
private readonly IHttpWorkflowsCacheManager _httpCacheManager;
|
||||
private readonly IWorkflowDefinitionPublisher _publisher;
|
||||
private readonly SignalManager _signalManager;
|
||||
private readonly IWorkflowDefinitionCacheManager _workflowCacheManager;
|
||||
private string? _graphChangeToken;
|
||||
|
||||
private string? _httpChangeToken;
|
||||
private string? _triggerChangeToken;
|
||||
|
||||
public AutoUpdateTests(App app) : base(app)
|
||||
{
|
||||
_cache = Scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||
_hasher = Scope.ServiceProvider.GetRequiredService<IHasher>();
|
||||
_definitionCacheManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
|
||||
_publisher = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionPublisher>();
|
||||
|
||||
_httpCacheManager = Scope.ServiceProvider.GetRequiredService<IHttpWorkflowsCacheManager>();
|
||||
_workflowCacheManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
|
||||
|
||||
_signalManager = Scope.ServiceProvider.GetRequiredService<SignalManager>();
|
||||
_changeTokenEvents = Scope.ServiceProvider.GetRequiredService<TriggerChangeTokenSignalEvents>();
|
||||
_changeTokenEvents.ChangeTokenSignalTriggered += OnChangeTokenSignalTriggered;
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Updating a workflow with `auto update consuming workflows` should invalidate consuming workflows from cache")]
|
||||
public async Task UpdateWorkflowWithAutoUpdate()
|
||||
{
|
||||
// Run workflow to make sure the all required items for running the workflow are in the cache.
|
||||
var client = WorkflowServer.CreateHttpWorkflowClient();
|
||||
await client.GetStringAsync("test-cache-invalidation");
|
||||
|
||||
// Make sure the items are in the cache.
|
||||
var hash = _httpCacheManager.ComputeBookmarkHash("/test-cache-invalidation", "get");
|
||||
Assert.True(_cache.TryGetValue($"http-workflow:{hash}", out _));
|
||||
|
||||
var filter = new TriggerFilter
|
||||
{
|
||||
Hash = hash
|
||||
};
|
||||
var hashedFilter = _hasher.Hash(filter);
|
||||
Assert.True(_cache.TryGetValue($"IEnumerable`1:{hashedFilter}", out _));
|
||||
|
||||
var parentWorkflowDefinitionFilter = new WorkflowDefinitionFilter
|
||||
{
|
||||
Id = ParentDefinitionVersionId
|
||||
};
|
||||
var parentVersionCacheKey = _definitionCacheManager.CreateWorkflowFilterCacheKey(parentWorkflowDefinitionFilter);
|
||||
Assert.True(_cache.TryGetValue(parentVersionCacheKey, out _));
|
||||
|
||||
// Set change tokens.
|
||||
_httpChangeToken = _workflowCacheManager.CreateWorkflowDefinitionChangeTokenKey(ParentDefinitionId);
|
||||
_triggerChangeToken = _httpCacheManager.GetTriggerChangeTokenKey(hash);
|
||||
_graphChangeToken = _workflowCacheManager.CreateWorkflowDefinitionChangeTokenKey(ParentDefinitionId);
|
||||
|
||||
// (Act) Save the draft version of the child workflow and update the references.
|
||||
await _publisher.PublishAsync(ChildDefinitionId);
|
||||
|
||||
// Wait until the notifications for updating the cache have been send and check the cache.
|
||||
await _signalManager.WaitAsync<TriggerChangeTokenSignalEventArgs>(HttpChangeTokenSignal);
|
||||
await _signalManager.WaitAsync<TriggerChangeTokenSignalEventArgs>(TriggerChangeTokenSignal);
|
||||
await _signalManager.WaitAsync<TriggerChangeTokenSignalEventArgs>(GraphChangeTokenSignal);
|
||||
|
||||
Assert.False(_cache.TryGetValue($"http-workflow:{hash}", out _));
|
||||
Assert.False(_cache.TryGetValue($"IEnumerable`1:{hashedFilter}", out _));
|
||||
Assert.False(_cache.TryGetValue(parentVersionCacheKey, out _));
|
||||
}
|
||||
|
||||
private void OnChangeTokenSignalTriggered(object? sender, TriggerChangeTokenSignalEventArgs args)
|
||||
{
|
||||
if (args.Key == _httpChangeToken) _signalManager.Trigger(HttpChangeTokenSignal, args);
|
||||
if (args.Key == _triggerChangeToken) _signalManager.Trigger(TriggerChangeTokenSignal, args);
|
||||
if (args.Key == _graphChangeToken) _signalManager.Trigger(GraphChangeTokenSignal, args);
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Testing.Shared.Services;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities.Workflows;
|
||||
using Elsa.Workflows.Management;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities;
|
||||
|
||||
public class DeleteWorkflowTests : AppComponentTest
|
||||
{
|
||||
private static readonly object WorkflowDeletedSignal = new();
|
||||
private readonly IServiceScope _scope1;
|
||||
// private readonly IServiceScope _scope2;
|
||||
// private readonly IServiceScope _scope3;
|
||||
private readonly SignalManager _signalManager;
|
||||
private readonly WorkflowDefinitionEvents _workflowDefinitionEvents;
|
||||
|
||||
public DeleteWorkflowTests(App app) : base(app)
|
||||
{
|
||||
_scope1 = app.Cluster.Pod1.Services.CreateScope();
|
||||
// Disabled these scope creations since this prevents events from firing in other tests.
|
||||
// _scope2 = app.Cluster.Pod2.Services.CreateScope();
|
||||
// _scope3 = app.Cluster.Pod3.Services.CreateScope();
|
||||
_signalManager = Scope.ServiceProvider.GetRequiredService<SignalManager>();
|
||||
_workflowDefinitionEvents = Scope.ServiceProvider.GetRequiredService<WorkflowDefinitionEvents>();
|
||||
_workflowDefinitionEvents.WorkflowDefinitionDeleted += OnWorkflowDefinitionDeleted;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteWorkflow()
|
||||
{
|
||||
EnsureWorkflowInRegistry(_scope1, Workflows.DeleteWorkflow.Type);
|
||||
|
||||
var workflowDefinitionManager = _scope1.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
|
||||
await workflowDefinitionManager.DeleteByDefinitionIdAsync(Workflows.DeleteWorkflow.DefinitionId);
|
||||
|
||||
WorkflowTypeDeletedFromRegistry(_scope1, Workflows.DeleteWorkflow.Type);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Clustered tests are interfering with other event driven tests")]
|
||||
public async Task DeleteWorkflow_Clustered()
|
||||
{
|
||||
EnsureWorkflowInRegistry(_scope1, DeleteWorkflowClustered.Type);
|
||||
// EnsureWorkflowInRegistry(_scope2, DeleteWorkflowClustered.Type);
|
||||
// EnsureWorkflowInRegistry(_scope3, DeleteWorkflowClustered.Type);
|
||||
|
||||
var workflowDefinitionManager = _scope1.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
|
||||
await workflowDefinitionManager.DeleteByDefinitionIdAsync(DeleteWorkflowClustered.DefinitionId);
|
||||
|
||||
WorkflowTypeDeletedFromRegistry(_scope1, DeleteWorkflowClustered.Type);
|
||||
|
||||
await _signalManager.WaitAsync<WorkflowDefinitionDeletedEventArgs>(WorkflowDeletedSignal);
|
||||
// WorkflowTypeDeletedFromRegistry(_scope2, DeleteWorkflowClustered.Type);
|
||||
// WorkflowTypeDeletedFromRegistry(_scope3, DeleteWorkflowClustered.Type);
|
||||
}
|
||||
|
||||
private static void EnsureWorkflowInRegistry(IServiceScope scope, string type)
|
||||
{
|
||||
var activityRegistry = scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
var descriptor = activityRegistry.Find(type);
|
||||
Assert.NotNull(descriptor);
|
||||
}
|
||||
|
||||
private static void WorkflowTypeDeletedFromRegistry(IServiceScope scope, string type)
|
||||
{
|
||||
var activityRegistry = scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
var descriptor = activityRegistry.Find(type);
|
||||
|
||||
Assert.Null(descriptor);
|
||||
}
|
||||
|
||||
private void OnWorkflowDefinitionDeleted(object? sender, WorkflowDefinitionDeletedEventArgs args)
|
||||
{
|
||||
if (args.DefinitionId == Workflows.DeleteWorkflow.DefinitionId)
|
||||
_signalManager.Trigger(WorkflowDeletedSignal, args);
|
||||
}
|
||||
|
||||
protected override void OnDispose()
|
||||
{
|
||||
_workflowDefinitionEvents.WorkflowDefinitionDeleted -= OnWorkflowDefinitionDeleted;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
|
||||
using Elsa.Workflows.Management.Models;
|
||||
using Elsa.Workflows.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities;
|
||||
|
||||
public class SaveWorkflowTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Theory(DisplayName = "Saving workflows updates ActivityRegistry")]
|
||||
[InlineData("Save1", true, true, true, true)]
|
||||
[InlineData("Save2", true, false, false, false)]
|
||||
[InlineData("Save3", false, true, false, false)]
|
||||
[InlineData("Save4", false, false, false, false)]
|
||||
public async Task ActivityRegistry(string name, bool usableAsActivity, bool publish, bool expectedInRegistry, bool isBrowsable)
|
||||
{
|
||||
var activityRegistry = Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
|
||||
var descriptor = activityRegistry.Find(name);
|
||||
if (descriptor is not null)
|
||||
activityRegistry.Remove(typeof(WorkflowDefinitionActivityProvider), descriptor);
|
||||
|
||||
var importer = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionImporter>();
|
||||
var request = new SaveWorkflowDefinitionRequest
|
||||
{
|
||||
Model = new WorkflowDefinitionModel
|
||||
{
|
||||
Name = name,
|
||||
DefinitionId = name,
|
||||
Options = new WorkflowOptions
|
||||
{
|
||||
UsableAsActivity = usableAsActivity,
|
||||
AutoUpdateConsumingWorkflows = true
|
||||
}
|
||||
},
|
||||
Publish = publish
|
||||
};
|
||||
await importer.ImportAsync(request);
|
||||
|
||||
descriptor = activityRegistry.Find(name);
|
||||
|
||||
if (expectedInRegistry)
|
||||
{
|
||||
Assert.NotNull(descriptor);
|
||||
Assert.Equal(isBrowsable, descriptor.IsBrowsable);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Null(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"id": "23d18a46dc3000fd",
|
||||
"definitionId": "f353742a9ef6af4",
|
||||
"name": "CacheInvalidation_Child",
|
||||
"createdAt": "2024-05-28T08:10:31.5429337+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "5d146ccb42668b6b",
|
||||
"nodeId": "Workflow1:5d146ccb42668b6b",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"correlationId": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Child version 1"
|
||||
}
|
||||
},
|
||||
"id": "d719079757f5d1bf",
|
||||
"nodeId": "Workflow1:5d146ccb42668b6b:d719079757f5d1bf",
|
||||
"name": "Correlate1",
|
||||
"type": "Elsa.Correlate",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -127.40211486816406,
|
||||
"y": 526.2000122070312
|
||||
},
|
||||
"size": {
|
||||
"width": 132.7375030517578,
|
||||
"height": 49.60000228881836
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"id": "3da9c310a071ac7b",
|
||||
"definitionId": "f353742a9ef6af4",
|
||||
"name": "CacheInvalidation_Child",
|
||||
"createdAt": "2024-05-28T11:00:47.8186457+00:00",
|
||||
"version": 2,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": false,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "5d146ccb42668b6b",
|
||||
"nodeId": "Workflow1:5d146ccb42668b6b",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"correlationId": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Child version 2"
|
||||
}
|
||||
},
|
||||
"id": "d719079757f5d1bf",
|
||||
"nodeId": "Workflow1:5d146ccb42668b6b:d719079757f5d1bf",
|
||||
"name": "Correlate1",
|
||||
"type": "Elsa.Correlate",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -127.40211486816406,
|
||||
"y": 526.2000122070312
|
||||
},
|
||||
"size": {
|
||||
"width": 132.7375030517578,
|
||||
"height": 49.60000228881836
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"id": "4b584e249fdca951",
|
||||
"definitionId": "878770f04439a55d",
|
||||
"name": "CacheInvalidation_Parent",
|
||||
"createdAt": "2024-05-28T08:11:06.1123531+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [
|
||||
{
|
||||
"id": "47ab4de953db266",
|
||||
"name": "CorrId",
|
||||
"typeName": "String",
|
||||
"isArray": false,
|
||||
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
|
||||
}
|
||||
],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "76f03074bbc8cff3",
|
||||
"nodeId": "Workflow2:76f03074bbc8cff3",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"workflowDefinitionId": "f353742a9ef6af4",
|
||||
"workflowDefinitionVersionId": "23d18a46dc3000fd",
|
||||
"latestAvailablePublishedVersion": 1,
|
||||
"latestAvailablePublishedVersionId": "23d18a46dc3000fd",
|
||||
"id": "b8fe7116016141f",
|
||||
"nodeId": "Workflow2:76f03074bbc8cff3:b8fe7116016141f",
|
||||
"name": "CacheInvalidationChild1",
|
||||
"type": "CacheInvalidationChild",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -40,
|
||||
"y": 320
|
||||
},
|
||||
"size": {
|
||||
"width": 203.9499969482422,
|
||||
"height": 49.60000228881836
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Parent version 1"
|
||||
}
|
||||
},
|
||||
"id": "ad9ee49c807b852e",
|
||||
"nodeId": "Workflow2:76f03074bbc8cff3:ad9ee49c807b852e",
|
||||
"name": "SetName1",
|
||||
"type": "Elsa.SetName",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -303.3261413574219,
|
||||
"y": 320
|
||||
},
|
||||
"size": {
|
||||
"width": 137.6354217529297,
|
||||
"height": 49.60000228881836
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "test-cache-invalidation"
|
||||
}
|
||||
},
|
||||
"supportedMethods": {
|
||||
"typeName": "String[]",
|
||||
"expression": {
|
||||
"type": "Object",
|
||||
"value": "[\u0022GET\u0022]"
|
||||
}
|
||||
},
|
||||
"authorize": {
|
||||
"typeName": "Boolean",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal"
|
||||
}
|
||||
},
|
||||
"requestTimeout": null,
|
||||
"requestSizeLimit": null,
|
||||
"fileSizeLimit": null,
|
||||
"allowedFileExtensions": null,
|
||||
"blockedFileExtensions": null,
|
||||
"allowedMimeTypes": null,
|
||||
"exposeRequestTooLargeOutcome": false,
|
||||
"exposeFileTooLargeOutcome": false,
|
||||
"exposeInvalidFileExtensionOutcome": false,
|
||||
"exposeInvalidFileMimeTypeOutcome": false,
|
||||
"parsedContent": null,
|
||||
"files": null,
|
||||
"routeData": null,
|
||||
"queryStringData": null,
|
||||
"headers": null,
|
||||
"result": null,
|
||||
"id": "109b9c25e55375ba",
|
||||
"nodeId": "Workflow2:76f03074bbc8cff3:109b9c25e55375ba",
|
||||
"name": "HttpEndpoint1",
|
||||
"type": "Elsa.HttpEndpoint",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": true,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -622.4391784667969,
|
||||
"y": 320
|
||||
},
|
||||
"size": {
|
||||
"width": 176.0625,
|
||||
"height": 49.60000228881836
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "ad9ee49c807b852e",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "b8fe7116016141f",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "109b9c25e55375ba",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "ad9ee49c807b852e",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using Elsa.Scheduling.Activities;
|
||||
using Elsa.Workflows.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities.Workflows;
|
||||
|
||||
public class DeleteWorkflow : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
public static readonly string Type = nameof(DeleteWorkflow);
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.Name = Type;
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WorkflowOptions.UsableAsActivity = true;
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Delay(TimeSpan.FromMilliseconds(250)),
|
||||
new WriteLine("This workflow will be deleted!")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using Elsa.Scheduling.Activities;
|
||||
using Elsa.Workflows.Activities;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities.Workflows;
|
||||
|
||||
public class DeleteWorkflowClustered : WorkflowBase
|
||||
{
|
||||
public static readonly string DefinitionId = Guid.NewGuid().ToString();
|
||||
public static readonly string Type = nameof(DeleteWorkflowClustered);
|
||||
|
||||
protected override void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder.Name = Type;
|
||||
builder.WithDefinitionId(DefinitionId);
|
||||
builder.WorkflowOptions.UsableAsActivity = true;
|
||||
builder.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Delay(TimeSpan.FromMilliseconds(250)),
|
||||
new WriteLine("This workflow will be deleted!")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using System.Net;
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
|
||||
using Elsa.Testing.Shared.Extensions;
|
||||
using Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Execute;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowCompletion;
|
||||
|
||||
public class WorkflowCompletionTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("2630068018ac1f0a")]
|
||||
[InlineData("5590069018aa4f0e")]
|
||||
public async Task Workflow_ShouldComplete(string workflowDefinitionId)
|
||||
{
|
||||
var client = WorkflowServer.CreateApiClient<IExecuteWorkflowApi>();
|
||||
using var response = await client.ExecuteAsync(workflowDefinitionId);
|
||||
var model = await response.ReadAsJsonAsync<Response>(WorkflowServer.Services);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(WorkflowSubStatus.Finished, model.WorkflowState.SubStatus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"id": "5590069018aa4f0e",
|
||||
"definitionId": "5590069018aa4f0e",
|
||||
"name": "Fork",
|
||||
"createdAt": "2024-04-20T20:52:32.29327+00:00",
|
||||
"version": 2,
|
||||
"toolVersion": "3.2.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "c74056c7f1f4a3",
|
||||
"nodeId": "Workflow1:c74056c7f1f4a3",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"branches": {
|
||||
"typeName": "String[]",
|
||||
"expression": {
|
||||
"type": "Object",
|
||||
"value": "[\u0022One\u0022,\u0022Two\u0022,\u0022Three\u0022]"
|
||||
}
|
||||
},
|
||||
"id": "c0e09e3ac3cfdba7",
|
||||
"nodeId": "Workflow1:c74056c7f1f4a3:c0e09e3ac3cfdba7",
|
||||
"name": "FlowFork1",
|
||||
"type": "Elsa.FlowFork",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -340,
|
||||
"y": -197
|
||||
},
|
||||
"size": {
|
||||
"width": 145.5625,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "One"
|
||||
}
|
||||
},
|
||||
"id": "e6f0cddb1cdbdd7c",
|
||||
"nodeId": "Workflow1:c74056c7f1f4a3:e6f0cddb1cdbdd7c",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -80,
|
||||
"y": -300
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Two"
|
||||
}
|
||||
},
|
||||
"id": "3ece093dfc20c752",
|
||||
"nodeId": "Workflow1:c74056c7f1f4a3:3ece093dfc20c752",
|
||||
"name": "WriteLine2",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -80,
|
||||
"y": -197
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Three"
|
||||
}
|
||||
},
|
||||
"id": "ca9fcd1d6069df9",
|
||||
"nodeId": "Workflow1:c74056c7f1f4a3:ca9fcd1d6069df9",
|
||||
"name": "WriteLine3",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -80,
|
||||
"y": -102
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "c0e09e3ac3cfdba7",
|
||||
"port": "One"
|
||||
},
|
||||
"target": {
|
||||
"activity": "e6f0cddb1cdbdd7c",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "c0e09e3ac3cfdba7",
|
||||
"port": "Two"
|
||||
},
|
||||
"target": {
|
||||
"activity": "3ece093dfc20c752",
|
||||
"port": "In"
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"activity": "c0e09e3ac3cfdba7",
|
||||
"port": "Three"
|
||||
},
|
||||
"target": {
|
||||
"activity": "ca9fcd1d6069df9",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"id": "2630068018ac1f0a",
|
||||
"definitionId": "2630068018ac1f0a",
|
||||
"name": "Hello World",
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "969b0703a9379c3b",
|
||||
"nodeId": "Workflow1:969b0703a9379c3b",
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Hello World!"
|
||||
}
|
||||
},
|
||||
"id": "b039045bb7443e57",
|
||||
"nodeId": "Workflow1:969b0703a9379c3b:b039045bb7443e57",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -231.796875,
|
||||
"y": 269
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
using System.Net;
|
||||
using Elsa.Testing.Shared.Services;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowDefinitionRefresh;
|
||||
|
||||
public class DynamicEndpointTests : AppComponentTest
|
||||
{
|
||||
private readonly IWorkflowDefinitionsRefresher _workflowDefinitionsRefresher;
|
||||
|
||||
public DynamicEndpointTests(App app) : base(app)
|
||||
{
|
||||
StaticValueHolder.Value = "first-value";
|
||||
_workflowDefinitionsRefresher = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionsRefresher>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ChangingEndpointValueThenRefresh_WorkflowShouldRespondToTheNewValue()
|
||||
{
|
||||
var client = WorkflowServer.CreateHttpWorkflowClient();
|
||||
|
||||
var firstResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "first-value"));
|
||||
|
||||
StaticValueHolder.Value = "second-value";
|
||||
var _ = await _workflowDefinitionsRefresher.RefreshWorkflowDefinitionsAsync(
|
||||
new Runtime.Requests.RefreshWorkflowDefinitionsRequest() { DefinitionIds = ["f69f061159adc3ae"] }, CancellationToken.None);
|
||||
|
||||
var secondResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "second-value"));
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, firstResponse.StatusCode);
|
||||
Assert.Equal(HttpStatusCode.OK, secondResponse.StatusCode);
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"id": "69cb6deaa8e20599",
|
||||
"definitionId": "f69f061159adc3ae",
|
||||
"name": "Workflow 1",
|
||||
"createdAt": "2024-07-04T13:41:33.1905134+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.3.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "1bac532ee993dfdc",
|
||||
"nodeId": "Workflow1:1bac532ee993dfdc",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"path": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "return getStaticValue() ?? \u0022first-value\u0022;"
|
||||
}
|
||||
},
|
||||
"supportedMethods": {
|
||||
"typeName": "String[]",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "[\u0022GET\u0022]"
|
||||
}
|
||||
},
|
||||
"authorize": {
|
||||
"typeName": "Boolean",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal"
|
||||
}
|
||||
},
|
||||
"requestTimeout": null,
|
||||
"requestSizeLimit": null,
|
||||
"fileSizeLimit": null,
|
||||
"allowedFileExtensions": null,
|
||||
"blockedFileExtensions": null,
|
||||
"allowedMimeTypes": null,
|
||||
"exposeRequestTooLargeOutcome": false,
|
||||
"exposeFileTooLargeOutcome": false,
|
||||
"exposeInvalidFileExtensionOutcome": false,
|
||||
"exposeInvalidFileMimeTypeOutcome": false,
|
||||
"parsedContent": null,
|
||||
"files": null,
|
||||
"routeData": null,
|
||||
"queryStringData": null,
|
||||
"headers": null,
|
||||
"result": null,
|
||||
"id": "25d3a6465094a796",
|
||||
"nodeId": "Workflow1:1bac532ee993dfdc:25d3a6465094a796",
|
||||
"name": "HttpEndpoint1",
|
||||
"type": "Elsa.HttpEndpoint",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": true,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -260,
|
||||
"y": 460
|
||||
},
|
||||
"size": {
|
||||
"width": 176.390625,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
using System.Net;
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
using Elsa.Workflows.ComponentTests.Materializers;
|
||||
using Elsa.Workflows.ComponentTests.WorkflowProviders;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Humanizer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowDefinitionReload;
|
||||
|
||||
public class ReloadWorkflowTests : AppComponentTest
|
||||
{
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly TestWorkflowProvider _testWorkflowProvider;
|
||||
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
|
||||
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
|
||||
private readonly IWorkflowDefinitionService _workflowDefinitionService;
|
||||
private readonly IWorkflowDefinitionsReloader _workflowDefinitionsReloader;
|
||||
|
||||
public ReloadWorkflowTests(App app) : base(app)
|
||||
{
|
||||
_workflowDefinitionManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
|
||||
_workflowDefinitionsReloader = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionsReloader>();
|
||||
_workflowBuilderFactory = Scope.ServiceProvider.GetRequiredService<IWorkflowBuilderFactory>();
|
||||
_workflowDefinitionService = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionService>();
|
||||
_activityRegistry = Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
|
||||
var workflowsProviders = Scope.ServiceProvider.GetRequiredService<IEnumerable<IWorkflowsProvider>>();
|
||||
_testWorkflowProvider = (TestWorkflowProvider)workflowsProviders.First(x => x is TestWorkflowProvider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Reloading_AfterRemovingTheWorkflow_ShouldMakeWorkflowReachableAgain()
|
||||
{
|
||||
var client = WorkflowServer.CreateHttpWorkflowClient();
|
||||
await _workflowDefinitionManager.DeleteByDefinitionIdAsync("f68b09bc-2013-4617-b82f-d76b6819a624", CancellationToken.None);
|
||||
var firstResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "reload-test"));
|
||||
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
|
||||
var secondResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "reload-test"));
|
||||
Assert.Equal(HttpStatusCode.NotFound, firstResponse.StatusCode);
|
||||
Assert.Equal(HttpStatusCode.OK, secondResponse.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Reloading_AfterUpdatingSourceProvider_ShouldRefreshCaches()
|
||||
{
|
||||
var definitionId = Guid.NewGuid().ToString();
|
||||
var definitionVersionId1 = Guid.NewGuid().ToString();
|
||||
var workflowV1 = await BuildWorkflowAsync(definitionId, definitionVersionId1, 1);
|
||||
|
||||
// Set up the initial workflow version.
|
||||
_testWorkflowProvider.MaterializedWorkflows = [workflowV1];
|
||||
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
|
||||
var definitionV1 = await _workflowDefinitionService.FindWorkflowGraphAsync(definitionId, VersionOptions.Latest);
|
||||
Assert.Equal(definitionVersionId1, definitionV1!.Workflow.Identity.Id);
|
||||
|
||||
// Simulate the workflow provider to have a new version available.
|
||||
var definitionVersionId2 = Guid.NewGuid().ToString();
|
||||
var workflowV2 = await BuildWorkflowAsync(definitionId, definitionVersionId2, 2);
|
||||
_testWorkflowProvider.MaterializedWorkflows = [workflowV1, workflowV2];
|
||||
|
||||
// Reload the workflow definitions.
|
||||
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
|
||||
|
||||
// Assert that the workflow definition service finds the updated workflow version.
|
||||
var definitionV2 = await _workflowDefinitionService.FindWorkflowGraphAsync(definitionId, VersionOptions.Latest);
|
||||
Assert.Equal(definitionVersionId2, definitionV2!.Workflow.Identity.Id);
|
||||
|
||||
// Cleanup: Delete the workflow definition and its versions.
|
||||
await _workflowDefinitionManager.DeleteByDefinitionIdAsync(definitionId, CancellationToken.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Reloading_AfterUpdatingSourceProvider_ShouldRefreshActivityRegistry()
|
||||
{
|
||||
var definitionId = Guid.NewGuid().ToString();
|
||||
var definitionVersionId1 = Guid.NewGuid().ToString();
|
||||
var workflowV1 = await BuildWorkflowAsync(definitionId, definitionVersionId1, 1);
|
||||
|
||||
// Set up the initial workflow version.
|
||||
_testWorkflowProvider.MaterializedWorkflows = [workflowV1];
|
||||
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
|
||||
var activityTypeName = workflowV1.Workflow.Name.Pascalize();
|
||||
var activityV1 = _activityRegistry.Find(activityTypeName);
|
||||
Assert.Equal(1, activityV1!.Version);
|
||||
|
||||
// Simulate the workflow provider to have a new version available.
|
||||
var definitionVersionId2 = Guid.NewGuid().ToString();
|
||||
var workflowV2 = await BuildWorkflowAsync(definitionId, definitionVersionId2, 2);
|
||||
_testWorkflowProvider.MaterializedWorkflows = [workflowV1, workflowV2];
|
||||
|
||||
// Reload the workflow definitions.
|
||||
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
|
||||
|
||||
// Assert that the activity registry contains a new activity descriptor representing the new workflow version.
|
||||
var activityV2 = _activityRegistry.Find(activityTypeName)!;
|
||||
Assert.Equal(2, activityV2.Version);
|
||||
|
||||
// Cleanup: Delete the workflow definition and its versions.
|
||||
await _workflowDefinitionManager.DeleteByDefinitionIdAsync(definitionId, CancellationToken.None);
|
||||
}
|
||||
|
||||
private async Task<MaterializedWorkflow> BuildWorkflowAsync(string definitionId, string definitionVersionId, int version)
|
||||
{
|
||||
var builder = _workflowBuilderFactory.CreateBuilder();
|
||||
builder.DefinitionId = definitionId;
|
||||
builder.Id = definitionVersionId;
|
||||
builder.Version = version;
|
||||
builder.Name = definitionId;
|
||||
builder.Root = new WriteLine($"Version {version}");
|
||||
builder.WorkflowOptions.UsableAsActivity = true;
|
||||
var workflow = await builder.BuildWorkflowAsync();
|
||||
workflow.Name = definitionId;
|
||||
return new MaterializedWorkflow(workflow, _testWorkflowProvider.Name, TestWorkflowMaterializer.MaterializerName);
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"id": "c2e19917-d03e-41ed-9d19-ef5c1ddc9871",
|
||||
"definitionId": "f68b09bc-2013-4617-b82f-d76b6819a624",
|
||||
"name": "Workflow 1",
|
||||
"createdAt": "2024-07-04T13:41:33.1905134+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.3.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "f8019bae-c506-4467-812b-e403e7aad8ff",
|
||||
"nodeId": "Workflow1:f8019bae-c506-4467-812b-e403e7aad8ff",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"path": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "reload-test"
|
||||
}
|
||||
},
|
||||
"supportedMethods": {
|
||||
"typeName": "String[]",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "[\u0022GET\u0022]"
|
||||
}
|
||||
},
|
||||
"authorize": {
|
||||
"typeName": "Boolean",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal"
|
||||
}
|
||||
},
|
||||
"requestTimeout": null,
|
||||
"requestSizeLimit": null,
|
||||
"fileSizeLimit": null,
|
||||
"allowedFileExtensions": null,
|
||||
"blockedFileExtensions": null,
|
||||
"allowedMimeTypes": null,
|
||||
"exposeRequestTooLargeOutcome": false,
|
||||
"exposeFileTooLargeOutcome": false,
|
||||
"exposeInvalidFileExtensionOutcome": false,
|
||||
"exposeInvalidFileMimeTypeOutcome": false,
|
||||
"parsedContent": null,
|
||||
"files": null,
|
||||
"routeData": null,
|
||||
"queryStringData": null,
|
||||
"headers": null,
|
||||
"result": null,
|
||||
"id": "cc196a5e-04f7-4794-b25c-1a0987632d8a",
|
||||
"nodeId": "Workflow1:f8019bae-c506-4467-812b-e403e7aad8ff:cc196a5e-04f7-4794-b25c-1a0987632d8a",
|
||||
"name": "HttpEndpoint1",
|
||||
"type": "Elsa.HttpEndpoint",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": true,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -260,
|
||||
"y": 460
|
||||
},
|
||||
"size": {
|
||||
"width": 176.390625,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
|
||||
using Elsa.Workflows.ComponentTests.Abstractions;
|
||||
using Elsa.Workflows.ComponentTests.Fixtures;
|
||||
|
||||
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowJsonStructures;
|
||||
|
||||
public class WorkflowJsonStructureTests(App app) : AppComponentTest(app)
|
||||
{
|
||||
private const string MainDefinitionId = "a417fadbbb7c417e";
|
||||
private const string Sub1NodeId = "Workflow2:4d5af7585eece1d7:f19ae76011a020f3";
|
||||
|
||||
[Fact]
|
||||
public async Task Workflow_ContainingWorkflowActivity_ShouldNotIncludeChildrenOfWorkflowActivity()
|
||||
{
|
||||
var client = WorkflowServer.CreateApiClient<IWorkflowDefinitionsApi>();
|
||||
var workflowDefinition = (await client.GetByIdAsync(MainDefinitionId))!;
|
||||
var root = workflowDefinition.Root;
|
||||
var subActivity = root["activities"]![0]!;
|
||||
|
||||
Assert.Null(subActivity["root"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Requesting_Subgraph_Returns_ExpectedSubgraph()
|
||||
{
|
||||
var client = WorkflowServer.CreateApiClient<IWorkflowDefinitionsApi>();
|
||||
var subgraph = (await client.GetSubgraphAsync(MainDefinitionId, Sub1NodeId))!;
|
||||
Assert.Equal(Sub1NodeId, subgraph.Activity["nodeId"]!.ToString());
|
||||
var writeLine = subgraph.Activity["root"]!["root"]!["activities"]![0]!;
|
||||
Assert.Equal("Elsa.WriteLine", writeLine["type"]!.ToString());
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"id": "a417fadbbb7c417e",
|
||||
"definitionId": "ebe87d0f1d1924ea",
|
||||
"name": "Main",
|
||||
"createdAt": "2024-06-20T15:08:33.469865+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.3.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "4d5af7585eece1d7",
|
||||
"nodeId": "Workflow2:4d5af7585eece1d7",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"workflowDefinitionId": "497be45e7d647e8f",
|
||||
"workflowDefinitionVersionId": "e91d58c7a7ca1861",
|
||||
"latestAvailablePublishedVersion": 1,
|
||||
"latestAvailablePublishedVersionId": "e91d58c7a7ca1861",
|
||||
"id": "f19ae76011a020f3",
|
||||
"nodeId": "Workflow2:4d5af7585eece1d7:f19ae76011a020f3",
|
||||
"name": "Sub1",
|
||||
"type": "Sub",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -235.796875,
|
||||
"y": -74
|
||||
},
|
||||
"size": {
|
||||
"width": 58.7421875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"workflowDefinitionId": "497be45e7d647e8f",
|
||||
"workflowDefinitionVersionId": "e91d58c7a7ca1861",
|
||||
"latestAvailablePublishedVersion": 1,
|
||||
"latestAvailablePublishedVersionId": "e91d58c7a7ca1861",
|
||||
"id": "ad4d54104a443b5b",
|
||||
"nodeId": "Workflow2:4d5af7585eece1d7:ad4d54104a443b5b",
|
||||
"name": "Sub2",
|
||||
"type": "Sub",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -101.796875,
|
||||
"y": -74
|
||||
},
|
||||
"size": {
|
||||
"width": 58.7421875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "f19ae76011a020f3",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "ad4d54104a443b5b",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"id": "e91d58c7a7ca1861",
|
||||
"definitionId": "497be45e7d647e8f",
|
||||
"name": "Sub",
|
||||
"createdAt": "2024-06-20T15:08:33.474045+00:00",
|
||||
"version": 1,
|
||||
"toolVersion": "3.3.0.0",
|
||||
"variables": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"outcomes": [],
|
||||
"customProperties": {
|
||||
"Elsa:WorkflowContextProviderTypes": []
|
||||
},
|
||||
"isReadonly": false,
|
||||
"isSystem": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "dc487ec63d2e8520",
|
||||
"nodeId": "Workflow1:dc487ec63d2e8520",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"notFoundConnections": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Test"
|
||||
}
|
||||
},
|
||||
"id": "f0f7dfe68eda4744",
|
||||
"nodeId": "Workflow1:dc487ec63d2e8520:f0f7dfe68eda4744",
|
||||
"name": "WriteLine1",
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": -55.796875,
|
||||
"y": -171
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user