diff --git a/src/LogicAppUnit.Samples.LogicApps.Tests/Constants.cs b/src/LogicAppUnit.Samples.LogicApps.Tests/Constants.cs index 8f4ee7f..d20f1eb 100644 --- a/src/LogicAppUnit.Samples.LogicApps.Tests/Constants.cs +++ b/src/LogicAppUnit.Samples.LogicApps.Tests/Constants.cs @@ -15,6 +15,7 @@ public static class Constants public static readonly string FLUENT_REQUEST_MATCHING_WORKFLOW = "fluent-workflow"; public static readonly string HTTP_WORKFLOW = "http-workflow"; public static readonly string HTTP_ASYNC_WORKFLOW = "http-async-workflow"; + public static readonly string HTTP_WITH_MANAGED_IDENTITY_WORKFLOW = "http-with-managed-identity-workflow"; public static readonly string INLINE_SCRIPT_WORKFLOW = "inline-script-workflow"; public static readonly string INVOKE_WORKFLOW = "invoke-workflow"; public static readonly string LOOP_WORKFLOW = "loop-workflow"; diff --git a/src/LogicAppUnit.Samples.LogicApps.Tests/HttpWithManagedIdentityWorkflow/HttpWithManagedIdentityWorkflowTest.cs b/src/LogicAppUnit.Samples.LogicApps.Tests/HttpWithManagedIdentityWorkflow/HttpWithManagedIdentityWorkflowTest.cs new file mode 100644 index 0000000..c66cd55 --- /dev/null +++ b/src/LogicAppUnit.Samples.LogicApps.Tests/HttpWithManagedIdentityWorkflow/HttpWithManagedIdentityWorkflowTest.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using LogicAppUnit.Helper; +using LogicAppUnit.Mocking; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace LogicAppUnit.Samples.LogicApps.Tests.HttpWithManagedIdentityWorkflow +{ + /// + /// Test cases for the http-with-managed-identity-workflow workflow which has an HTTP action with Managed Identity as the authentication type. + /// + [TestClass] + public class HttpWithManagedIdentityWorkflowTest : WorkflowTestBase + { + [TestInitialize] + public void TestInitialize() + { + Initialize(Constants.LOGIC_APP_TEST_EXAMPLE_BASE_PATH, Constants.HTTP_WITH_MANAGED_IDENTITY_WORKFLOW); + } + + [ClassCleanup] + public static void CleanResources() + { + Close(); + } + + /// + /// Tests that the correct response is returned when the HTTP call to the Service to get the customers is successful. + /// + [TestMethod] + public void HttpWithManagedIdentityWorkflowTest_When_Successful() + { + using (ITestRunner testRunner = CreateTestRunner()) + { + // Configure mock responses + testRunner + .AddMockResponse( + MockRequestMatcher.Create() + .UsingGet() + .WithPath(PathMatchType.Exact, "/api/v1/customers")) + .RespondWith( + MockResponseBuilder.Create() + .WithSuccess()); + + // Run the workflow + var workflowResponse = testRunner.TriggerWorkflow(HttpMethod.Post); + + // Check workflow run status + Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus); + + // Check workflow response + testRunner.ExceptionWrapper(() => Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode)); + + // Check action result + Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Get_Customers_from_Service_One")); + Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Success_Response")); + } + } + } +} diff --git a/src/LogicAppUnit.Samples.LogicApps/http-with-managed-identity-workflow/workflow.json b/src/LogicAppUnit.Samples.LogicApps/http-with-managed-identity-workflow/workflow.json new file mode 100644 index 0000000..55a8a91 --- /dev/null +++ b/src/LogicAppUnit.Samples.LogicApps/http-with-managed-identity-workflow/workflow.json @@ -0,0 +1,49 @@ +{ + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Get_Customers_from_Service_One": { + "type": "Http", + "description": "Track some properties in this action", + "inputs": { + "uri": "@{parameters('ServiceOne-Url')}/customers", + "method": "GET", + "headers": { + "x-api-key": "ApiKey @{parameters('ServiceOne-Authentication-APIKey')}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "api://sample-audience" + } + }, + "runAfter": {}, + "operationOptions": "DisableAsyncPattern" + }, + "Success_Response": { + "type": "Response", + "kind": "Http", + "inputs": { + "statusCode": 200 + }, + "runAfter": { + "Get_Customers_from_Service_One": [ + "SUCCEEDED" + ] + } + } + }, + "contentVersion": "1.0.0.0", + "outputs": {}, + "triggers": { + "Receive_HTTP_request": { + "type": "Request", + "kind": "Http", + "inputs": { + "method": "POST" + }, + "operationOptions": "SuppressWorkflowHeadersOnResponse" + } + } + }, + "kind": "Stateful" +} \ No newline at end of file diff --git a/src/LogicAppUnit/WorkflowTestBase.cs b/src/LogicAppUnit/WorkflowTestBase.cs index 41a7df0..e61fe48 100644 --- a/src/LogicAppUnit/WorkflowTestBase.cs +++ b/src/LogicAppUnit/WorkflowTestBase.cs @@ -267,6 +267,7 @@ private void ProcessWorkflowDefinitionFile(string logicAppBasePath, string workf _workflowDefinition.ReplaceInvokeWorkflowActionsWithHttp(); _workflowDefinition.ReplaceCallLocalFunctionActionsWithHttp(); _workflowDefinition.ReplaceBuiltInConnectorActionsWithHttp(_testConfig.Workflow.BuiltInConnectorsToMock); + _workflowDefinition.ReplaceManagedIdentityAuthenticationTypeWithNone(); } /// diff --git a/src/LogicAppUnit/Wrapper/WorkflowDefinitionWrapper.cs b/src/LogicAppUnit/Wrapper/WorkflowDefinitionWrapper.cs index f4f27a5..aef72ef 100644 --- a/src/LogicAppUnit/Wrapper/WorkflowDefinitionWrapper.cs +++ b/src/LogicAppUnit/Wrapper/WorkflowDefinitionWrapper.cs @@ -296,5 +296,29 @@ public void ReplaceCallLocalFunctionActionsWithHttp() }); } } + + /// + /// Update all HTTP actions with authentication type ManagedServiceIdentity to use None as the authentication type. + /// + /// + /// The ManagedServiceIdentity is not supported. + /// + public void ReplaceManagedIdentityAuthenticationTypeWithNone() + { + var httpActionsWithManagedIdentityAuthenticationType = _jObjectWorkflow.SelectTokens("$..actions.*").Where(x => x["type"].ToString() == "Http") + .Where(x => x["inputs"]?["authentication"]?["type"].ToString() == "ManagedServiceIdentity").Select(x => x["inputs"]?["authentication"] as JObject).ToList(); + + if (httpActionsWithManagedIdentityAuthenticationType.Count > 0) + { + Console.WriteLine("Updating workflow HTTP actions to replace authentication type `ManagedServiceIdentity` with `None`:"); + + httpActionsWithManagedIdentityAuthenticationType.ForEach(x => + { + x["type"] = "None"; + + Console.WriteLine($" {((JProperty)x.Parent.Parent.Parent.Parent.Parent).Name}"); + }); + } + } } }