Incremental work on tests and QA

This commit is contained in:
Sipke Schoorstra 2020-10-19 22:12:11 +02:00
parent 6dad26ac3c
commit bd3b41440a
70 changed files with 869 additions and 245 deletions

View file

@ -10,3 +10,6 @@ indent_size=4
resharper_csharp_max_line_length=240
resharper_keep_user_linebreaks=true
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers=false

View file

@ -52,9 +52,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Core", "src\ser
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.UnitTests", "test\unit\Elsa.Core.UnitTests\Elsa.Core.UnitTests.csproj", "{475EEB95-ED27-4366-88EA-97C5000AC8E8}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}"
EndProject
@ -72,6 +70,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "locking", "locking", "{7CD5
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.YesSql.Provider.Sqlite.InMemory", "src\core\Elsa.YesSql.Provider.Sqlite.InMemory\Elsa.YesSql.Provider.Sqlite.InMemory.csproj", "{E2D63391-1986-45C8-A18F-4D58F3D71057}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Core.IntegrationTests", "test\integration\Elsa.Core.IntegrationTests\Elsa.Core.IntegrationTests.csproj", "{3C43CC9B-E64F-4481-9B27-3E868AD95CE9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -130,10 +130,6 @@ Global
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.Build.0 = Release|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.Build.0 = Release|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -159,6 +155,10 @@ Global
{E2D63391-1986-45C8-A18F-4D58F3D71057}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2D63391-1986-45C8-A18F-4D58F3D71057}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2D63391-1986-45C8-A18F-4D58F3D71057}.Release|Any CPU.Build.0 = Release|Any CPU
{3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -182,7 +182,6 @@ Global
{468E498C-59DB-4541-8D8A-0D89DE9083AB} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{475EEB95-ED27-4366-88EA-97C5000AC8E8} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}
{12D29DDC-A885-4CAA-908C-106D845B10C0} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
@ -191,6 +190,7 @@ Global
{EBD49CCA-5400-4C36-B5DF-7B28190AA323} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
{150EF356-E8BC-4922-91C2-362017479409} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
{E2D63391-1986-45C8-A18F-4D58F3D71057} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
{3C43CC9B-E64F-4481-9B27-3E868AD95CE9} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}

View file

@ -56,9 +56,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Host", "src\ser
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.UnitTests", "test\unit\Elsa.Core.UnitTests\Elsa.Core.UnitTests.csproj", "{475EEB95-ED27-4366-88EA-97C5000AC8E8}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}"
EndProject
@ -68,8 +66,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Timers", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.SqlServer", "src\providers\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj", "{150EF356-E8BC-4922-91C2-362017479409}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.GraphQL", "src\server\Elsa.Server.GraphQL\Elsa.Server.GraphQL.csproj", "{12D29DDC-A885-4CAA-908C-106D845B10C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Serialization", "src\samples\Elsa.Samples.Serialization\Elsa.Samples.Serialization.csproj", "{DF47517F-9029-44DF-A29F-F2DE15041473}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HelloWorldConsole", "src\samples\Elsa.Samples.HelloWorldConsole\Elsa.Samples.HelloWorldConsole.csproj", "{E224F8CF-F9F5-4E99-B405-758F3C02C47A}"
@ -94,6 +90,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.ReadLineEchoCo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.YesSql.Provider.Sqlite.InMemory", "src\core\Elsa.YesSql.Provider.Sqlite.InMemory\Elsa.YesSql.Provider.Sqlite.InMemory.csproj", "{D0364288-3072-44F4-877C-7721C20BC27F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Core.IntegrationTests", "test\integration\Elsa.Core.IntegrationTests\Elsa.Core.IntegrationTests.csproj", "{4CB34AB3-01C9-4911-8914-EABAA744EAD3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "component", "component", "{FC47A50F-03B2-47D8-AAFB-075314FBA186}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.ComponentTests", "test\component\Elsa.ComponentTests\Elsa.ComponentTests.csproj", "{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Server.Api", "src\server\Elsa.Server.Api\Elsa.Server.Api.csproj", "{44E0B699-A140-4551-A0E9-9FD9F171A9C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -156,10 +160,6 @@ Global
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.Build.0 = Release|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.Build.0 = Release|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -172,10 +172,6 @@ Global
{150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.Build.0 = Debug|Any CPU
{150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.ActiveCfg = Release|Any CPU
{150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.Build.0 = Release|Any CPU
{12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.Build.0 = Release|Any CPU
{DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF47517F-9029-44DF-A29F-F2DE15041473}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -221,6 +217,18 @@ Global
{D0364288-3072-44F4-877C-7721C20BC27F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0364288-3072-44F4-877C-7721C20BC27F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0364288-3072-44F4-877C-7721C20BC27F}.Release|Any CPU.Build.0 = Release|Any CPU
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Release|Any CPU.Build.0 = Release|Any CPU
{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Release|Any CPU.Build.0 = Release|Any CPU
{44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -246,11 +254,9 @@ Global
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{475EEB95-ED27-4366-88EA-97C5000AC8E8} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}
{071DD6EC-D00C-4513-82B6-3FE8438061E3} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{12D29DDC-A885-4CAA-908C-106D845B10C0} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{DF47517F-9029-44DF-A29F-F2DE15041473} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{E224F8CF-F9F5-4E99-B405-758F3C02C47A} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{A11D79AE-F4C9-4595-9B73-0E0AB221B90D} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
@ -264,6 +270,10 @@ Global
{F755FB1F-72FB-4F7B-8270-F5F40F4D6952} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{867CB845-B803-4D40-9360-3D11ADBD9CE9} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{D0364288-3072-44F4-877C-7721C20BC27F} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
{4CB34AB3-01C9-4911-8914-EABAA744EAD3} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
{FC47A50F-03B2-47D8-AAFB-075314FBA186} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5} = {FC47A50F-03B2-47D8-AAFB-075314FBA186}
{44E0B699-A140-4551-A0E9-9FD9F171A9C2} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}

View file

@ -8,4 +8,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Configurer/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Configurer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Noda/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -22,7 +22,7 @@ namespace Elsa.Activities.Console
)]
public class ReadLine : Activity
{
private readonly TextReader _input;
private readonly TextReader? _input;
public ReadLine()
{
@ -46,7 +46,7 @@ namespace Elsa.Activities.Console
protected override IActivityExecutionResult OnResume(ActivityExecutionContext context)
{
var receivedInput = (string)context.Input;
var receivedInput = (string)context.Input!;
return Execute(receivedInput);
}

View file

@ -30,7 +30,7 @@ namespace Elsa.Activities.Console
}
[ActivityProperty(Hint = "The text to write.")]
public string Text { get; set; }
public string? Text { get; set; }
private readonly TextWriter _output;

View file

@ -0,0 +1,17 @@
using System;
using System.Threading.Tasks;
using Elsa.Builders;
using Elsa.Services.Models;
// ReSharper disable once CheckNamespace
namespace Elsa.Activities.Console
{
public static class WriteLineExtensions
{
public static ISetupActivity<WriteLine> WithText(this ISetupActivity<WriteLine> writeLine, Func<ActivityExecutionContext, ValueTask<string?>> text) => writeLine.Set(x => x.Text, text);
public static ISetupActivity<WriteLine> WithText(this ISetupActivity<WriteLine> writeLine, Func<ActivityExecutionContext, string> text) => writeLine.Set(x => x.Text, text);
public static ISetupActivity<WriteLine> WithText(this ISetupActivity<WriteLine> writeLine, Func<ValueTask<string?>> text) => writeLine.Set(x => x.Text, text);
public static ISetupActivity<WriteLine> WithText(this ISetupActivity<WriteLine> writeLine, Func<string?> text) => writeLine.Set(x => x.Text, text);
public static ISetupActivity<WriteLine> WithText(this ISetupActivity<WriteLine> writeLine, string? text) => writeLine.Set(x => x.Text, text);
}
}

View file

@ -18,6 +18,7 @@
<RepositoryType>GitHub</RepositoryType>
<PackageTags>elsa, workflows</PackageTags>
<PackageIcon>icon.png</PackageIcon>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View file

@ -7,10 +7,11 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddConsoleActivities(this IServiceCollection services, TextReader standardIn = default)
public static IServiceCollection AddConsoleActivities(this IServiceCollection services, TextReader? standardIn = default, TextWriter? standardOut = default)
{
return services
.AddSingleton(standardIn ?? Console.In)
.AddSingleton(standardOut ?? Console.Out)
.AddActivity<ReadLine>()
.AddActivity<WriteLine>();
}

View file

@ -33,7 +33,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.9" />
</ItemGroup>
</Project>

View file

@ -20,7 +20,7 @@ namespace Elsa.Activities.UserTask.Activities
)]
public class UserTask : Activity
{
private readonly IJsonSerializer _serializer;
private readonly IContentSerializer _serializer;
[ActivityProperty(
Type = ActivityPropertyTypes.List,
@ -28,7 +28,7 @@ namespace Elsa.Activities.UserTask.Activities
)]
public ICollection<string> Actions { get; set; } = new List<string>();
public UserTask(IJsonSerializer serializer)
public UserTask(IContentSerializer serializer)
{
_serializer = serializer;
}

View file

@ -32,7 +32,7 @@
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="3.1.7" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="3.1.8" />
<PackageReference Include="NodaTime" Version="3.0.2" />

View file

@ -5,7 +5,7 @@ namespace Elsa
{
public static class VariablesExtensions
{
public static T Get<T>(this Variables variables, string name, IJsonSerializer serializer)
public static T Get<T>(this Variables variables, string name, IContentSerializer serializer)
{
var value = variables.Get(name);
return value != null ? serializer.Deserialize<T>(value) : default!;

View file

@ -4,6 +4,21 @@ namespace Elsa.Models
{
public class ActivityDefinitionPropertyValue
{
public static ActivityDefinitionPropertyValue Literal<T>(T value) => new ActivityDefinitionPropertyValue(value!.ToString(), "Literal", typeof(T));
public static ActivityDefinitionPropertyValue Liquid<T>(string expression) => new ActivityDefinitionPropertyValue(expression, "Liquid", typeof(T));
public static ActivityDefinitionPropertyValue JavaScript<T>(string expression) => new ActivityDefinitionPropertyValue(expression, "JavaScript", typeof(T));
public ActivityDefinitionPropertyValue()
{
}
public ActivityDefinitionPropertyValue(string expression, string syntax, Type type)
{
Expression = expression;
Syntax = syntax;
Type = type;
}
public Type Type { get; set; } = default!;
public string Syntax { get; set; } = default!;
public string Expression { get; set; } = default!;

View file

@ -2,7 +2,7 @@
namespace Elsa.Serialization
{
public interface IJsonSerializer
public interface IContentSerializer
{
JObject Serialize<T>(T value);
T Deserialize<T>(JToken token);

View file

@ -39,5 +39,20 @@ namespace Elsa.Services
string? activityId = default,
object? input = default,
CancellationToken cancellationToken = default) where T : IWorkflow;
ValueTask<WorkflowInstance> RunWorkflowAsync(
IWorkflow workflow,
string? activityId = default,
object? input = default,
string? correlationId = default,
CancellationToken cancellationToken = default);
ValueTask<WorkflowInstance> RunWorkflowAsync(
IWorkflow workflow,
WorkflowInstance workflowInstance,
string? activityId = default,
object? input = default,
string? correlationId = default,
CancellationToken cancellationToken = default);
}
}

View file

@ -18,7 +18,6 @@ namespace Elsa.Services.Models
ServiceProvider = serviceProvider;
WorkflowBlueprint = workflowBlueprint;
WorkflowInstance = workflowInstance;
ExecutionLog = new List<ExecutionLogEntry>(workflowInstance.ExecutionLog);
IsFirstPass = true;
}
@ -47,7 +46,7 @@ namespace Elsa.Services.Models
public ScheduledActivity PeekScheduledActivity() => WorkflowInstance.ScheduledActivities.Peek();
public string? CorrelationId { get; set; }
public bool DeleteCompletedInstances { get; set; }
public ICollection<ExecutionLogEntry> ExecutionLog { get; }
public ICollection<ExecutionLogEntry> ExecutionLog => WorkflowInstance.ExecutionLog;
public WorkflowStatus Status => WorkflowInstance.Status;
public void SetVariable(string name, object? value) => WorkflowInstance.Variables.Set(name, JToken.FromObject(value!));

View file

@ -93,11 +93,9 @@ namespace Elsa.Builders
public IActivityBuilder New(
Type activityType,
Action<IActivityBuilder>? branch = default,
IDictionary<string, IActivityPropertyValueProvider>? propertyValueProviders = default)
{
var activityBuilder = new ActivityBuilder(activityType, this, propertyValueProviders);
branch?.Invoke(activityBuilder);
return activityBuilder;
}
@ -105,7 +103,7 @@ namespace Elsa.Builders
Action<IActivityBuilder>? branch = default,
IDictionary<string, IActivityPropertyValueProvider>? propertyValueProviders = default)
where T : class, IActivity =>
New(typeof(T), branch, propertyValueProviders);
New(typeof(T), propertyValueProviders);
public IActivityBuilder New<T>(
Action<ISetupActivity<T>>? setup = default,

View file

@ -5,14 +5,14 @@ using Elsa.Queries;
using Elsa.Services;
using Rebus.Handlers;
namespace Elsa.Messaging.Distributed.Handlers
namespace Elsa.Consumers
{
public class RunWorkflowHandler : IHandleMessages<RunWorkflow>
public class RunWorkflowConsumer : IHandleMessages<RunWorkflow>
{
private readonly IWorkflowHost _workflowHost;
private readonly IWorkflowInstanceManager _workflowInstanceManager;
public RunWorkflowHandler(IWorkflowHost workflowHost, IWorkflowInstanceManager workflowInstanceManager)
public RunWorkflowConsumer(IWorkflowHost workflowHost, IWorkflowInstanceManager workflowInstanceManager)
{
_workflowHost = workflowHost;
_workflowInstanceManager = workflowInstanceManager;

View file

@ -46,7 +46,7 @@
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.8" />
@ -69,7 +69,6 @@
<ItemGroup>
<Folder Include="Data" />
<Folder Include="Messaging\Domain" />
</ItemGroup>
</Project>

View file

@ -29,7 +29,7 @@ namespace Elsa
CreateJsonSerializer = sp =>
{
var serializer = DefaultJsonSerializer.CreateDefaultJsonSerializer();
var serializer = ContentSerializer.CreateDefaultJsonSerializer();
JsonSerializerConfigurer(sp, serializer);
return serializer;
};

View file

@ -1,15 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Elsa.Services;
namespace Elsa.Extensions
{
public static class ActivityCollectionExtensions
{
public static IEnumerable<IActivity> Find(this IEnumerable<IActivity> collection, IEnumerable<string> ids)
{
var idList = ids?.ToList();
return idList != null ? collection.Where(x => idList.Contains(x.Id)) : default;
}
}
}

View file

@ -1,22 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Elsa;
using Elsa.Activities.ControlFlow;
using Elsa.Activities.Primitives;
using Elsa.Activities.Signaling;
using Elsa.Builders;
using Elsa.Consumers;
using Elsa.Converters;
using Elsa.Data;
using Elsa.Data.Extensions;
using Elsa.Events;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Handlers;
using Elsa.Indexes;
using Elsa.Messages;
using Elsa.Messaging;
using Elsa.Messaging.Distributed.Handlers;
using Elsa.Metadata;
using Elsa.Metadata.Handlers;
using Elsa.Runtime;
using Elsa.Serialization;
using Elsa.ServiceBus;
using Elsa.Services;
using Elsa.StartupTasks;
using Elsa.Triggers;
@ -67,13 +71,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
public static IServiceCollection AddConsumer<TMessage, TConsumer>(this IServiceCollection services) where TConsumer : class, IHandleMessages<TMessage> => services.AddTransient<IHandleMessages<TMessage>, TConsumer>();
private static IServiceCollection AddMediatR(this ElsaOptions options)
{
return options.Services.AddMediatR(
mediatr => mediatr.AsScoped(),
typeof(ElsaServiceCollectionExtensions));
}
private static IServiceCollection AddMediatR(this ElsaOptions options) => options.Services.AddMediatR(mediatr => mediatr.AsScoped(), typeof(IActivity));
private static ElsaOptions AddWorkflowsCore(this ElsaOptions configuration)
{
@ -87,7 +85,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddTransient<Func<IEnumerable<IActivity>>>(sp => sp.GetServices<IActivity>)
.AddSingleton<IIdGenerator, IdGenerator>()
.AddSingleton(sp => sp.GetRequiredService<ElsaOptions>().CreateJsonSerializer(sp))
.AddSingleton<IJsonSerializer, DefaultJsonSerializer>()
.AddSingleton<IContentSerializer, ContentSerializer>()
.AddSingleton<IActivitySerializer, ActivitySerializer>()
.AddSingleton<TypeConverter>()
.TryAddProvider<IExpressionHandler, LiteralHandler>(ServiceLifetime.Singleton)
@ -99,7 +97,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddScoped<IWorkflowHost, WorkflowHost>()
.AddSingleton<IWorkflowFactory, WorkflowFactory>()
.AddSingleton<IWorkflowBlueprintMaterializer, WorkflowBlueprintMaterializer>()
.AddSingleton<IWorkflowSelector, WorkflowSelector>()
.AddScoped<IWorkflowSelector, WorkflowSelector>()
.AddScoped<IWorkflowDefinitionManager, WorkflowDefinitionManager>()
.AddScoped<IWorkflowInstanceManager, WorkflowInstanceManager>()
.AddIndexProvider<WorkflowDefinitionIndexProvider>()
@ -109,8 +107,9 @@ namespace Microsoft.Extensions.DependencyInjection
.AddWorkflowProvider<CodeWorkflowProvider>()
.AddTransient<IWorkflowBuilder, WorkflowBuilder>()
.AddTransient<Func<IWorkflowBuilder>>(sp => sp.GetRequiredService<IWorkflowBuilder>)
.AddNotificationHandlers(typeof(ElsaServiceCollectionExtensions))
.AddStartupTask<StartServiceBusTask>()
.AddConsumer<RunWorkflow, RunWorkflowHandler>()
.AddConsumer<RunWorkflow, RunWorkflowConsumer>()
.AddMetadataHandlers()
.AddPrimitiveActivities();

View file

@ -5,12 +5,12 @@ using Elsa.Models;
using MediatR;
using NodaTime;
namespace Elsa.Messaging.Domain.Handlers
namespace Elsa.Handlers
{
public class WorkflowExecutionLogEventHandler : INotificationHandler<ActivityExecuted>
public class AppendExecutionLog : INotificationHandler<ActivityExecuted>
{
private readonly IClock _clock;
public WorkflowExecutionLogEventHandler(IClock clock) => _clock = clock;
public AppendExecutionLog(IClock clock) => _clock = clock;
public Task Handle(ActivityExecuted notification, CancellationToken cancellationToken)
{

View file

@ -7,9 +7,9 @@ using Elsa.Services.Models;
using MediatR;
using Microsoft.Extensions.Logging;
namespace Elsa.Messaging.Domain.Handlers
namespace Elsa.Handlers
{
public class PersistenceWorkflowEventHandler :
public class PersistWorkflow :
INotificationHandler<WorkflowExecuted>,
INotificationHandler<WorkflowSuspended>,
INotificationHandler<ActivityExecuted>,
@ -18,9 +18,9 @@ namespace Elsa.Messaging.Domain.Handlers
private readonly IWorkflowInstanceManager _workflowInstanceManager;
private readonly ILogger _logger;
public PersistenceWorkflowEventHandler(
public PersistWorkflow(
IWorkflowInstanceManager workflowInstanceManager,
ILogger<PersistenceWorkflowEventHandler> logger)
ILogger<PersistWorkflow> logger)
{
_workflowInstanceManager = workflowInstanceManager;
_logger = logger;

View file

@ -5,8 +5,8 @@ namespace Elsa.Serialization
{
public class ActivitySerializer : IActivitySerializer
{
private readonly IJsonSerializer _ijSerializer;
public ActivitySerializer(IJsonSerializer ijSerializer) => _ijSerializer = ijSerializer;
private readonly IContentSerializer _ijSerializer;
public ActivitySerializer(IContentSerializer ijSerializer) => _ijSerializer = ijSerializer;
public JObject Serialize<T>(T activity) where T : IActivity => _ijSerializer.Serialize(activity);
public T Deserialize<T>(JObject data) where T : IActivity => _ijSerializer.Deserialize<T>(data);
}

View file

@ -7,9 +7,9 @@ using NodaTime.Serialization.JsonNet;
namespace Elsa.Serialization
{
public class DefaultJsonSerializer : IJsonSerializer
public class ContentSerializer : IContentSerializer
{
public DefaultJsonSerializer(JsonSerializer serializer)
public ContentSerializer(JsonSerializer serializer)
{
Serializer = serializer;
}
@ -30,9 +30,9 @@ namespace Elsa.Serialization
jsonSerializer.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
jsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
jsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
jsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.All;
jsonSerializer.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;
jsonSerializer.TypeNameHandling = TypeNameHandling.Objects;
jsonSerializer.TypeNameHandling = TypeNameHandling.None;
jsonSerializer.ContractResolver = new CamelCasePropertyNamesContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy

View file

@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Rebus.Config;
using Rebus.ServiceProvider;
namespace Elsa.Messaging
namespace Elsa.ServiceBus
{
public static class ServiceCollectionExtensions
{

View file

@ -27,7 +27,6 @@ namespace Elsa.Services
private readonly IWorkflowBuilder _workflowBuilder;
private readonly IMediator _mediator;
private readonly IServiceProvider _serviceProvider;
private readonly IEnumerable<ITriggerProvider> _triggerProviders;
private readonly ILogger _logger;
public WorkflowHost(
@ -36,7 +35,6 @@ namespace Elsa.Services
IWorkflowBuilder workflowBuilder,
IMediator mediator,
IServiceProvider serviceProvider,
IEnumerable<ITriggerProvider> triggerProviders,
ILogger<WorkflowHost> logger)
{
_workflowRegistry = workflowRegistry;
@ -44,7 +42,6 @@ namespace Elsa.Services
_workflowBuilder = workflowBuilder;
_mediator = mediator;
_serviceProvider = serviceProvider;
_triggerProviders = triggerProviders;
_logger = logger;
}
@ -79,6 +76,29 @@ namespace Elsa.Services
where T : IWorkflow =>
await RunWorkflowAsync(_workflowBuilder.Build<T>(), workflowInstance, activityId, input, cancellationToken);
public async ValueTask<WorkflowInstance> RunWorkflowAsync(
IWorkflow workflow,
string? activityId = default,
object? input = default,
string? correlationId = default,
CancellationToken cancellationToken = default)
{
var workflowBlueprint = _workflowBuilder.Build(workflow);
return await RunWorkflowAsync(workflowBlueprint, activityId, input, correlationId, cancellationToken);
}
public async ValueTask<WorkflowInstance> RunWorkflowAsync(
IWorkflow workflow,
WorkflowInstance workflowInstance,
string? activityId = default,
object? input = default,
string? correlationId = default,
CancellationToken cancellationToken = default)
{
var workflowBlueprint = _workflowBuilder.Build(workflow);
return await RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, input, cancellationToken);
}
public async ValueTask<WorkflowInstance> RunWorkflowAsync(
WorkflowInstance workflowInstance,
string? activityId = default,

View file

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:62840/",
"sslPort": 44305
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Elsa.Samples.CustomActivities": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

View file

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:62841/",
"sslPort": 44336
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Elsa.Samples.HelloWorldHttp": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

View file

@ -60,7 +60,7 @@ namespace Elsa.Samples.Serialization
};
// Serialize workflow definition to JSON.
var serializer = services.GetRequiredService<IJsonSerializer>();
var serializer = services.GetRequiredService<IContentSerializer>();
var json = serializer.Serialize(workflowDefinition);
Console.WriteLine(json);

View file

@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.9" />
</ItemGroup>
<ItemGroup>

View file

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Elsa.Server.Core\Elsa.Server.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.1.1" />
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
</ItemGroup>
<ItemGroup>
<Compile Update="Endpoints\WorkflowDefinitions\Post.Request.cs">
<DependentUpon>Post.cs</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,25 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Models;
using Elsa.Queries;
using Elsa.Services;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
{
[ApiController]
[ApiVersion("1")]
[Route("v{version:apiVersion}/workflow-definitions/{id}")]
public class Get : ControllerBase
{
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
public Get(IWorkflowDefinitionManager workflowDefinitionManager) => _workflowDefinitionManager = workflowDefinitionManager;
[HttpGet]
public async Task<IActionResult> Handle([FromRoute(Name = "id")] string workflowDefinitionId, CancellationToken cancellationToken)
{
var workflowDefinition = await _workflowDefinitionManager.GetAsync(workflowDefinitionId, VersionOptions.Latest, cancellationToken);
return workflowDefinition == null ? (IActionResult)NotFound() : Ok(workflowDefinition);
}
}
}

View file

@ -0,0 +1,20 @@
using System.Collections.Generic;
using Elsa.Models;
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
{
public class CreateWorkflowDefinitionRequest
{
public string WorkflowDefinitionId { get; set; } = default!;
public string? Name { get; set; }
public string? Description { get; set; }
public Variables? Variables { get; set; }
public bool IsSingleton { get; set; }
public WorkflowPersistenceBehavior PersistenceBehavior { get; set; }
public bool DeleteCompletedInstances { get; set; }
public bool Enabled { get; set; }
public bool Publish { get; set; }
public ICollection<ActivityDefinition> Activities { get; set; } = new List<ActivityDefinition>();
public ICollection<ConnectionDefinition> Connections { get; set; } = new List<ConnectionDefinition>();
}
}

View file

@ -0,0 +1,45 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Models;
using Elsa.Services;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
{
[ApiController]
[ApiVersion("1")]
[Route("v{version:apiVersion}/workflow-definitions")]
public class Post : ControllerBase
{
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
public Post(IWorkflowDefinitionManager workflowDefinitionManager)
{
_workflowDefinitionManager = workflowDefinitionManager;
}
[HttpPost]
public async Task<IActionResult> Handle(CreateWorkflowDefinitionRequest request, ApiVersion apiVersion, CancellationToken cancellationToken)
{
var workflowDefinition = new WorkflowDefinition
{
WorkflowDefinitionId = request.WorkflowDefinitionId.Trim(),
Activities = request.Activities,
Connections = request.Connections,
Description = request.Description?.Trim(),
Name = request.Name?.Trim(),
Variables = request.Variables,
IsEnabled = request.Enabled,
IsLatest = true,
IsPublished = request.Publish,
Version = 1,
IsSingleton = request.IsSingleton,
PersistenceBehavior = request.PersistenceBehavior,
DeleteCompletedInstances = request.DeleteCompletedInstances
};
await _workflowDefinitionManager.SaveAsync(workflowDefinition, cancellationToken);
return CreatedAtAction("Handle", "Get", new { version = apiVersion.ToString() }, workflowDefinition);
}
}
}

View file

@ -0,0 +1,18 @@
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using NodaTime;
using NodaTime.Serialization.SystemTextJson;
namespace Elsa.Server.Api.Extensions
{
public static class JsonMvcBuilderExtensions
{
public static IMvcBuilder AddJsonSerialization(this IMvcBuilder builder) =>
builder.AddJsonOptions(
options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
});
}
}

View file

@ -0,0 +1,25 @@
using Elsa.Server.Api.Extensions;
using Microsoft.AspNetCore.Mvc;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddElsaApiEndpoints(this IServiceCollection services)
{
services.AddControllers().SetCompatibilityVersion(CompatibilityVersion.Latest).AddJsonSerialization();
services.AddRouting(options => options.LowercaseUrls = true);
services.AddApiVersioning(
options =>
{
options.ReportApiVersions = true;
options.DefaultApiVersion = ApiVersion.Default;
options.AssumeDefaultVersionWhenUnspecified = true;
});
return services;
}
}
}

View file

@ -6,7 +6,8 @@ using Elsa.Services;
using HotChocolate;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Server.GraphQL.Extensions
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{

View file

@ -29,7 +29,7 @@ namespace Elsa.Server.GraphQL
WorkflowInput workflowInput,
[Service] IWorkflowDefinitionManager manager,
[Service] IIdGenerator idGenerator,
[Service] IJsonSerializer serializer,
[Service] IContentSerializer serializer,
[Service] IWorkflowPublisher publisher,
CancellationToken cancellationToken)
{

View file

@ -5,14 +5,11 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Elsa.Server.Api\Elsa.Server.Api.csproj" />
<ProjectReference Include="..\Elsa.Server.Core\Elsa.Server.Core.csproj" />
<ProjectReference Include="..\Elsa.Server.GraphQL\Elsa.Server.GraphQL.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GraphQL.Server.Ui.GraphiQL" Version="4.0.1" />
<PackageReference Include="GraphQL.Server.Ui.Playground" Version="4.0.1" />
<PackageReference Include="GraphQL.Server.Ui.Voyager" Version="4.0.1" />
<PackageReference Include="YesSql.Provider.Sqlite" Version="1.0.0-beta-1547" />
</ItemGroup>

View file

@ -1,8 +1,5 @@
using Elsa.Runtime;
using Elsa.Server.GraphQL.Extensions;
using Elsa.StartupTasks;
using HotChocolate.AspNetCore;
using HotChocolate.AspNetCore.Voyager;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
@ -34,7 +31,7 @@ namespace Elsa.Server.Host
services
.AddElsaServer()
.AddElsaGraphQL()
.AddElsaApiEndpoints()
.AddCors(options => options.AddDefaultPolicy(cors => cors
.AllowAnyOrigin()
@ -57,9 +54,6 @@ namespace Elsa.Server.Host
app
.UseCors()
.UseGraphQL("/graphql")
.UsePlayground("/graphql")
.UseVoyager("/graphql")
.UseHttpActivities();
}
}

View file

@ -0,0 +1,37 @@
{
"$id": "1",
"workflowDefinitionId": "SampleWorkflow",
"workflowDefinitionVersionId": "1",
"version": 1,
"variables": {
"$id": "2",
"data": {}
},
"isEnabled": true,
"isPublished": true,
"isLatest": true,
"activities": {
"$id": "3",
"$values": [
{
"$id": "4",
"id": "activity-1",
"type": "WriteLine",
"properties": {
"$id": "5",
"Text": {
"$id": "6",
"type": "System.String, mscorlib",
"syntax": "Liquid",
"expression": "Hello World!"
}
}
}
]
},
"connections": {
"$id": "7",
"$values": []
}
}

View file

@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.14.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\server\Elsa.Server.Host\Elsa.Server.Host.csproj" />
<ProjectReference Include="..\..\shared\Elsa.Testing.Shared\Elsa.Testing.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Assets" />
</ItemGroup>
<ItemGroup>
<None Update="Assets\hello-world-workflow.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,75 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using AutoFixture;
using Elsa.Activities.Console;
using Elsa.ComponentTests.Helpers;
using Elsa.Core.IntegrationTests.Helpers;
using Elsa.Models;
using Elsa.Server.Api.Endpoints.WorkflowDefinitions;
using Elsa.Testing.Shared.AutoFixture;
using Xunit;
namespace Elsa.ComponentTests.Endpoints.WorkflowDefinitions
{
[Collection(ComponentTestsCollection.Name)]
public class PostTests : IDisposable
{
private readonly IFixture _fixture;
private readonly TemporaryFolder _tempFolder;
private readonly ElsaHostApplicationFactory _hostApplicationFactory;
private readonly HttpClient _httpClient;
public PostTests(ElsaHostApplicationFactory hostApplicationFactory)
{
_fixture = new Fixture().Customize(new NodaTimeCustomization());
_tempFolder = new TemporaryFolder();
_hostApplicationFactory = hostApplicationFactory;
hostApplicationFactory.SetDbConnectionString($@"Data Source={_tempFolder.Folder}elsa.db;Cache=Shared");
_httpClient = hostApplicationFactory.CreateClient();
}
[Fact(DisplayName = "Posting a new workflow definition returns HTTP 201.")]
public async Task Post01()
{
var request = CreateWorkflowDefinitionRequest();
var response = await _httpClient.PostJsonAsync("/v1/workflow-definitions", request);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
}
private CreateWorkflowDefinitionRequest CreateWorkflowDefinitionRequest()
{
var writeLine = new ActivityDefinition
{
Id = _fixture.Create<string>(),
Type = nameof(WriteLine),
Properties = new ActivityDefinitionProperties
{
[nameof(WriteLine.Text)] = ActivityDefinitionPropertyValue.Literal("Hello World!")
}
};
var readLine = new ActivityDefinition { Id = _fixture.Create<string>(), Type = nameof(ReadLine) };
var activities = new[] { writeLine, readLine };
var connections = new[] { new ConnectionDefinition(writeLine.Id, readLine.Id, OutcomeNames.Done) };
return _fixture.Build<CreateWorkflowDefinitionRequest>()
.With(x => x.Activities, activities)
.With(x => x.Connections, connections)
.Create();
}
private string CreateWorkflowDefinitionJson()
{
throw new NotImplementedException();
}
public void Dispose()
{
_hostApplicationFactory.Dispose();
_tempFolder.Dispose();
}
}
}

View file

@ -0,0 +1,13 @@
using System.IO;
using System.Threading.Tasks;
namespace Elsa.ComponentTests.Helpers
{
public static class AssetHelper
{
private static readonly string AssetsDirectory;
static AssetHelper() => AssetsDirectory = Path.Combine(Path.GetDirectoryName(typeof(AssetHelper).Assembly.Location)!, "Assets");
public static string GetAssetPath(string filename) => Path.Combine(AssetsDirectory, filename);
public static Task<string> ReadAsset(string filename) => File.ReadAllTextAsync(Path.Combine(AssetsDirectory, filename));
}
}

View file

@ -0,0 +1,10 @@
using Xunit;
namespace Elsa.ComponentTests.Helpers
{
[CollectionDefinition(Name)]
public class ComponentTestsCollection : ICollectionFixture<ElsaHostApplicationFactory>
{
public const string Name = "Component Tests";
}
}

View file

@ -0,0 +1,23 @@
using Elsa.Server.Host;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
namespace Elsa.ComponentTests.Helpers
{
public class ElsaHostApplicationFactory : WebApplicationFactory<Startup>
{
private string _dbConnectionString;
public void SetDbConnectionString(string connectionString)
{
_dbConnectionString = connectionString;
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder
.ConfigureAppConfiguration(config => config.AddInMemoryCollection(FakeConfiguration.Create(_dbConnectionString)));
}
}
}

View file

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace Elsa.ComponentTests.Helpers
{
public static class FakeConfiguration
{
public static IEnumerable<KeyValuePair<string, string>> Create(string dbConnectionString)
{
return new Dictionary<string, string>
{
["ConnectionStrings:Sqlite"] = dbConnectionString,
};
}
}
}

View file

@ -0,0 +1,18 @@
using System.Net.Http;
using System.Threading.Tasks;
namespace Elsa.ComponentTests.Helpers
{
public static class HttpClientExtensions
{
public static async Task<T> GetJsonAsync<T>(this HttpClient httpClient, string requestUri)
{
using var response = await httpClient.GetAsync(requestUri);
response.EnsureSuccessStatusCode();
return await response.Content.ReadJsonAsync<T>();
}
public static async Task<HttpResponseMessage> PostJsonAsync<T>(this HttpClient httpClient, string requestUri, T value) => await httpClient.PostAsync(requestUri, new JsonContent(value!));
}
}

View file

@ -0,0 +1,15 @@
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Elsa.ComponentTests.Helpers
{
public static class HttpContentExtensions
{
public static async Task<T> ReadJsonAsync<T>(this HttpContent content)
{
var json = await content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(json, JsonContent.SerializerSettings)!;
}
}
}

View file

@ -0,0 +1,29 @@
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using NodaTime;
using NodaTime.Serialization.JsonNet;
namespace Elsa.ComponentTests.Helpers
{
public class JsonContent : StringContent
{
public static readonly JsonSerializerSettings SerializerSettings;
static JsonContent()
{
SerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
SerializerSettings.Converters.Add(new StringEnumConverter());
}
public JsonContent(string content) : base(content, Encoding.UTF8, "application/json")
{
}
public JsonContent(object content) : this(JsonConvert.SerializeObject(content, SerializerSettings))
{
}
}
}

View file

@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Elsa.Core.IntegrationTests.Helpers;
using Elsa.Core.IntegrationTests.Workflows;
using Elsa.Models;
using Elsa.Testing.Shared.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Elsa.Core.IntegrationTests
{
public class BasicWorkflowUnitTests : WorkflowsUnitTestBase
{
public BasicWorkflowUnitTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}
[Fact(DisplayName = "Runs simple workflow.")]
public async Task Test01()
{
var workflowInstance = await WorkflowHost.RunWorkflowAsync<BasicWorkflow>();
Assert.Equal(WorkflowStatus.Completed, workflowInstance.Status);
}
}
}

View file

@ -2,9 +2,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
@ -33,8 +31,12 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\..\src\core\Elsa\Elsa.csproj" />
<ProjectReference Include="..\..\shared\Elsa.Testing.Shared\Elsa.Testing.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Helpers" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,28 @@
using System.Linq;
using System.Threading.Tasks;
using Elsa.Core.IntegrationTests.Helpers;
using Elsa.Core.IntegrationTests.Workflows;
using Elsa.Testing.Shared.Helpers;
using Xunit;
using Xunit.Abstractions;
namespace Elsa.Core.IntegrationTests
{
public class ForLoopWorkflowUnitTests : WorkflowsUnitTestBase
{
public ForLoopWorkflowUnitTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}
[Fact(DisplayName = "Runs For loop workflow.")]
public async Task Test01()
{
const int loopCount = 10;
var workflow = new ForLoopWorkflow(loopCount);
var workflowInstance = await WorkflowHost.RunWorkflowAsync(workflow);
var iterationLogs = workflowInstance.ExecutionLog.Where(x => x.ActivityId == "WriteLine").ToList();
Assert.Equal(loopCount, iterationLogs.Count);
}
}
}

View file

@ -0,0 +1,13 @@
using Elsa.Activities.Console;
using Elsa.Builders;
namespace Elsa.Core.IntegrationTests.Workflows
{
public class BasicWorkflow : IWorkflow
{
public void Build(IWorkflowBuilder builder)
{
builder.WriteLine("Hello xUnit!");
}
}
}

View file

@ -0,0 +1,26 @@
using Elsa.Activities.Console;
using Elsa.Activities.ControlFlow;
using Elsa.Builders;
namespace Elsa.Core.IntegrationTests.Workflows
{
public class ForLoopWorkflow : IWorkflow
{
private readonly int _loopCount;
public ForLoopWorkflow(int loopCount)
{
_loopCount = loopCount;
}
public void Build(IWorkflowBuilder builder)
{
builder.For(
0,
_loopCount,
iterate => iterate
.Then<WriteLine>(activity => activity.Set(x => x.Text, context => $"Iteration {context.Input}"))
.WithId("WriteLine"));
}
}
}

View file

@ -1,7 +1,7 @@
using System;
using AutoFixture.Kernel;
namespace Elsa.Testing.Shared.Autofixture.Abstractions
namespace Elsa.Testing.Shared.AutoFixture.Abstractions
{
public abstract class SpecimenBuilderBase<T> : ISpecimenBuilder
{

View file

@ -1,7 +1,7 @@
using AutoFixture;
using Elsa.Testing.Shared.Autofixture.SpecimenBuilders;
using Elsa.Testing.Shared.AutoFixture.SpecimenBuilders;
namespace Elsa.Testing.Shared.Autofixture
namespace Elsa.Testing.Shared.AutoFixture
{
public class NodaTimeCustomization : ICustomization
{

View file

@ -1,10 +1,10 @@
using System;
using AutoFixture;
using AutoFixture.Kernel;
using Elsa.Testing.Shared.Autofixture.Abstractions;
using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class DurationGenerator : SpecimenBuilderBase<Duration>
{

View file

@ -1,10 +1,10 @@
using System;
using AutoFixture;
using AutoFixture.Kernel;
using Elsa.Testing.Shared.Autofixture.Abstractions;
using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class InstantGenerator : SpecimenBuilderBase<Instant>
{

View file

@ -1,9 +1,9 @@
using System;
using AutoFixture.Kernel;
using Elsa.Testing.Shared.Autofixture.Abstractions;
using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class LocalDateGenerator : SpecimenBuilderBase<LocalDate>
{

View file

@ -1,10 +1,10 @@
using System;
using AutoFixture;
using AutoFixture.Kernel;
using Elsa.Testing.Shared.Autofixture.Abstractions;
using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class PeriodGenerator : SpecimenBuilderBase<Period>
{

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>latest</LangVersion>
<PackageVersion>1.0.0</PackageVersion>
<Authors>Elsa Contributors</Authors>
@ -19,7 +19,10 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.14.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.9" />
<PackageReference Include="NodaTime" Version="3.0.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
</ItemGroup>
<ItemGroup>
@ -29,4 +32,8 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

View file

@ -1,7 +1,7 @@
using System;
using System.IO;
namespace Elsa.Core.UnitTests
namespace Elsa.Core.IntegrationTests.Helpers
{
public class TemporaryFolder : IDisposable
{

View file

@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;
using Elsa.Core.IntegrationTests.Helpers;
using Elsa.Services;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Xunit.Abstractions;
using YesSql;
using YesSql.Provider.Sqlite;
namespace Elsa.Testing.Shared.Helpers
{
public abstract class WorkflowsUnitTestBase : IAsyncLifetime, IDisposable
{
private readonly TemporaryFolder _tempFolder;
protected WorkflowsUnitTestBase(ITestOutputHelper testOutputHelper, Action<IServiceCollection>? configureServices = default)
{
_tempFolder = new TemporaryFolder();
TestOutputHelper = testOutputHelper;
var services = new ServiceCollection()
.AddElsa(options => options.UsePersistence(config => ConfigurePersistence(config, _tempFolder.Folder)))
.AddConsoleActivities(Console.In, new XunitConsoleForwarder(testOutputHelper));
configureServices?.Invoke(services);
ServiceProvider = services.BuildServiceProvider();
WorkflowHost = ServiceProvider.GetRequiredService<IWorkflowHost>();
}
protected ITestOutputHelper TestOutputHelper { get; }
protected ServiceProvider ServiceProvider { get; }
protected IWorkflowHost WorkflowHost { get; }
public virtual void Dispose() => _tempFolder.Dispose();
public virtual async Task InitializeAsync()
{
var startupRunner = ServiceProvider.GetRequiredService<IStartupRunner>();
await startupRunner.StartupAsync();
}
public virtual async Task DisposeAsync()
{
await ServiceProvider.DisposeAsync();
Dispose();
}
private void ConfigurePersistence(IConfiguration configuration, string folder)
{
var connectionString = $@"Data Source={folder}elsa.db;Cache=Shared";
configuration.UseSqLite(connectionString).UseDefaultIdGenerator();
}
}
}

View file

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Xunit.Abstractions;
namespace Elsa.Core.IntegrationTests.Helpers
{
public class XunitConsoleForwarder : TextWriter
{
private readonly ITestOutputHelper _output;
private IList<char> _line = new List<char>();
public XunitConsoleForwarder(ITestOutputHelper output) => _output = output;
public override Encoding Encoding => Console.Out.Encoding;
public override void Write(char value)
{
if (value == '\n')
{
FlushLine();
_line = new List<char>();
return;
}
_line.Add(value);
}
protected override void Dispose(bool disposing)
{
if (_line.Count > 0)
FlushLine();
base.Dispose(disposing);
}
private void FlushLine()
{
if (_line.Count > 0 && _line.Last() == '\r')
_line.RemoveAt(_line.Count - 1);
_output.WriteLine(new string(_line.ToArray()));
}
}
}

View file

@ -1,120 +0,0 @@
// using System;
// using System.Threading;
// using System.Threading.Tasks;
// using AutoFixture;
// using Elsa.ActivityResults;
// using Elsa.Expressions;
// using Elsa.Models;
// using Elsa.Services;
// using Elsa.Services.Models;
// using Elsa.Testing.Shared.Autofixture;
// using MediatR;
// using Microsoft.Extensions.DependencyInjection;
// using Microsoft.Extensions.Logging.Abstractions;
// using Moq;
// using NodaTime;
// using NodaTime.Testing;
// using Xunit;
// using YesSql;
// using YesSql.Provider.Sqlite;
//
// namespace Elsa.Core.UnitTests
// {
// public class WorkflowHostTests : IDisposable
// {
// private readonly IFixture _fixture;
// private readonly WorkflowHost _workflowHost;
// private TemporaryFolder _tempFolder;
// private ISession _session;
//
// public WorkflowHostTests()
// {
// _fixture = new Fixture().Customize(new NodaTimeCustomization());
// _session = CreateSession();
//
// var workflowActivatorMock = new Mock<IWorkflowFactory>();
// var workflowRegistryMock = new Mock<IWorkflowRegistry>();
// var workflowInstanceManager = new WorkflowInstanceManager(_session);
// var workflowExpressionEvaluatorMock = new Mock<IExpressionEvaluator>();
// var mediatorMock = new Mock<IMediator>();
// var now = _fixture.Create<Instant>();
// var clock = new FakeClock(now);
// var logger = new NullLogger<WorkflowHost>();
// var serviceProvider = new ServiceCollection().BuildServiceProvider();
//
// workflowActivatorMock
// .Setup(x => x.InstantiateAsync(It.IsAny<WorkflowBlueprint>(), It.IsAny<string?>(), It.IsAny<CancellationToken>()))
// .ReturnsAsync((WorkflowBlueprint workflow, string? correlationId, CancellationToken cancellationToken) => new WorkflowInstance());
//
// _workflowHost = new WorkflowHost(
// workflowInstanceManager,
// workflowRegistryMock.Object,
// workflowActivatorMock.Object,
// workflowExpressionEvaluatorMock.Object,
// clock,
// mediatorMock.Object,
// serviceProvider,
// logger);
// }
//
// public void Dispose() => _session.Dispose();
//
// private ISession CreateSession()
// {
// _tempFolder = new TemporaryFolder();
// var connectionString = $@"Data Source={_tempFolder.Folder}elsa.db;Cache=Shared";
// var config = new Configuration().UseSqLite(connectionString).UseDefaultIdGenerator();
// var store = StoreFactory.CreateAndInitializeAsync(config).GetAwaiter().GetResult();
// return store.CreateSession();
// }
//
// [Fact(DisplayName = "Can run simple workflow to completed state.")]
// public async Task RunAsync01()
// {
// var activityExecutionResultMock = new Mock<IActivityExecutionResult>();
// var activity = CreateActivity(activityExecutionResult: activityExecutionResultMock.Object);
// var workflow = CreateWorkflow(activity);
// var executionContext = await _workflowHost.RunWorkflowAsync(workflow);
//
// Assert.Equal(WorkflowStatus.Completed, executionContext.UpdateWorkflowInstance().Status);
// }
//
// [Fact(DisplayName = "Invokes returned activity execution result.")]
// public async Task RunAsync02()
// {
// var activityExecutionResultMock = new Mock<IActivityExecutionResult>();
// var activity = CreateActivity(true, activityExecutionResultMock.Object);
// var workflow = CreateWorkflow(activity);
// var executionContext = await _workflowHost.RunWorkflowAsync(workflow);
//
// activityExecutionResultMock
// .Verify(x => x.ExecuteAsync(It.IsAny<ActivityExecutionContext>(), It.IsAny<CancellationToken>()), Times.Once);
// }
//
// private IActivity CreateActivity(bool canExecute = true, IActivityExecutionResult? activityExecutionResult = null)
// {
// var activityMock = new Mock<IActivity>();
// var activityId = _fixture.Create<string>();
//
// activityMock.Setup(x => x.Id).Returns(activityId);
//
// activityMock
// .Setup(x => x.CanExecuteAsync(It.IsAny<ActivityExecutionContext>(), It.IsAny<CancellationToken>()))
// .ReturnsAsync(canExecute);
//
// if (activityExecutionResult != null)
// activityMock
// .Setup(x => x.ExecuteAsync(It.IsAny<ActivityExecutionContext>(), It.IsAny<CancellationToken>()))
// .ReturnsAsync(activityExecutionResult);
//
// return activityMock.Object;
// }
//
// private WorkflowBlueprint CreateWorkflow(IActivity activity)
// {
// var workflow = new WorkflowBlueprint();
// workflow.Activities.Add(activity);
// return workflow;
// }
// }
// }