Fix cyclic input argument evaluation (#3755)
* Prevent stack overflow when evaluating input arguments * Shuffle test folders
This commit is contained in:
parent
67efc51ebb
commit
1e407a9f70
37
Elsa.sln
37
Elsa.sln
|
|
@ -46,10 +46,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MassTransit", "src\mod
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.IntegrationTests", "test\Elsa.IntegrationTests\Elsa.IntegrationTests.csproj", "{B066ED0A-86E0-4025-85C2-7E8F7139D8A4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.UnitTests", "test\Elsa.UnitTests\Elsa.UnitTests.csproj", "{85A6862B-E523-45FA-A26B-BF98BE140E89}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Labels", "src\modules\Elsa.Labels\Elsa.Labels.csproj", "{80FF5821-E831-450D-AA0C-C76D07D878F4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bundles", "bundles", "{F06B9573-DF68-4606-866C-A7546A10A05A}"
|
||||
|
|
@ -161,6 +157,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.ElasticsearchS
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.OutboundHttpRequests", "src\samples\console\Elsa.Samples.OutboundHttpRequests\Elsa.Samples.OutboundHttpRequests.csproj", "{39AB433B-F7A6-4DD3-873A-9527946B7BD8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{18453B51-25EB-4317-A4B3-B10518252E92}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{1B8D5897-902E-4632-8698-E89CAF3DDF54}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "component", "component", "{08B41FFA-CEE3-46A7-B5C0-3EB65D37A16C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.JavaScript.UnitTests", "test\unit\Elsa.JavaScript.UnitTests\Elsa.JavaScript.UnitTests.csproj", "{0BB927FB-8C12-49B6-9150-64B733B2EBFD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.IntegrationTests", "test\integration\Elsa.IntegrationTests\Elsa.IntegrationTests.csproj", "{E9652738-2B3D-4357-B84B-54F0EA161382}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -199,14 +205,6 @@ Global
|
|||
{BB983D0B-A939-4008-B9E3-C7C172BCF83A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BB983D0B-A939-4008-B9E3-C7C172BCF83A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BB983D0B-A939-4008-B9E3-C7C172BCF83A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B066ED0A-86E0-4025-85C2-7E8F7139D8A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B066ED0A-86E0-4025-85C2-7E8F7139D8A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B066ED0A-86E0-4025-85C2-7E8F7139D8A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B066ED0A-86E0-4025-85C2-7E8F7139D8A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{85A6862B-E523-45FA-A26B-BF98BE140E89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{85A6862B-E523-45FA-A26B-BF98BE140E89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85A6862B-E523-45FA-A26B-BF98BE140E89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85A6862B-E523-45FA-A26B-BF98BE140E89}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{80FF5821-E831-450D-AA0C-C76D07D878F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{80FF5821-E831-450D-AA0C-C76D07D878F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{80FF5821-E831-450D-AA0C-C76D07D878F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -411,6 +409,14 @@ Global
|
|||
{39AB433B-F7A6-4DD3-873A-9527946B7BD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{39AB433B-F7A6-4DD3-873A-9527946B7BD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{39AB433B-F7A6-4DD3-873A-9527946B7BD8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0BB927FB-8C12-49B6-9150-64B733B2EBFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0BB927FB-8C12-49B6-9150-64B733B2EBFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0BB927FB-8C12-49B6-9150-64B733B2EBFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0BB927FB-8C12-49B6-9150-64B733B2EBFD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E9652738-2B3D-4357-B84B-54F0EA161382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E9652738-2B3D-4357-B84B-54F0EA161382}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E9652738-2B3D-4357-B84B-54F0EA161382}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E9652738-2B3D-4357-B84B-54F0EA161382}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{155227F0-A33B-40AA-A4B4-06F813EB921B} = {61017E64-6D00-49CB-9E81-5002DC8F7D5F}
|
||||
|
|
@ -418,8 +424,6 @@ Global
|
|||
{873BFC3E-63C2-4495-A503-5EC05DCD84E4} = {155227F0-A33B-40AA-A4B4-06F813EB921B}
|
||||
{56C2FFB8-EA54-45B5-A095-4A78142EB4B5} = {155227F0-A33B-40AA-A4B4-06F813EB921B}
|
||||
{5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79} = {61017E64-6D00-49CB-9E81-5002DC8F7D5F}
|
||||
{B066ED0A-86E0-4025-85C2-7E8F7139D8A4} = {90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}
|
||||
{85A6862B-E523-45FA-A26B-BF98BE140E89} = {90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}
|
||||
{F06B9573-DF68-4606-866C-A7546A10A05A} = {61017E64-6D00-49CB-9E81-5002DC8F7D5F}
|
||||
{B2049499-D384-46DF-8837-F1180107DD54} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{FC5D2CE9-FFB0-478D-8D54-E4109D1FD202} = {F06B9573-DF68-4606-866C-A7546A10A05A}
|
||||
|
|
@ -481,5 +485,10 @@ Global
|
|||
{C25CFDCF-8E06-4DD8-A83E-FF7EF9FDA02E} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5}
|
||||
{4A54379F-4775-41B6-9752-FF300288916A} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5}
|
||||
{39AB433B-F7A6-4DD3-873A-9527946B7BD8} = {873BFC3E-63C2-4495-A503-5EC05DCD84E4}
|
||||
{18453B51-25EB-4317-A4B3-B10518252E92} = {90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}
|
||||
{1B8D5897-902E-4632-8698-E89CAF3DDF54} = {90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}
|
||||
{08B41FFA-CEE3-46A7-B5C0-3EB65D37A16C} = {90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}
|
||||
{0BB927FB-8C12-49B6-9150-64B733B2EBFD} = {18453B51-25EB-4317-A4B3-B10518252E92}
|
||||
{E9652738-2B3D-4357-B84B-54F0EA161382} = {1B8D5897-902E-4632-8698-E89CAF3DDF54}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@ public class JavaScriptFeature : FeatureBase
|
|||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Module.UseWorkflowManagement(management => management.AddActivitiesFrom<JavaScriptFeature>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Apply()
|
||||
{
|
||||
// JavaScript services.
|
||||
Services
|
||||
.AddSingleton<IExpressionSyntaxProvider, JavaScriptExpressionSyntaxProvider>()
|
||||
.AddSingleton<IJavaScriptEvaluator, JintJavaScriptEvaluator>()
|
||||
|
|
@ -41,6 +48,7 @@ public class JavaScriptFeature : FeatureBase
|
|||
.AddExpressionHandler<JavaScriptExpressionHandler, JavaScriptExpression>()
|
||||
;
|
||||
|
||||
// Type definition services.
|
||||
Services
|
||||
.AddSingleton<ITypeDefinitionService, TypeDefinitionService>()
|
||||
.AddSingleton<ITypeDescriber, TypeDescriber>()
|
||||
|
|
@ -50,7 +58,8 @@ public class JavaScriptFeature : FeatureBase
|
|||
.AddSingleton<ITypeDefinitionProvider, CommonTypeDefinitionProvider>()
|
||||
.AddSingleton<ITypeDefinitionProvider, VariableTypeDefinitionProvider>()
|
||||
;
|
||||
|
||||
Module.UseWorkflowManagement(management => management.AddActivitiesFrom<JavaScriptFeature>());
|
||||
|
||||
// Handlers.
|
||||
Services.AddNotificationHandlersFrom<JavaScriptFeature>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
using Elsa.Expressions.Models;
|
||||
using Elsa.Expressions.Services;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Notifications;
|
||||
using Elsa.Mediator.Services;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Management.Activities;
|
||||
using Elsa.Workflows.Management.Extensions;
|
||||
using Elsa.Workflows.Management.Services;
|
||||
using Humanizer;
|
||||
using JetBrains.Annotations;
|
||||
using Jint;
|
||||
|
||||
namespace Elsa.JavaScript.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Configures the JavaScript engine with workflow input getters.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class WorkflowDefinitionActivityJavaScriptHandler : INotificationHandler<EvaluatingJavaScript>
|
||||
{
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly IExpressionEvaluator _expressionEvaluator;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public WorkflowDefinitionActivityJavaScriptHandler(IActivityRegistry activityRegistry, IExpressionEvaluator expressionEvaluator)
|
||||
{
|
||||
_activityRegistry = activityRegistry;
|
||||
_expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
|
||||
{
|
||||
var engine = notification.Engine;
|
||||
var context = notification.Context;
|
||||
|
||||
// If we are already evaluating inputs, then we're in a circular evaluation loop. In this case, we should not attempt to evaluate the inputs.
|
||||
if(context.TransientProperties.TryGetValue("EvaluatingInputs", out var evaluatingInputs) && (bool)evaluatingInputs)
|
||||
return;
|
||||
|
||||
// To prevent a circular evaluation loop, set a flag on the context to indicate that we're currently evaluating the inputs.
|
||||
context.TransientProperties["EvaluatingInputs"] = true;
|
||||
|
||||
// Create input getters.
|
||||
await CreateInputAccessorsAsync(engine, context);
|
||||
}
|
||||
|
||||
private async Task CreateInputAccessorsAsync(Engine engine, ExpressionExecutionContext context)
|
||||
{
|
||||
var workflowDefinitionActivity = GetFirstWorkflowDefinitionActivity(context);
|
||||
|
||||
if (workflowDefinitionActivity == null)
|
||||
return;
|
||||
|
||||
var descriptor = _activityRegistry.Find(workflowDefinitionActivity.Type, workflowDefinitionActivity.Version)!;
|
||||
var inputDefinitions = descriptor.Inputs;
|
||||
|
||||
foreach (var inputDefinition in inputDefinitions)
|
||||
{
|
||||
var inputPascalName = inputDefinition.Name.Pascalize();
|
||||
var input = workflowDefinitionActivity.SyntheticProperties.TryGetValue(inputDefinition.Name, out var inputValue) ? (Input?)inputValue : default;
|
||||
var evaluatedExpression = input != null ? await _expressionEvaluator.EvaluateAsync(input, context) : input;
|
||||
|
||||
engine.SetValue($"get{inputPascalName}", (Func<object?>)(() => evaluatedExpression));
|
||||
}
|
||||
}
|
||||
|
||||
private static WorkflowDefinitionActivity? GetFirstWorkflowDefinitionActivity(ExpressionExecutionContext context) =>
|
||||
context.GetActivityExecutionContext().GetFirstWorkflowDefinitionActivity();
|
||||
}
|
||||
|
|
@ -74,8 +74,6 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
// Create variable & input setters and getters for each variable.
|
||||
CreateMemoryBlockAccessors(engine, context);
|
||||
|
||||
// Create input getters.
|
||||
await CreateInputAccessorsAsync(engine, context);
|
||||
|
||||
engine.SetValue("isNullOrWhiteSpace", (Func<string, bool>)(value => string.IsNullOrWhiteSpace(value)));
|
||||
engine.SetValue("isNullOrEmpty", (Func<string, bool>)(value => string.IsNullOrEmpty(value)));
|
||||
|
|
@ -93,29 +91,6 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
|
||||
return engine;
|
||||
}
|
||||
|
||||
private async Task CreateInputAccessorsAsync(Engine engine, ExpressionExecutionContext context)
|
||||
{
|
||||
var workflowDefinitionActivity = GetFirstWorkflowDefinitionActivity(context);
|
||||
|
||||
if (workflowDefinitionActivity == null)
|
||||
return;
|
||||
|
||||
var descriptor = _activityRegistry.Find(workflowDefinitionActivity.Type, workflowDefinitionActivity.Version)!;
|
||||
var inputDefinitions = descriptor.Inputs;
|
||||
|
||||
foreach (var inputDefinition in inputDefinitions)
|
||||
{
|
||||
var inputPascalName = inputDefinition.Name.Pascalize();
|
||||
var input = workflowDefinitionActivity.SyntheticProperties.TryGetValue(inputDefinition.Name, out var inputValue) ? (Input?)inputValue : default;
|
||||
var evaluatedExpression = input != null ? await _expressionEvaluator.EvaluateAsync(input, context) : input;
|
||||
|
||||
engine.SetValue($"get{inputPascalName}", (Func<object?>)(() => evaluatedExpression));
|
||||
}
|
||||
}
|
||||
|
||||
private static WorkflowDefinitionActivity? GetFirstWorkflowDefinitionActivity(ExpressionExecutionContext context) =>
|
||||
context.GetActivityExecutionContext().GetFirstWorkflowDefinitionActivity();
|
||||
|
||||
private static void CreateMemoryBlockAccessors(Engine engine, ExpressionExecutionContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
using Xunit;
|
||||
|
||||
namespace Elsa.UnitTests;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
@ -19,4 +20,8 @@
|
|||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\modules\Elsa.JavaScript\Elsa.JavaScript.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
26
test/unit/Elsa.JavaScript.UnitTests/UnitTest1.cs
Normal file
26
test/unit/Elsa.JavaScript.UnitTests/UnitTest1.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Elsa.Expressions.Services;
|
||||
using Elsa.JavaScript.Handlers;
|
||||
using Elsa.Workflows.Management.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.JavaScript.UnitTests;
|
||||
|
||||
public class WorkflowDefinitionActivityJavaScriptHandlerTests
|
||||
{
|
||||
private readonly WorkflowDefinitionActivityJavaScriptHandler _handler;
|
||||
|
||||
public WorkflowDefinitionActivityJavaScriptHandlerTests()
|
||||
{
|
||||
var activityRegistryMock = new Mock<IActivityRegistry>();
|
||||
var expressionEvaluatorMock = new Mock<IExpressionEvaluator>();
|
||||
_handler = new WorkflowDefinitionActivityJavaScriptHandler(activityRegistryMock.Object, expressionEvaluatorMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue