Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jakemoresca committed Nov 15, 2023
1 parent e58a621 commit 2a02a42
Show file tree
Hide file tree
Showing 14 changed files with 444 additions and 0 deletions.
24 changes: 24 additions & 0 deletions ActionFlow.Tests/ActionFlow.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="RulesEngine" Version="5.0.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ActionFlow\ActionFlow.csproj" />
</ItemGroup>

</Project>
56 changes: 56 additions & 0 deletions ActionFlow.Tests/Engine/RuleEngineWrapperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using ActionFlow.Engine;
using NSubstitute;
using RulesEngine.Models;
using System.Dynamic;

namespace ActionFlow.Tests.Engine
{
[TestClass]
public class RuleEngineWrapperTests
{
[TestMethod]
public void When_running_rule_engine_with_basic_workflow_it_should_execute()
{
//Arrange
var workflowProvider = Substitute.For<IWorkflowProvider>();
workflowProvider.GetAllWorkflows().Returns(CreateFakeWorkflows());

var rulesEngine = new RuleEngineWrapper(workflowProvider);

//Act
dynamic datas = new ExpandoObject();
datas.count = 1;
var inputs = new dynamic[]
{
datas
};

var resultList = rulesEngine.ExecuteAllRulesAsync("Test Workflow Rule 1", inputs).Result;

//Assert
Assert.IsTrue(resultList.TrueForAll(x => x.IsSuccess));
}

private List<Workflow> CreateFakeWorkflows()
{
List<Workflow> workflows = new List<Workflow>();
Workflow workflow = new Workflow();
workflow.WorkflowName = "Test Workflow Rule 1";

List<Rule> rules = new List<Rule>();

Rule rule = new Rule();
rule.RuleName = "Test Rule";
rule.SuccessEvent = "Count is within tolerance.";
rule.ErrorMessage = "Over expected.";
rule.Expression = "count < 3";
rule.RuleExpressionType = RuleExpressionType.LambdaExpression;

rules.Add(rule);
workflow.Rules = rules;
workflows.Add(workflow);

return workflows;
}
}
}
45 changes: 45 additions & 0 deletions ActionFlow.Tests/Engine/WorkflowTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using RulesEngine.Models;
using System.Dynamic;

namespace ActionFlow.Tests.Engine
{
[TestClass]
public class WorkflowTests
{
[TestMethod]
public void When_running_basic_workflow_it_should_execute()
{
//Arrange
List<Workflow> workflows = new List<Workflow>();
Workflow workflow = new Workflow();
workflow.WorkflowName = "Test Workflow Rule 1";

List<Rule> rules = new List<Rule>();

Rule rule = new Rule();
rule.RuleName = "Test Rule";
rule.SuccessEvent = "Count is within tolerance.";
rule.ErrorMessage = "Over expected.";
rule.Expression = "count < 3";
rule.RuleExpressionType = RuleExpressionType.LambdaExpression;

rules.Add(rule);
workflow.Rules = rules;
workflows.Add(workflow);
var rulesEngine = new RulesEngine.RulesEngine(workflows.ToArray(), null);

dynamic datas = new ExpandoObject();
datas.count = 1;
var inputs = new dynamic[]
{
datas
};

//Act
var resultList = rulesEngine.ExecuteAllRulesAsync("Test Workflow Rule 1", inputs).Result;

//Assert
Assert.IsTrue(resultList.TrueForAll(x => x.IsSuccess));
}
}
}
110 changes: 110 additions & 0 deletions ActionFlow.Tests/Rules/VariableRuleTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using ActionFlow.Engine;
using ActionFlow.Rules;
using NSubstitute;
using RulesEngine.Models;

namespace ActionFlow.Tests.Rules
{
[TestClass]
public class VariableRuleTests
{

[TestMethod]
public void When_running_rule_engine_with_basic_workflow_it_should_execute()
{
//Arrange
var workflowProvider = Substitute.For<IWorkflowProvider>();
workflowProvider.GetAllWorkflows().Returns(CreateBasicWorkflow());

var rulesEngine = new RuleEngineWrapper(workflowProvider);

//Act
var resultList = rulesEngine.ExecuteAllRulesAsync("Test Workflow Rule 1", new object[] { }).Result;

//Assert
Assert.IsTrue(resultList.TrueForAll(x => x.IsSuccess));
Assert.AreEqual(2, resultList[0].Rule.LocalParams.Count());
}

[TestMethod]
public void When_running_rule_engine_with_false_condition_on_variable_rule_child_it_should_fail()
{
//Arrange
var workflowProvider = Substitute.For<IWorkflowProvider>();
workflowProvider.GetAllWorkflows().Returns(CreateConditionExpressionWorkflow());

var rulesEngine = new RuleEngineWrapper(workflowProvider);

//Act
var resultList = rulesEngine.ExecuteAllRulesAsync("Test Workflow Rule 1", new object[] { }).Result;

//Assert
Assert.IsFalse(resultList.TrueForAll(x => x.IsSuccess));
Assert.AreEqual(2, resultList[0].Rule.LocalParams.Count());
}

private List<Workflow> CreateBasicWorkflow()
{
List<Workflow> workflows = new List<Workflow>();
Workflow workflow = new Workflow();
workflow.WorkflowName = "Test Workflow Rule 1";

List<Rule> rules = new List<Rule>();

var variableRule1 = new VariableRule();
variableRule1.Name = "Declare test variables";
variableRule1.Variables = new Dictionary<string, string>
{
{ "age", "1" },
{ "canWalk", "false" }
};
variableRule1.ConditionExpression = "age == 1 && canWalk == false";

var variableRule2 = new VariableRule();
variableRule2.Name = "Test previously declared variables";
variableRule2.ConditionExpression = "age == 1 && canWalk == false";

var variableRule3 = new VariableRule();
variableRule3.Name = "Test previously declared variables 2";
variableRule3.ConditionExpression = "age == 1 && canWalk == false";

variableRule1.Rules.Add(variableRule2);
variableRule1.Rules.Add(variableRule3);

rules.Add(variableRule1.AsRuleEngineRule());
workflow.Rules = rules;
workflows.Add(workflow);

return workflows;
}

private List<Workflow> CreateConditionExpressionWorkflow()
{
List<Workflow> workflows = new List<Workflow>();
Workflow workflow = new Workflow();
workflow.WorkflowName = "Test Workflow Rule 1";

List<Rule> rules = new List<Rule>();

var variableRule1 = new VariableRule();
variableRule1.Name = "Declare test variables";
variableRule1.Variables = new Dictionary<string, string>
{
{ "age", "1" },
{ "canWalk", "false" }
};

var variableRule2 = new VariableRule();
variableRule2.Name = "Test previously declared variables";
variableRule2.ConditionExpression = "age == 1 && canWalk == true";

variableRule1.Rules.Add(variableRule2);

rules.Add(variableRule1.AsRuleEngineRule());
workflow.Rules = rules;
workflows.Add(workflow);

return workflows;
}
}
}
1 change: 1 addition & 0 deletions ActionFlow.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;
31 changes: 31 additions & 0 deletions ActionFlow.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActionFlow.Tests", "ActionFlow.Tests\ActionFlow.Tests.csproj", "{AACB88C1-1FA4-4D10-B6DD-F5F1CEDAFD62}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ActionFlow", "ActionFlow\ActionFlow.csproj", "{EFBB5884-ED06-4DC3-8324-3C14C7991ECB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AACB88C1-1FA4-4D10-B6DD-F5F1CEDAFD62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AACB88C1-1FA4-4D10-B6DD-F5F1CEDAFD62}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AACB88C1-1FA4-4D10-B6DD-F5F1CEDAFD62}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AACB88C1-1FA4-4D10-B6DD-F5F1CEDAFD62}.Release|Any CPU.Build.0 = Release|Any CPU
{EFBB5884-ED06-4DC3-8324-3C14C7991ECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EFBB5884-ED06-4DC3-8324-3C14C7991ECB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFBB5884-ED06-4DC3-8324-3C14C7991ECB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFBB5884-ED06-4DC3-8324-3C14C7991ECB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {157E2014-67B6-43AA-85D5-304BD88DE941}
EndGlobalSection
EndGlobal
13 changes: 13 additions & 0 deletions ActionFlow/ActionFlow.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="RulesEngine" Version="5.0.2" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions ActionFlow/ActionFlow.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActionFlow", "ActionFlow.csproj", "{8EB94BDF-60AA-4581-8486-F6A3AC25DD40}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8EB94BDF-60AA-4581-8486-F6A3AC25DD40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EB94BDF-60AA-4581-8486-F6A3AC25DD40}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EB94BDF-60AA-4581-8486-F6A3AC25DD40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EB94BDF-60AA-4581-8486-F6A3AC25DD40}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {157E2014-67B6-43AA-85D5-304BD88DE941}
EndGlobalSection
EndGlobal
9 changes: 9 additions & 0 deletions ActionFlow/Engine/IRuleEngineWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using RulesEngine.Models;

namespace ActionFlow.Engine
{
public interface IRuleEngineWrapper
{
ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params object[] inputs);
}
}
9 changes: 9 additions & 0 deletions ActionFlow/Engine/IWorkflowProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using RulesEngine.Models;

namespace ActionFlow.Engine
{
public interface IWorkflowProvider
{
List<Workflow> GetAllWorkflows();
}
}
20 changes: 20 additions & 0 deletions ActionFlow/Engine/RuleEngineWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using RulesEngine.Interfaces;
using RulesEngine.Models;

namespace ActionFlow.Engine
{
public class RuleEngineWrapper : IRuleEngineWrapper
{
private readonly IRulesEngine _rulesEngine;

public RuleEngineWrapper(IWorkflowProvider workflowProvider)
{
_rulesEngine = new RulesEngine.RulesEngine(workflowProvider.GetAllWorkflows().ToArray(), null);
}

public ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params object[] inputs)
{
return _rulesEngine.ExecuteAllRulesAsync(workflowName, inputs);
}
}
}
33 changes: 33 additions & 0 deletions ActionFlow/Engine/WorkflowProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using RulesEngine.Models;

namespace ActionFlow.Engine
{
public class WorkflowProvider : IWorkflowProvider
{
public List<Workflow> GetAllWorkflows()
{
List<Workflow> workflows = new List<Workflow>();

//Test
//Todo: Load from DB, Json, or other source
Workflow workflow = new Workflow();
workflow.WorkflowName = "Test Workflow Rule 1";

List<Rule> rules = new List<Rule>();

Rule rule = new Rule();
rule.RuleName = "Test Rule";
rule.SuccessEvent = "Count is within tolerance.";
rule.ErrorMessage = "Over expected.";
rule.Expression = "count < 3";
rule.RuleExpressionType = RuleExpressionType.LambdaExpression;

rules.Add(rule);
workflow.Rules = rules;
workflows.Add(workflow);
//Test End

return workflows;
}
}
}
Loading

0 comments on commit 2a02a42

Please sign in to comment.