diff --git a/ActionFlow.Tests/ActionFlow.Tests.csproj b/ActionFlow.Tests/ActionFlow.Tests.csproj index aaf7cd2..b193972 100644 --- a/ActionFlow.Tests/ActionFlow.Tests.csproj +++ b/ActionFlow.Tests/ActionFlow.Tests.csproj @@ -10,6 +10,7 @@ + @@ -24,4 +25,10 @@ + + + Always + + + diff --git a/ActionFlow.Tests/Actions/CallWorkflowActionTests.cs b/ActionFlow.Tests/Actions/CallWorkflowActionTests.cs index 6fa2099..7134e55 100644 --- a/ActionFlow.Tests/Actions/CallWorkflowActionTests.cs +++ b/ActionFlow.Tests/Actions/CallWorkflowActionTests.cs @@ -1,4 +1,5 @@ using ActionFlow.Actions; +using ActionFlow.Domain.Actions; using ActionFlow.Domain.Engine; using ActionFlow.Engine; using ActionFlow.Engine.Factories; @@ -7,71 +8,70 @@ namespace ActionFlow.Tests.Actions { - [TestClass] - public class CallWorkflowActionTests - { - [TestMethod] - public async Task When_executing_it_should_call_other_workflow_and_get_output_variable() - { - //Arrange - var workflowProvider = Substitute.For(); - var workflows = CreateFakeWorkflowsWithOutput(); - workflowProvider.GetAllWorkflows().Returns(workflows); + [TestClass] + public class CallWorkflowActionTests + { + [TestMethod] + public async Task When_executing_it_should_call_other_workflow_and_get_output_variable() + { + //Arrange + var workflowProvider = Substitute.For(); + var workflows = CreateFakeWorkflowsWithOutput(); + workflowProvider.GetAllWorkflows().Returns(workflows); - var stepActionFactory = Substitute.For(); - stepActionFactory.Get("Variable").Returns(new SetVariableAction()); + var stepActionFactory = Substitute.For(); + stepActionFactory.Get("Variable").Returns(new SetVariableAction()); - var stepExecutionEvaluator = new StepExecutionEvaluator(); + var stepExecutionEvaluator = new StepExecutionEvaluator(); + var actionFlowEngine = new ActionFlowEngine(workflowProvider, stepActionFactory, stepExecutionEvaluator); - var actionFlowEngine = new ActionFlowEngine(workflowProvider, stepActionFactory, stepExecutionEvaluator); + var sut = new CallWorkflowAction(); + var executionContext = new ActionFlow.Engine.ExecutionContext(actionFlowEngine); + var parameters = new Dictionary + { + { "age", "18" } + }; + var targetWorkflowName = "Test Workflow Rule 2"; + var resultVariableName = "result"; + executionContext.AddOrUpdateActionProperty(CallWorkflowAction.WorkflowNameKey, targetWorkflowName); + executionContext.AddOrUpdateActionProperty(CallWorkflowAction.ResultVariableKey, resultVariableName); + executionContext.AddOrUpdateActionProperty(CallWorkflowAction.ParametersKey, parameters); + sut.SetExecutionContext(executionContext); - var sut = new CallWorkflowAction(); - var executionContext = new ActionFlow.Engine.ExecutionContext(actionFlowEngine); - var parameters = new Dictionary - { - { "age", "18" } - }; - var targetWorkflowName = "Test Workflow Rule 2"; - var resultVariableName = "result"; - executionContext.AddOrUpdateActionProperty(CallWorkflowAction.WorkflowNameKey, targetWorkflowName); - executionContext.AddOrUpdateActionProperty(CallWorkflowAction.ResultVariableKey, resultVariableName); - executionContext.AddOrUpdateActionProperty(CallWorkflowAction.ParametersKey, parameters); - sut.SetExecutionContext(executionContext); + //Act + await sut.ExecuteAction(); - //Act - await sut.ExecuteAction(); + //Assert + var output = executionContext.EvaluateExpression>(resultVariableName); + Assert.AreEqual(true, output["canVote"]); + } - //Assert - var output = executionContext.EvaluateExpression>(resultVariableName); - Assert.IsTrue((bool)output["canVote"]); - } + private static List CreateFakeWorkflowsWithOutput() + { + List workflows = []; - private static List CreateFakeWorkflowsWithOutput() - { - List workflows = []; + var targetWorkflowName = "Test Workflow Rule 2"; - var targetWorkflowName = "Test Workflow Rule 2"; + var steps2 = new List + { + new("test variable value", "Variable", new Dictionary + { + { + SetVariableAction.VariablesKey, new Dictionary + { + { "canVote", "age >= 18" } + } + } + }) + }; - var steps2 = new List - { - new("test variable value", "Variable", new Dictionary - { - { - SetVariableAction.VariablesKey, new Dictionary - { - { "canVote", "age >= 18" } - } - } - }) - }; - - Workflow workflow2 = new Workflow(targetWorkflowName, steps2, + Workflow workflow2 = new Workflow(targetWorkflowName, steps2, [ - new Parameter{ Name = "canVote", Expression = "canVote"} - ]); - workflows.Add(workflow2); + new() { Name = "canVote", Expression = "canVote"} + ]); + workflows.Add(workflow2); - return workflows; - } - } + return workflows; + } + } } diff --git a/ActionFlow.Tests/Actions/ControlFlowActionTests.cs b/ActionFlow.Tests/Actions/ControlFlowActionTests.cs index 4dee0c8..b264a6c 100644 --- a/ActionFlow.Tests/Actions/ControlFlowActionTests.cs +++ b/ActionFlow.Tests/Actions/ControlFlowActionTests.cs @@ -1,138 +1,137 @@ using ActionFlow.Actions; using ActionFlow.Domain.Actions; -using ActionFlow.Domain.Engine; using ActionFlow.Engine; -using ActionFlow.Engine.Factories; using NSubstitute; namespace ActionFlow.Tests.Actions { - [TestClass] - public class ControlFlowActionTests : ActionBaseTests - { - [TestMethod] - public async Task When_executing_it_should_call_only_valid_scoped_workflow_steps() - { - //Arrange - var sut = new ControlFlowAction(); - var stepExecutionEvaluator = new StepExecutionEvaluator(); - ActionFlowEngine.GetStepExecutionEvaluator().Returns(stepExecutionEvaluator); - var executionContext = ExecutionContext; + [TestClass] + public class ControlFlowActionTests : ActionBaseTests + { + [TestMethod] + public async Task When_executing_it_should_call_only_valid_scoped_workflow_steps() + { + //Arrange + var sut = new ControlFlowAction(); + var stepExecutionEvaluator = new StepExecutionEvaluator(); + ActionFlowEngine.GetStepExecutionEvaluator().Returns(stepExecutionEvaluator); + var executionContext = ExecutionContext; - var conditions = CreateScopedWorkflows(); - executionContext.AddOrUpdateParameter("age", 18); - executionContext.AddOrUpdateActionProperty(ControlFlowAction.ConditionsKey, conditions); - sut.SetExecutionContext(executionContext); + var conditions = CreateScopedWorkflows(); + executionContext.AddOrUpdateParameter("age", 18); + executionContext.AddOrUpdateActionProperty(ControlFlowAction.ConditionsKey, conditions); + sut.SetExecutionContext(executionContext); - //Act - await sut.ExecuteAction(); + //Act + await sut.ExecuteAction(); - //Assert - Assert.AreEqual(18, executionContext.EvaluateExpression("age")); - Assert.AreEqual(true, executionContext.EvaluateExpression("canWalk")); - } + //Assert + Assert.AreEqual(18, executionContext.EvaluateExpression("age")); + Assert.IsTrue(executionContext.EvaluateExpression("canWalk")); + } - [TestMethod] - public async Task When_executing_it_should_call_all_scoped_workflow_steps() - { - //Arrange - var sut = new ControlFlowAction(); - var stepExecutionEvaluator = new StepExecutionEvaluator(); - ActionFlowEngine.GetStepExecutionEvaluator().Returns(stepExecutionEvaluator); - var executionContext = ExecutionContext; + [TestMethod] + public async Task When_executing_it_should_call_all_scoped_workflow_steps() + { + //Arrange + var sut = new ControlFlowAction(); + var stepExecutionEvaluator = new StepExecutionEvaluator(); + ActionFlowEngine.GetStepExecutionEvaluator().Returns(stepExecutionEvaluator); + var executionContext = ExecutionContext; - var conditions = CreateScopedWorkflowsThatAllWillBeCalled(); - executionContext.AddOrUpdateParameter("age", 1); - executionContext.AddOrUpdateActionProperty(ControlFlowAction.ConditionsKey, conditions); - sut.SetExecutionContext(executionContext); + var conditions = CreateScopedWorkflowsThatAllWillBeCalled(); + executionContext.AddOrUpdateParameter("age", 1); + executionContext.AddOrUpdateActionProperty(ControlFlowAction.ConditionsKey, conditions); + sut.SetExecutionContext(executionContext); - //Act - await sut.ExecuteAction(); + //Act + await sut.ExecuteAction(); - //Assert - Assert.AreEqual(true, executionContext.EvaluateExpression("isBaby")); - Assert.AreEqual(18, executionContext.EvaluateExpression("age")); - Assert.AreEqual(true, executionContext.EvaluateExpression("canWalk")); - } + //Assert + Assert.IsTrue(executionContext.EvaluateExpression("isBaby")); + Assert.AreEqual(18, executionContext.EvaluateExpression("age")); + Assert.IsTrue(executionContext.EvaluateExpression("canWalk")); + } - private static List CreateScopedWorkflows() - { - var conditions = new List - { - new() { - Expression = "age == 1", - Steps = + private static List CreateScopedWorkflows() + { + var conditions = new List + { + new() { + Expression = "age == 1", + Steps = [ - new Step("Set canWalk to false", "Variable", new Dictionary - { - { - SetVariableAction.VariablesKey, new Dictionary - { - { "canWalk", "false" } - } - } - }) - ] - }, - new() { - Expression = "age == 18", - Steps = + new ("Set canWalk to false", "Variable", new Dictionary + { + { + SetVariableAction.VariablesKey, new Dictionary + { + { "canWalk", "false" } + } + } + }) + ] + }, + new() { + Expression = "age == 18", + Steps = [ - new Step("Set canWalk to true", "Variable", new Dictionary - { - { - SetVariableAction.VariablesKey, new Dictionary - { - { "canWalk", "true" } - } - } - }) - ] - } - }; + new("Set canWalk to true", "Variable", new Dictionary + { + { + SetVariableAction.VariablesKey, new Dictionary + { + { "canWalk", "true" } + } + } + }) + ] + } + }; - return conditions; - } + return conditions; + } - private static List CreateScopedWorkflowsThatAllWillBeCalled() - { - var conditions = new List - { - new() { - Expression = "age == 1", - Steps = + private static List CreateScopedWorkflowsThatAllWillBeCalled() + { + var conditions = new List + { + new() { + Expression = "age == 1", + Steps = [ - new Step("Set canWalk to false", "Variable", new Dictionary - { - { - SetVariableAction.VariablesKey, new Dictionary - { - { "canWalk", "false" }, - { "isBaby", "true" }, - { "age", "18" } - } - } - }) - ] - }, - new() { - Expression = "age == 18", - Steps = + new("Set canWalk to false", "Variable", new Dictionary + { + { + SetVariableAction.VariablesKey, new Dictionary + { + { "canWalk", "false" }, + { "isBaby", "true" }, + { "age", "18" } + } + } + }) + ] + }, + new() { + Expression = "age == 18", + Steps = [ - new Step("Set canWalk to true", "Variable", new Dictionary - { - { - SetVariableAction.VariablesKey, new Dictionary - { - { "canWalk", "true" } - } - } - }) - ] - } - }; + new("Set canWalk to true", "Variable", new Dictionary + { + { + SetVariableAction.VariablesKey, new Dictionary + { + { "canWalk", "true" } + } + } + }) + ] + } + }; - return conditions; - } - } + + return conditions; + } + } } diff --git a/ActionFlow.Tests/Actions/ForLoopActionTests.cs b/ActionFlow.Tests/Actions/ForLoopActionTests.cs index 57c5996..39644c9 100644 --- a/ActionFlow.Tests/Actions/ForLoopActionTests.cs +++ b/ActionFlow.Tests/Actions/ForLoopActionTests.cs @@ -34,20 +34,20 @@ public async Task When_executing_it_should_repeat_steps_3_times() Assert.AreEqual(21, executionContext.EvaluateExpression("age")); } - private static List CreateLoopSteps() - { - var steps = new List - { - new("Increment age by 1", "Variable", new Dictionary - { - { - SetVariableAction.VariablesKey, new Dictionary - { - { "age", "age + 1" } - } - } - }) - }; + private static List CreateLoopSteps() + { + var steps = new List + { + new("Increment age by 1", "Variable", new Dictionary + { + { + SetVariableAction.VariablesKey, new Dictionary + { + { "age", "age + 1" } + } + } + }) + }; return steps; } diff --git a/ActionFlow.Tests/Engine/ActionFlowEngineTests.cs b/ActionFlow.Tests/Engine/ActionFlowEngineTests.cs index f133697..225b6e7 100644 --- a/ActionFlow.Tests/Engine/ActionFlowEngineTests.cs +++ b/ActionFlow.Tests/Engine/ActionFlowEngineTests.cs @@ -7,97 +7,97 @@ namespace ActionFlow.Tests.Engine { - [TestClass] - public class ActionFlowEngineTests - { - [TestMethod] - public async Task When_running_rule_engine_with_basic_workflow_it_should_execute() - { - //Arrange - var workflowProvider = Substitute.For(); - var workflows = CreateFakeWorkflows(); - workflowProvider.GetAllWorkflows().Returns(workflows); - - var stepActionFactory = Substitute.For(); - var stepExecutionEvaluator = Substitute.For(); - - var actionFlowEngine = new ActionFlowEngine(workflowProvider, stepActionFactory, stepExecutionEvaluator); - - var inputs = new Parameter[] - { - new() { Name = "test", Expression = "true"} - }; - - //Act - await actionFlowEngine.ExecuteWorkflowAsync("Test Workflow Rule 1", inputs); - - //Assert - await stepExecutionEvaluator.ReceivedWithAnyArgs(2).EvaluateAndRunStep(workflows[0].Steps[0], new ExecutionContext(actionFlowEngine), stepActionFactory); - } - - [TestMethod] - public async Task When_running_rule_engine_with_output_parameter_workflow_it_evaluate_output() - { - //Arrange - var workflowProvider = Substitute.For(); - var workflows = CreateFakeWorkflowsWithOutput(); - workflowProvider.GetAllWorkflows().Returns(workflows); - - var stepActionFactory = Substitute.For(); - var stepExecutionEvaluator = Substitute.For(); - var actionFlowEngine = new ActionFlowEngine(workflowProvider, stepActionFactory, stepExecutionEvaluator); - - var executionContext = new ExecutionContext(actionFlowEngine); - executionContext.AddOrUpdateParameter(new Parameter { Name = "age", Expression = "1" }); - executionContext.AddOrUpdateParameter(new Parameter { Name = "canWalk", Expression = "true" }); - - stepExecutionEvaluator.EvaluateAndRunStep(workflows[0].Steps[0], executionContext, stepActionFactory).ReturnsForAnyArgs(executionContext); - - //Act - var output = await actionFlowEngine.ExecuteWorkflowAsync("Test Workflow Rule 1", executionContext); - - //Assert - await stepExecutionEvaluator.ReceivedWithAnyArgs(1).EvaluateAndRunStep(workflows[0].Steps[0], new ExecutionContext(actionFlowEngine), stepActionFactory); - Assert.AreEqual(2, output.OutputParameters.Count); - Assert.IsFalse((bool)output.OutputParameters["canVote"]); - Assert.AreEqual(1, output.OutputParameters["age"]); - } - - private static List CreateFakeWorkflows() - { - List workflows = []; - var steps = new List - { - new("initialize", "Variable", new Dictionary - { - { "age", "1" }, - { "canWalk", "true" }, - }), - new("test variable value", "Variable", [], "age == 1 && canWalk == true") - }; - - Workflow workflow = new Workflow("Test Workflow Rule 1", steps); - workflows.Add(workflow); - - return workflows; - } - - private static List CreateFakeWorkflowsWithOutput() - { - List workflows = []; - var steps = new List - { - new("test variable value", "Variable", [], "age == 1 && canWalk == true") - }; - - Workflow workflow = new Workflow("Test Workflow Rule 1", steps, + [TestClass] + public class ActionFlowEngineTests + { + [TestMethod] + public async Task When_running_rule_engine_with_basic_workflow_it_should_execute() + { + //Arrange + var workflowProvider = Substitute.For(); + var workflows = CreateFakeWorkflows(); + workflowProvider.GetAllWorkflows().Returns(workflows); + + var stepActionFactory = Substitute.For(); + var stepExecutionEvaluator = Substitute.For(); + + var actionFlowEngine = new ActionFlowEngine(workflowProvider, stepActionFactory, stepExecutionEvaluator); + + var inputs = new Parameter[] + { + new() { Name = "test", Expression = "true"} + }; + + //Act + await actionFlowEngine.ExecuteWorkflowAsync("Test Workflow Rule 1", inputs); + + //Assert + await stepExecutionEvaluator.ReceivedWithAnyArgs(2).EvaluateAndRunStep(workflows[0].Steps[0], new ExecutionContext(actionFlowEngine), stepActionFactory); + } + + [TestMethod] + public async Task When_running_rule_engine_with_output_parameter_workflow_it_evaluate_output() + { + //Arrange + var workflowProvider = Substitute.For(); + var workflows = CreateFakeWorkflowsWithOutput(); + workflowProvider.GetAllWorkflows().Returns(workflows); + + var stepActionFactory = Substitute.For(); + var stepExecutionEvaluator = Substitute.For(); + var actionFlowEngine = new ActionFlowEngine(workflowProvider, stepActionFactory, stepExecutionEvaluator); + + var executionContext = new ExecutionContext(actionFlowEngine); + executionContext.AddOrUpdateParameter(new Parameter { Name = "age", Expression = "1" }); + executionContext.AddOrUpdateParameter(new Parameter { Name = "canWalk", Expression = "true" }); + + stepExecutionEvaluator.EvaluateAndRunStep(workflows[0].Steps[0], executionContext, stepActionFactory).ReturnsForAnyArgs(executionContext); + + //Act + var output = await actionFlowEngine.ExecuteWorkflowAsync("Test Workflow Rule 1", executionContext); + + //Assert + await stepExecutionEvaluator.ReceivedWithAnyArgs(1).EvaluateAndRunStep(workflows[0].Steps[0], new ExecutionContext(actionFlowEngine), stepActionFactory); + Assert.AreEqual(2 ,output.OutputParameters.Count); + Assert.AreEqual(false, output.OutputParameters["canVote"]); + Assert.AreEqual(1, output.OutputParameters["age"]); + } + + private static List CreateFakeWorkflows() + { + List workflows = []; + var steps = new List + { + new("initialize", "Variable", new Dictionary + { + { "age", "1" }, + { "canWalk", "true" }, + }), + new("test variable value", "Variable", [], "age == 1 && canWalk == true") + }; + + Workflow workflow = new Workflow("Test Workflow Rule 1", steps); + workflows.Add(workflow); + + return workflows; + } + + private static List CreateFakeWorkflowsWithOutput() + { + List workflows = []; + var steps = new List + { + new("test variable value", "Variable", [], "age == 1 && canWalk == true") + }; + + Workflow workflow = new Workflow("Test Workflow Rule 1", steps, [ - new Parameter{ Name = "canVote", Expression = "age >= 18 && canWalk == true"}, - new Parameter{ Name = "age", Expression = "age"} - ]); - workflows.Add(workflow); - - return workflows; - } - } + new() { Name = "canVote", Expression = "age >= 18 && canWalk == true"}, + new() { Name = "age", Expression = "age"} + ]); + workflows.Add(workflow); + + return workflows; + } + } } diff --git a/ActionFlow.Tests/Extensions/ServiceCollectionExtensionsTests.cs b/ActionFlow.Tests/Extensions/ServiceCollectionExtensionsTests.cs index 5538f9d..604dff3 100644 --- a/ActionFlow.Tests/Extensions/ServiceCollectionExtensionsTests.cs +++ b/ActionFlow.Tests/Extensions/ServiceCollectionExtensionsTests.cs @@ -23,10 +23,10 @@ public void When_using_action_flow_engine_it_should_register_all_required_servic //Assert Assert.IsNotNull(provider.GetRequiredService()); - Assert.IsNotNull(provider.GetRequiredService()); Assert.IsNotNull(provider.GetRequiredService()); Assert.IsNotNull(provider.GetRequiredService()); Assert.IsNotNull(provider.GetRequiredService()); + Assert.IsNotNull(provider.GetRequiredService()); Assert.IsNotNull(provider.GetRequiredService>()); var stepActionFactory = provider.GetRequiredService(); diff --git a/ActionFlow.Tests/Providers/WorkflowProviderBuiltinExtensionsTests.cs b/ActionFlow.Tests/Providers/WorkflowProviderBuiltinExtensionsTests.cs new file mode 100644 index 0000000..0ac97d3 --- /dev/null +++ b/ActionFlow.Tests/Providers/WorkflowProviderBuiltinExtensionsTests.cs @@ -0,0 +1,72 @@ +using ActionFlow.Domain.Engine; +using ActionFlow.Engine.Providers; +using ActionFlow.Engine.Providers.Extensions; +using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using System.Text.Json; + +namespace ActionFlow.Tests.Providers; + +[TestClass] +public class WorkflowProviderBuiltinExtensionsTests +{ + [TestMethod] + public void When_using_from_json_it_should_add_workflow() + { + //Arrange + var workflows = new List + { + new("Test", + [ + new("initialize", "Variable", new Dictionary + { + { "age", "1" }, + { "canWalk", "true" }, + }), + new("test variable value", "Variable", [], "age == 1 && canWalk == true") + ]) + }; + + var workflowJson = JsonSerializer.SerializeToNode(workflows); + var services = new ServiceCollection(); + services.AddJsonWorkflowProvider(workflowJson!.AsArray()); + + //Act + var provider = services.BuildServiceProvider(); + + //Assert + var workflowProvider = provider.GetRequiredService(); + var result = workflowProvider.GetAllWorkflows(); + result.Should().BeEquivalentTo(workflows); + } + + [TestMethod] + public void When_using_from_json_file_it_should_add_workflow() + { + //Arrange + var expected = new List + { + new("Test", + [ + new("initialize", "Variable", new Dictionary + { + { "age", "1" }, + { "canWalk", "true" }, + }), + new("test variable value", "Variable", [], "age == 1 && canWalk == true") + ]) + }; + + var services = new ServiceCollection(); + var path = Path.Combine(Environment.CurrentDirectory, @"Providers\workflows.json"); + services.AddJsonWorkflowProvider(path); + + //Act + var provider = services.BuildServiceProvider(); + + //Assert + var workflowProvider = provider.GetRequiredService(); + var result = workflowProvider.GetAllWorkflows(); + result.Should().BeEquivalentTo(expected); + } +} diff --git a/ActionFlow.Tests/Providers/WorkflowProviderTests.cs b/ActionFlow.Tests/Providers/WorkflowProviderTests.cs new file mode 100644 index 0000000..d38b811 --- /dev/null +++ b/ActionFlow.Tests/Providers/WorkflowProviderTests.cs @@ -0,0 +1,26 @@ +using ActionFlow.Domain.Engine; +using ActionFlow.Engine.Providers; + +namespace ActionFlow.Tests.Providers; + +[TestClass] +public class WorkflowProviderTests +{ + [TestMethod] + public void When_getting_all_workflows_it_should_return_a_list() + { + //Arrange + var testWorkflows = new List + { + new("test", []) + }; + var sut = new WorkflowProvider(testWorkflows); + + //Act + var result = sut.GetAllWorkflows(); + + //Assert + Assert.IsInstanceOfType(result, typeof(List)); + Assert.IsTrue(result.Contains(testWorkflows[0])); + } +} diff --git a/ActionFlow.Tests/Providers/workflows.json b/ActionFlow.Tests/Providers/workflows.json new file mode 100644 index 0000000..30994cc --- /dev/null +++ b/ActionFlow.Tests/Providers/workflows.json @@ -0,0 +1,23 @@ +[ + { + "WorkflowName": "Test", + "Steps": [ + { + "Name": "initialize", + "ActionType": "Variable", + "ConditionExpression": null, + "Properties": { + "age": "1", + "canWalk": "true" + } + }, + { + "Name": "test variable value", + "ActionType": "Variable", + "ConditionExpression": "age == 1 \u0026\u0026 canWalk == true", + "Properties": {} + } + ], + "OutputParameters": null + } +] \ No newline at end of file diff --git a/ActionFlow/Domain/Actions/ApiCallResult.cs b/ActionFlow/Domain/Actions/ApiCallResult.cs index d4eac6c..44a894f 100644 --- a/ActionFlow/Domain/Actions/ApiCallResult.cs +++ b/ActionFlow/Domain/Actions/ApiCallResult.cs @@ -2,10 +2,17 @@ namespace ActionFlow.Domain.Actions { - public class ApiCallResult(JsonNode body, Dictionary> headers, int statusCode) - { - public JsonNode Body { get; } = body; - public int StatusCode { get; } = statusCode; - public Dictionary> Headers { get; } = headers; - } + public class ApiCallResult + { + public ApiCallResult(JsonNode body, Dictionary> headers, int statusCode) + { + Body = body; + Headers = headers; + StatusCode = statusCode; + } + + public JsonNode Body { get; } + public int StatusCode { get; } + public Dictionary> Headers { get; } = []; + } } diff --git a/ActionFlow/Domain/Engine/Step.cs b/ActionFlow/Domain/Engine/Step.cs index e4576e0..047e747 100644 --- a/ActionFlow/Domain/Engine/Step.cs +++ b/ActionFlow/Domain/Engine/Step.cs @@ -1,10 +1,19 @@ namespace ActionFlow.Domain.Engine { - public class Step(string name, string actionType, Dictionary? properties = null, string? conditionExpression = null) + public class Step { - public string Name { get; } = name; - public string ActionType { get; } = actionType; - public string? ConditionExpression { get; } = conditionExpression; - public Dictionary? Properties { get; } = properties ?? []; + public Step(string name, string actionType, Dictionary? properties = null, string? conditionExpression = null) + { + Name = name; + ActionType = actionType; + Properties = properties ?? []; + ConditionExpression = conditionExpression; + } + + public string Name { get; } + public string ActionType { get; } + public string? ConditionExpression { get; } + + public Dictionary? Properties { get; } } } diff --git a/ActionFlow/Engine/ExecutionContext.cs b/ActionFlow/Engine/ExecutionContext.cs index bfb4b6a..8c2b608 100644 --- a/ActionFlow/Engine/ExecutionContext.cs +++ b/ActionFlow/Engine/ExecutionContext.cs @@ -2,65 +2,72 @@ namespace ActionFlow.Engine { - public class ExecutionContext(IActionFlowEngine actionFlowEngine) - { - private readonly Interpreter _intepreter = new Interpreter(); - private readonly IActionFlowEngine _actionFlowEngine = actionFlowEngine; + public class ExecutionContext + { + private readonly Interpreter _intepreter; + private readonly IActionFlowEngine _actionFlowEngine; - private Dictionary _actionProperties { get; } = []; + public ExecutionContext(IActionFlowEngine actionFlowEngine) + { + _actionProperties = []; + _intepreter = new Interpreter(); + _actionFlowEngine = actionFlowEngine; + } - public IActionFlowEngine GetCurrentEngine() => _actionFlowEngine; + private Dictionary _actionProperties { get; } - public void AddOrUpdateParameter(Domain.Engine.Parameter parameter) - { - AddOrUpdateParameter(parameter.Name!, _intepreter.Eval(parameter.Expression)); - } + public IActionFlowEngine GetCurrentEngine() => _actionFlowEngine; - public void AddOrUpdateParameter(string name, object value) - { - _intepreter.SetVariable(name, value); - } + public void AddOrUpdateParameter(Domain.Engine.Parameter parameter) + { + AddOrUpdateParameter(parameter.Name!, _intepreter.Eval(parameter.Expression)); + } - public T GetParameter(string key) - { - return _intepreter.Eval(key); - } + public void AddOrUpdateParameter(string name, object value) + { + _intepreter.SetVariable(name, value); + } - public T EvaluateExpression(string expression) - { - return _intepreter.Eval(expression); - } + public T GetParameter(string key) + { + return _intepreter.Eval(key); + } - public void AddOrUpdateActionProperty(string key, object value) - { - if (_actionProperties.ContainsKey(key)) - { - _actionProperties[key] = value; - } - else - { - _actionProperties.Add(key, value); - } - } + public T EvaluateExpression(string expression) + { + return _intepreter.Eval(expression); + } - public T? GetActionProperty(string key) - { - if (_actionProperties.TryGetValue(key, out var value)) - { - return (T)value; - } + public void AddOrUpdateActionProperty(string key, object value) + { + if (_actionProperties.ContainsKey(key)) + { + _actionProperties[key] = value; + } + else + { + _actionProperties.Add(key, value); + } + } - return default; - } + public T? GetActionProperty(string key) + { + if (_actionProperties.TryGetValue(key, out var value)) + { + return (T)value; + } - public void ClearActionProperties() - { - foreach (var propertyKey in _actionProperties.Keys) - { - _intepreter.UnsetVariable(propertyKey); - } + return default; + } - _actionProperties.Clear(); - } - } + public void ClearActionProperties() + { + foreach (var propertyKey in _actionProperties.Keys) + { + _intepreter.UnsetVariable(propertyKey); + } + + _actionProperties.Clear(); + } + } } diff --git a/ActionFlow/Engine/Providers/Extensions/WorkflowProviderBuiltinExtensions.cs b/ActionFlow/Engine/Providers/Extensions/WorkflowProviderBuiltinExtensions.cs new file mode 100644 index 0000000..22f9dc2 --- /dev/null +++ b/ActionFlow/Engine/Providers/Extensions/WorkflowProviderBuiltinExtensions.cs @@ -0,0 +1,59 @@ +using ActionFlow.Domain.Engine; +using Microsoft.Extensions.DependencyInjection; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace ActionFlow.Engine.Providers.Extensions; +public static class WorkflowProviderBuiltinExtensions +{ + public static void AddJsonWorkflowProvider(this IServiceCollection services, string jsonPath) + { + var jsonString = File.ReadAllText(jsonPath); + var workflowsJson = JsonArray.Parse(jsonString)?.AsArray(); + + services.AddJsonWorkflowProvider(workflowsJson!); + } + + public static void AddJsonWorkflowProvider(this IServiceCollection services, JsonArray workflowsJson) + { + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + options.Converters.Add(new ObjectToStringConverter()); + + var workflows = workflowsJson.Deserialize>(options); + + if (workflows != null) + { + services.AddScoped(x => + { + return new WorkflowProvider([.. workflows]); + }); + } + } + + public class ObjectToStringConverter : JsonConverter + { + public override bool CanConvert(Type typeToConvert) => typeof(object) == typeToConvert; + + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + { + return reader.TryGetInt64(out long l) ? l.ToString() : reader.GetDouble().ToString(); + } + if (reader.TokenType == JsonTokenType.String) + { + return reader.GetString(); + } + using (JsonDocument document = JsonDocument.ParseValue(ref reader)) + { + return document.RootElement.Clone().ToString(); + } + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString()); + } + } +} diff --git a/ActionFlow/Engine/Providers/IWorkflowProvider.cs b/ActionFlow/Engine/Providers/IWorkflowProvider.cs index 9c31290..884116d 100644 --- a/ActionFlow/Engine/Providers/IWorkflowProvider.cs +++ b/ActionFlow/Engine/Providers/IWorkflowProvider.cs @@ -2,8 +2,8 @@ namespace ActionFlow.Engine.Providers { - public interface IWorkflowProvider - { - List GetAllWorkflows(); - } + public interface IWorkflowProvider + { + List GetAllWorkflows(); + } } \ No newline at end of file diff --git a/ActionFlow/Engine/Providers/WorkflowProvider.cs b/ActionFlow/Engine/Providers/WorkflowProvider.cs index accf8db..d6c5deb 100644 --- a/ActionFlow/Engine/Providers/WorkflowProvider.cs +++ b/ActionFlow/Engine/Providers/WorkflowProvider.cs @@ -2,29 +2,32 @@ namespace ActionFlow.Engine.Providers { - public class WorkflowProvider : IWorkflowProvider - { - public List GetAllWorkflows() - { - List workflows = []; + public class BlankWorkflowProvider() : WorkflowProvider(new List()) + { - //Test - //Todo: Load from DB, Json, or other source - var steps = new List - { - new("initialize", "Variable", new Dictionary - { - { "age", "1" }, - { "canWalk", "true" }, - }), - new("test variable value", "Variable", [], "age == 1 && canWalk == true") - }; + } - Workflow workflow = new Workflow("Test Workflow Rule 1", steps); - workflows.Add(workflow); - //Test End + public class WorkflowProvider(List workflows) : IWorkflowProvider + { + public List GetAllWorkflows() + { + //Test + //Todo: Load from DB, Json, or other source + //var steps = new List + //{ + // new("initialize", "Variable", new Dictionary + // { + // { "age", "1" }, + // { "canWalk", "true" }, + // }), + // new("test variable value", "Variable", [], "age == 1 && canWalk == true") + //}; - return workflows; - } - } + //Workflow workflow = new Workflow("Test Workflow Rule 1", steps); + //workflows.Add(workflow); + ////Test End + + return workflows; + } + } } diff --git a/ActionFlow/Extensions/ServiceCollectionExtensions.cs b/ActionFlow/Extensions/ServiceCollectionExtensions.cs index 2deb1a9..95c46a5 100644 --- a/ActionFlow/Extensions/ServiceCollectionExtensions.cs +++ b/ActionFlow/Extensions/ServiceCollectionExtensions.cs @@ -27,7 +27,7 @@ public static void AddDefaultActions(this IServiceCollection services) public static void UseActionFlowEngine(this IServiceCollection services) { services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped();