Skip to content

Commit

Permalink
Merge pull request #45 from thygesteffensen/feature/assertness
Browse files Browse the repository at this point in the history
feat!: Added flow result
  • Loading branch information
thygesteffensen authored Mar 1, 2021
2 parents 736a160 + ed74956 commit 5282445
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 5 deletions.
45 changes: 45 additions & 0 deletions PowerAutomateMockUp/FlowParser/ActionState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#nullable enable
using System.Collections.Generic;
using Parser.ExpressionParser;
using Parser.FlowParser.ActionExecutors;

namespace Parser.FlowParser
{
public class FlowResult
{
public FlowResult()
{
ActionStates = new Dictionary<string, ActionState>();
}

public Dictionary<string, ActionState> ActionStates { get; set; }
public int NumberOfExecutedActions { get; set; }
}

public class ActionState
{
private ValueContainer? _actionInput;
#nullable enable
public ValueContainer? ActionInput
{
get => _actionInput;
set
{
_actionInput = value;
if (_actionInput == null || _actionInput.Type() != ValueContainer.ValueType.Object) return;
if (_actionInput.AsDict().ContainsKey("parameters"))
{
ActionParameters = _actionInput.AsDict()["parameters"];
}
}
}

public ValueContainer? ActionParameters { set; get; }

public ActionResult? ActionOutput { get; set; }
#nullable disable
public string ActionName { get; set; }
public string ActionType { get; set; }
public int ActionOrder { get; set; }
}
}
38 changes: 33 additions & 5 deletions PowerAutomateMockUp/FlowParser/FlowRunner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -7,16 +8,15 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Parser.ExpressionParser;
using Parser.ExpressionParser.Functions.Base;
using Parser.FlowParser.ActionExecutors;

namespace Parser.FlowParser
{
public interface IFlowRunner
{
void InitializeFlowRunner(in string path);
Task Trigger();
Task Trigger(ValueContainer triggerOutput);
Task<FlowResult> Trigger();
Task<FlowResult> Trigger(ValueContainer triggerOutput);
}

public class FlowRunner : IFlowRunner
Expand All @@ -26,6 +26,8 @@ public class FlowRunner : IFlowRunner
private readonly IScopeDepthManager _scopeManager;
private readonly IActionExecutorFactory _actionExecutorFactory;
private readonly ILogger<FlowRunner> _logger;
private readonly Dictionary<string, ActionState> _actionSates;
private int _actionsExecuted;
private JProperty _trigger;

public FlowRunner(
Expand All @@ -41,6 +43,8 @@ public FlowRunner(
_actionExecutorFactory =
actionExecutorFactory ?? throw new ArgumentNullException(nameof(actionExecutorFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_actionSates = new Dictionary<string, ActionState>();
_actionsExecuted = 0;
}

public void InitializeFlowRunner(in string path)
Expand All @@ -54,7 +58,7 @@ public void InitializeFlowRunner(in string path)
_scopeManager.Push("root", flowDefinition.SelectToken("$.actions").OfType<JProperty>(), null);
}

public async Task Trigger()
public async Task<FlowResult> Trigger()
{
var trigger = GetActionExecutor(_trigger);

Expand All @@ -67,13 +71,25 @@ public async Task Trigger()
}

await RunFlow();

return new FlowResult
{
ActionStates = _actionSates,
NumberOfExecutedActions = _actionsExecuted
};
}

public async Task Trigger(ValueContainer triggerOutput)
public async Task<FlowResult> Trigger(ValueContainer triggerOutput)
{
_state.AddTriggerOutputs(triggerOutput);

await RunFlow();

return new FlowResult
{
ActionStates = _actionSates,
NumberOfExecutedActions = _actionsExecuted
};
}

private async Task RunFlow()
Expand All @@ -95,6 +111,18 @@ private async Task RunFlow()
var actionExecutor = GetActionExecutor(currentAd);

var actionResult = await ExecuteAction(actionExecutor, currentAd);

if (_flowRunnerSettings.LogActionsStates)
{
_actionSates[currentAd.Name] = new ActionState
{
ActionInput = actionExecutor?.Inputs,
ActionOutput = actionResult,
ActionOrder = _actionsExecuted++,
ActionName = actionExecutor?.ActionName
};
}

if (!(actionResult?.ContinueExecution ?? true))
{
break;
Expand Down
2 changes: 2 additions & 0 deletions PowerAutomateMockUp/FlowParser/FlowSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ public class FlowSettings
public bool FailOnUnknownAction { get; set; } = true;

public List<string> IgnoreActions { get; set; } = new List<string>();

public bool LogActionsStates { get; set; } = true;
}
}
137 changes: 137 additions & 0 deletions Test/FullFlowTestV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;
using Parser;
using Parser.ExpressionParser;
using Parser.FlowParser;
using Parser.FlowParser.ActionExecutors;

namespace Test
{
[TestFixture]
public class FullFlowTestV2
{
private static readonly string TestFlowPath = System.IO.Path.GetFullPath(@"FlowSamples");

[Test]
public async Task TestFlowFalse()
{
var path = @$"{TestFlowPath}\PowerAutomateMockUpSampleFlow.json";

var services = new ServiceCollection();
services.AddFlowRunner();

services.AddFlowActionByName<UpdateAccountInvalidId>(UpdateAccountInvalidId.FlowActionName);
services.AddFlowActionByApiIdAndOperationsName<SendEmailNotification>(SendEmailNotification.ApiId,
SendEmailNotification.SupportedOperations);
services.AddFlowActionByName<GetRecordValidId>(GetRecordValidId.FlowActionName);
services.AddFlowActionByName<UpdateAccountValidId>(UpdateAccountValidId.FlowActionName);
services.AddFlowActionByName<SendOutWarning>(SendOutWarning.FlowActionName);


var sp = services.BuildServiceProvider();
var flowRunner = sp.GetRequiredService<IFlowRunner>();

flowRunner.InitializeFlowRunner(path);

var flowResult = await flowRunner.Trigger(new ValueContainer(
new Dictionary<string, ValueContainer>
{
{"body/name", new ValueContainer("Alice Bob")},
{"body/accountid", new ValueContainer(Guid.NewGuid().ToString())}
}));

Assert.AreEqual(7, flowResult.NumberOfExecutedActions);

const string actionName = "Send_me_an_email_notification";
Assert.IsTrue(flowResult.ActionStates.ContainsKey(actionName), "Action is expected to be triggered.");
Assert.NotNull(flowResult.ActionStates[actionName].ActionParameters, "Action input is expected.");
var actionInput = flowResult.ActionStates[actionName].ActionParameters.AsDict();
Assert.IsTrue(actionInput.ContainsKey("NotificationEmailDefinition"), "Action input should contain this object.");
var notification = actionInput["NotificationEmailDefinition"].AsDict();
Assert.AreEqual("A new Account have been added", notification["notificationSubject"].GetValue<string>(), "Asserting the input");

Assert.IsFalse(flowResult.ActionStates.ContainsKey(SendOutWarning.FlowActionName), "Action is not expected to be triggered.");
}

private class UpdateAccountInvalidId : OpenApiConnectionActionExecutorBase
{
public const string FlowActionName = "Update_Account_-_Invalid_Id";

public UpdateAccountInvalidId(IExpressionEngine expressionEngine) : base(expressionEngine)
{
}

public override Task<ActionResult> Execute()
{
return Task.FromResult(new ActionResult
{
ActionStatus = ActionStatus.Failed,
ActionOutput = new ValueContainer(true)
});
}
}

private class SendEmailNotification : OpenApiConnectionActionExecutorBase
{
public const string ApiId = "/providers/Microsoft.PowerApps/apis/shared_flowpush";
public static readonly string[] SupportedOperations = {"SendEmailNotification"};

public SendEmailNotification(IExpressionEngine expressionEngine) : base(expressionEngine)
{
}

public override Task<ActionResult> Execute()
{
Console.WriteLine($"Email Title: {Parameters["NotificationEmailDefinition/notificationSubject"]}");
Console.WriteLine($"Email Content: {Parameters["NotificationEmailDefinition/notificationBody"]}");

return Task.FromResult(new ActionResult {ActionOutput = new ValueContainer(true)});
}
}

private class GetRecordValidId : OpenApiConnectionActionExecutorBase
{
public const string FlowActionName = "Get_a_record_-_Valid_Id";

public GetRecordValidId(IExpressionEngine expressionEngine) : base(expressionEngine)
{
}

public override Task<ActionResult> Execute()
{
return Task.FromResult(new ActionResult {ActionOutput = new ValueContainer(true)});
}
}

private class UpdateAccountValidId : OpenApiConnectionActionExecutorBase
{
public const string FlowActionName = "Update_Account_-_Valid_Id";

public override Task<ActionResult> Execute()
{
return Task.FromResult(new ActionResult());
}

public UpdateAccountValidId(IExpressionEngine expressionEngine) : base(expressionEngine)
{
}
}

private class SendOutWarning : OpenApiConnectionActionExecutorBase
{
public const string FlowActionName = "Send_an_error_message_to_owner";

public SendOutWarning(IExpressionEngine expressionEngine) : base(expressionEngine)
{
}

public override Task<ActionResult> Execute()
{
return Task.FromResult(new ActionResult());
}
}
}
}

0 comments on commit 5282445

Please sign in to comment.