diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 47a169ed..048ecff4 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -21,3 +21,5 @@ jobs: run: dotnet restore ConductorSharp.sln - name: Build run: dotnet build --no-restore ConductorSharp.sln + - name: Test + run: dotnet test --no-restore --verbosity normal ConductorSharp.sln \ No newline at end of file diff --git a/ConductorSharp.sln b/ConductorSharp.sln index 7f457c40..f0f8822f 100644 --- a/ConductorSharp.sln +++ b/ConductorSharp.sln @@ -1,67 +1,73 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31919.166 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Engine", "src\ConductorSharp.Engine\ConductorSharp.Engine.csproj", "{22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Client", "src\ConductorSharp.Client\ConductorSharp.Client.csproj", "{3244BEE8-17C4-4B00-BEB1-A41CC3E95482}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.ApiEnabled", "examples\ConductorSharp.ApiEnabled\ConductorSharp.ApiEnabled.csproj", "{C350E5E2-EA36-4816-BCBB-CBB597AAFF78}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Definitions", "examples\ConductorSharp.Definitions\ConductorSharp.Definitions.csproj", "{68400F84-CE5A-4FFA-A417-05C798ECD5A4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{16F68738-1ED3-4646-BE01-DB9246C10E89}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.NoApi", "examples\ConductorSharp.NoApi\ConductorSharp.NoApi.csproj", "{44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}" -EndProject -Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{C398B7D9-C238-4169-86A8-B03D01FBB2BE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DE1FA421-B8D6-45A7-9667-0798A241A89C}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Debug|Any CPU.Build.0 = Debug|Any CPU - {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Release|Any CPU.ActiveCfg = Release|Any CPU - {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Release|Any CPU.Build.0 = Release|Any CPU - {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Release|Any CPU.Build.0 = Release|Any CPU - {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Release|Any CPU.Build.0 = Release|Any CPU - {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Release|Any CPU.Build.0 = Release|Any CPU - {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Release|Any CPU.Build.0 = Release|Any CPU - {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {C350E5E2-EA36-4816-BCBB-CBB597AAFF78} = {16F68738-1ED3-4646-BE01-DB9246C10E89} - {68400F84-CE5A-4FFA-A417-05C798ECD5A4} = {16F68738-1ED3-4646-BE01-DB9246C10E89} - {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9} = {16F68738-1ED3-4646-BE01-DB9246C10E89} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2443B3EC-E590-4C83-8BE2-A0787C66307C} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31919.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Engine", "src\ConductorSharp.Engine\ConductorSharp.Engine.csproj", "{22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Client", "src\ConductorSharp.Client\ConductorSharp.Client.csproj", "{3244BEE8-17C4-4B00-BEB1-A41CC3E95482}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.ApiEnabled", "examples\ConductorSharp.ApiEnabled\ConductorSharp.ApiEnabled.csproj", "{C350E5E2-EA36-4816-BCBB-CBB597AAFF78}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Definitions", "examples\ConductorSharp.Definitions\ConductorSharp.Definitions.csproj", "{68400F84-CE5A-4FFA-A417-05C798ECD5A4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{16F68738-1ED3-4646-BE01-DB9246C10E89}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.NoApi", "examples\ConductorSharp.NoApi\ConductorSharp.NoApi.csproj", "{44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}" +EndProject +Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{C398B7D9-C238-4169-86A8-B03D01FBB2BE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConductorSharp.Engine.Tests", "test\ConductorSharp.Engine.Tests\ConductorSharp.Engine.Tests.csproj", "{45AB7886-41DB-4A0E-9667-1C78D63F0FC7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DE1FA421-B8D6-45A7-9667-0798A241A89C}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22BDC06E-50E5-4FE4-97D2-CD9E07EF4842}.Release|Any CPU.Build.0 = Release|Any CPU + {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3244BEE8-17C4-4B00-BEB1-A41CC3E95482}.Release|Any CPU.Build.0 = Release|Any CPU + {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C350E5E2-EA36-4816-BCBB-CBB597AAFF78}.Release|Any CPU.Build.0 = Release|Any CPU + {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68400F84-CE5A-4FFA-A417-05C798ECD5A4}.Release|Any CPU.Build.0 = Release|Any CPU + {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9}.Release|Any CPU.Build.0 = Release|Any CPU + {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C398B7D9-C238-4169-86A8-B03D01FBB2BE}.Release|Any CPU.Build.0 = Release|Any CPU + {45AB7886-41DB-4A0E-9667-1C78D63F0FC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45AB7886-41DB-4A0E-9667-1C78D63F0FC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45AB7886-41DB-4A0E-9667-1C78D63F0FC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45AB7886-41DB-4A0E-9667-1C78D63F0FC7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C350E5E2-EA36-4816-BCBB-CBB597AAFF78} = {16F68738-1ED3-4646-BE01-DB9246C10E89} + {68400F84-CE5A-4FFA-A417-05C798ECD5A4} = {16F68738-1ED3-4646-BE01-DB9246C10E89} + {44E887F8-5E0D-4729-A4A8-AFEBBF87C6F9} = {16F68738-1ED3-4646-BE01-DB9246C10E89} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2443B3EC-E590-4C83-8BE2-A0787C66307C} + EndGlobalSection +EndGlobal diff --git a/test/ConductorSharp.Engine.Tests/ConductorSharp.Engine.Tests.csproj b/test/ConductorSharp.Engine.Tests/ConductorSharp.Engine.Tests.csproj new file mode 100644 index 00000000..e3aa706a --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/ConductorSharp.Engine.Tests.csproj @@ -0,0 +1,38 @@ + + + + net6.0 + enable + false + + + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs new file mode 100644 index 00000000..b2a725da --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs @@ -0,0 +1,16 @@ +using ConductorSharp.Engine.Tests.Samples.Workflows; + +namespace ConductorSharp.Engine.Tests.Integration +{ + public class WorkflowBuilderTests + { + [Fact] + public void BuilderReturnsCorrectDefinition() + { + var definition = JsonConvert.SerializeObject(new SendCustomerNotification().GetDefinition(), Formatting.Indented); + var expectedDefinition = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Samples/Workflows/SendCustomerNotification.json"); + + Assert.Equal(expectedDefinition, definition); + } + } +} diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGet.json b/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGet.json new file mode 100644 index 00000000..c801cab1 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGet.json @@ -0,0 +1,30 @@ +{ + "ownerApp": "undefined", + "createTime": 0, + "updateTime": 0, + "createdBy": "UNDEFINED", + "updatedBy": "UNDEFINED", + "name": "CUSTOMER_get", + "description": "{\"description\":\"Missing description\"}", + "retryCount": 0, + "timeoutSeconds": 60, + "inputKeys": [ + "customer_id" + ], + "outputKeys": [ + "name", + "address" + ], + "timeoutPolicy": "TIME_OUT_WF", + "retryLogic": "FIXED", + "retryDelaySeconds": 0, + "responseTimeoutSeconds": 60, + "concurrentExecLimit": 0, + "inputTemplate": null, + "rateLimitPerFrequency": 0, + "rateLimitFrequencyInSeconds": 1, + "isolationGroupId": null, + "executionNameSpace": null, + "ownerEmail": "undefined@undefined.local", + "pollTimeoutSeconds": 0 +} \ No newline at end of file diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs new file mode 100644 index 00000000..c5c7d639 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs @@ -0,0 +1,31 @@ +namespace ConductorSharp.Engine.Tests.Samples.Tasks; + +public partial class CustomerGetV1Input : IRequest +{ + /// + /// customer_id + /// + public dynamic CustomerId { get; set; } +} + +public partial class CustomerGetV1Output +{ +/// +/// name +/// +public dynamic Name { get; set; } + +/// +/// address +/// +public dynamic Address { get; set; } +} + +/// +/// CUSTOMER_get +/// +/// +[OriginalName("CUSTOMER_get")] +public partial class CustomerGetV1 : SimpleTaskModel +{ +} diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepare.json b/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepare.json new file mode 100644 index 00000000..50e935e3 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepare.json @@ -0,0 +1,27 @@ +{ + "ownerApp": "undefined", + "createTime": 1656663495488, + "createdBy": "", + "name": "EMAIL_prepare", + "description": "{\"description\":\"Missing description\"}", + "retryCount": 0, + "timeoutSeconds": 60, + "inputKeys": [ + "customer_name", + "address" + ], + "outputKeys": [ + "email_body" + ], + "timeoutPolicy": "TIME_OUT_WF", + "retryLogic": "FIXED", + "retryDelaySeconds": 0, + "responseTimeoutSeconds": 60, + "concurrentExecLimit": 0, + "inputTemplate": {}, + "rateLimitPerFrequency": 0, + "rateLimitFrequencyInSeconds": 1, + "ownerEmail": "undefined@undefined.local", + "pollTimeoutSeconds": 0, + "backoffScaleFactor": 1 +} \ No newline at end of file diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs new file mode 100644 index 00000000..9ad9db2d --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs @@ -0,0 +1,29 @@ +namespace ConductorSharp.Engine.Tests.Samples.Tasks; + +public partial class EmailPrepareV1Input : IRequest +{ + /// + /// address + /// + public dynamic Address { get; set; } + /// + /// name + /// + public dynamic Name { get; set; } +} + +public partial class EmailPrepareV1Output +{ + /// + /// email_body + /// + public dynamic EmailBody { get; set; } +} + +/// +/// EMAIL_prepare +/// +[OriginalName("EMAIL_prepare")] +public partial class EmailPrepareV1 : SimpleTaskModel +{ +} diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs new file mode 100644 index 00000000..cf4c50a9 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; + +namespace ConductorSharp.Engine.Tests.Samples.Workers; + +public class GetCustomerRequest : IRequest +{ + [Required] + public int CustomerId { get; set; } +} + +public class GetCustomerResponse +{ + public string Name { get; set; } + public string Address { get; set; } +} + +public class Customer +{ + public int Id { get; set; } + public string Name { get; set; } + public string Address { get; set; } +} + +[OriginalName("CUSTOMER_get")] +public class GetCustomerHandler : ITaskRequestHandler +{ + public Task Handle(GetCustomerRequest request, CancellationToken cancellationToken) => throw new NotImplementedException(); +} diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs new file mode 100644 index 00000000..0c100b98 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs @@ -0,0 +1,18 @@ +namespace ConductorSharp.Engine.Tests.Samples.Workers; + +public class PrepareEmailRequest : IRequest +{ + public string CustomerName { get; set; } + public string Address { get; set; } +} + +public class PrepareEmailResponse +{ + public string EmailBody { get; set; } +} + +[OriginalName("EMAIL_prepare")] +public class PrepareEmailHandler : ITaskRequestHandler +{ + public Task Handle(PrepareEmailRequest request, CancellationToken cancellationToken) => throw new NotImplementedException(); +} diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workflows/SendCustomerNotification.cs b/test/ConductorSharp.Engine.Tests/Samples/Workflows/SendCustomerNotification.cs new file mode 100644 index 00000000..2df608d2 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Workflows/SendCustomerNotification.cs @@ -0,0 +1,47 @@ +namespace ConductorSharp.Engine.Tests.Samples.Workflows; + +public class SendCustomerNotificationInput : WorkflowInput +{ + public dynamic CustomerId { get; set; } +} + +public class SendCustomerNotificationOutput : WorkflowOutput +{ + public dynamic EmailBody { get; set; } +} + +[OriginalName("NOTIFICATION_send_to_customer")] +public class SendCustomerNotification + : Workflow +{ + public CustomerGetV1 GetCustomer { get; set; } + public EmailPrepareV1 PrepareEmail { get; set; } + + public override WorkflowDefinition GetDefinition() + { + var builder = new WorkflowDefinitionBuilder(); + + builder.AddTask( + a => a.GetCustomer, + b => new() { CustomerId = b.WorkflowInput.CustomerId } + ); + + builder.AddTask( + a => a.PrepareEmail, + b => + new() + { + Address = b.GetCustomer.Output.Address, + Name = b.GetCustomer.Output.Name + } + ); + + return builder.Build( + options => + { + options.Version = 1; + options.OwnerEmail = "example@example.local"; + } + ); + } +} diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workflows/SendCustomerNotification.json b/test/ConductorSharp.Engine.Tests/Samples/Workflows/SendCustomerNotification.json new file mode 100644 index 00000000..83c0d144 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Samples/Workflows/SendCustomerNotification.json @@ -0,0 +1,91 @@ +{ + "ownerApp": null, + "createTime": 0, + "updateTime": 0, + "createdBy": null, + "updatedBy": null, + "name": "NOTIFICATION_send_to_customer", + "description": "{\"description\":null,\"labels\":null}", + "version": 1, + "tasks": [ + { + "queryExpression": null, + "name": "CUSTOMER_get", + "taskReferenceName": "get_customer", + "description": "{\"description\":null}", + "inputParameters": { + "customer_id": "${workflow.input.customer_id}" + }, + "type": "SIMPLE", + "dynamicTaskNameParam": null, + "caseValueParam": null, + "caseExpression": null, + "expression": null, + "evaluatorType": null, + "scriptExpression": null, + "decisionCases": null, + "dynamicForkJoinTasksParam": null, + "dynamicForkTasksParam": null, + "dynamicForkTasksInputParamName": null, + "defaultCase": null, + "forkTasks": null, + "startDelay": 0, + "subWorkflowParam": null, + "joinOn": null, + "sink": null, + "optional": false, + "taskDefinition": null, + "rateLimited": false, + "defaultExclusiveJoinTask": null, + "asyncComplete": false, + "loopCondition": null, + "loopOver": null + }, + { + "queryExpression": null, + "name": "EMAIL_prepare", + "taskReferenceName": "prepare_email", + "description": "{\"description\":null}", + "inputParameters": { + "address": "${get_customer.output.address}", + "name": "${get_customer.output.name}" + }, + "type": "SIMPLE", + "dynamicTaskNameParam": null, + "caseValueParam": null, + "caseExpression": null, + "expression": null, + "evaluatorType": null, + "scriptExpression": null, + "decisionCases": null, + "dynamicForkJoinTasksParam": null, + "dynamicForkTasksParam": null, + "dynamicForkTasksInputParamName": null, + "defaultCase": null, + "forkTasks": null, + "startDelay": 0, + "subWorkflowParam": null, + "joinOn": null, + "sink": null, + "optional": false, + "taskDefinition": null, + "rateLimited": false, + "defaultExclusiveJoinTask": null, + "asyncComplete": false, + "loopCondition": null, + "loopOver": null + } + ], + "inputParameters": [ + "{\"customer_id\":{\"value\":\"\",\"description\":\" (optional)\"}}" + ], + "outputParameters": null, + "failureWorkflow": null, + "schemaVersion": 2, + "restartable": true, + "workflowStatusListenerEnabled": true, + "ownerEmail": "example@example.local", + "timeoutPolicy": null, + "timeoutSeconds": 0, + "variables": null +} \ No newline at end of file diff --git a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs new file mode 100644 index 00000000..2cf2a99b --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs @@ -0,0 +1,16 @@ +using ConductorSharp.Engine.Tests.Samples.Workers; + +namespace ConductorSharp.Engine.Tests.Unit +{ + public class TaskDefinitionBuilderTests + { + [Fact] + public void ReturnsCorrectDefinition() + { + var definition = JsonConvert.SerializeObject(TaskDefinitionBuilder.Build(null), Formatting.Indented); + var expectedDefinition = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Samples/Tasks/CustomerGet.json"); + + Assert.Equal(expectedDefinition, definition); + } + } +} diff --git a/test/ConductorSharp.Engine.Tests/Usings.cs b/test/ConductorSharp.Engine.Tests/Usings.cs new file mode 100644 index 00000000..4435fa02 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Usings.cs @@ -0,0 +1,9 @@ +global using Xunit; +global using ConductorSharp.Engine.Interface; +global using ConductorSharp.Engine.Util; +global using MediatR; +global using ConductorSharp.Client.Model.Common; +global using ConductorSharp.Engine.Builders; +global using ConductorSharp.Engine.Tests.Samples.Tasks; +global using ConductorSharp.Engine.Model; +global using Newtonsoft.Json; \ No newline at end of file diff --git a/test/ConductorSharp.Engine.Tests/Util/EmbeddedFileHelper.cs b/test/ConductorSharp.Engine.Tests/Util/EmbeddedFileHelper.cs new file mode 100644 index 00000000..52bcbfae --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Util/EmbeddedFileHelper.cs @@ -0,0 +1,75 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace ConductorSharp.Engine.Util +{ + + internal static class EmbeddedFileHelper + { + private static string ReadAssemblyFile(Assembly assembly, string name) + { + var stream = assembly.GetManifestResourceStream(name); + + if (stream == null) + throw new InvalidOperationException($"Resource {name} does not exist."); + + using var reader = new StreamReader(stream, Encoding.UTF8); + + return reader.ReadToEnd(); + } + + public static T GetObjectFromEmbeddedFile( + string fileName, + params (string Key, object Value)[] templateParams + ) + { + fileName = fileName.Replace( + "~/", + typeof(EmbeddedFileHelper).Assembly.GetName().Name + "." + ) + .Replace("/", "."); + + var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); + + if (contents == null) + throw new Exception(); + + if (templateParams != null) + foreach (var (Key, Value) in templateParams) + contents = contents.Replace("{{" + Key + "}}", $"{Value}"); + + return JsonConvert.DeserializeObject(contents); + } + + public static string GetLinesFromEmbeddedFile(string fileName) + { + fileName = fileName.Replace( + "~/", + typeof(EmbeddedFileHelper).Assembly.GetName().Name + "." + ) + .Replace("/", "."); + + var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); + + return contents; + } + + public static Task GetObjectFromEmbeddedFileAsync( + string fileName, + params (string Key, object Value)[] templateParams + ) => Task.FromResult(GetObjectFromEmbeddedFile(fileName, templateParams)); + + public static string Reserialize( + string fileName, + params (string Key, object Value)[] templateParams + ) + { + var file = GetObjectFromEmbeddedFile(fileName, templateParams); + return JsonConvert.SerializeObject(file); + } + } +} \ No newline at end of file