Skip to content

Commit 3697d62

Browse files
authored
Changes for 1.6.0.
1 parent 18845bc commit 3697d62

File tree

15 files changed

+638
-124
lines changed

15 files changed

+638
-124
lines changed

ChangeLog.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
# 1.6.0 (5th June 2023)
2+
3+
LogicAppUnit Testing Framework:
4+
5+
- Added support for Linux and MacOS platforms. [[PR #14](https://github.com/LogicAppUnit/TestingFramework/pull/14), [@easchi](https://github.com/eashi) and [PR #15](https://github.com/LogicAppUnit/TestingFramework/pull/15), [@atthevergeof](https://github.com/atthevergeof)]
6+
- Added new overloads to `TestRunner.TriggerWorkflow()` to configure URL query parameters when triggering a workflow with a HTTP trigger. [[PR #15](https://github.com/LogicAppUnit/TestingFramework/pull/15), [@atthevergeof](https://github.com/atthevergeof)]
7+
- Added support for workflows using a HTTP trigger with an asynchronous response. Previous versions of the framework assumed that all responses were synchronous. Now the framework handles a 202 (Accepted) response and uses the callback URL (in the `Location` header) to poll the workflow and get the response. [[PR #15](https://github.com/LogicAppUnit/TestingFramework/pull/15), [@atthevergeof](https://github.com/atthevergeof)]
8+
- Added support for workflows using a HTTP trigger where the response action is not the last action in the workflow. Previous versions of the framework assumed that the workflow was complete once the response was received. Now the framework polls the workflow status to ensure that the workflow has completed. [[PR #15](https://github.com/LogicAppUnit/TestingFramework/pull/15), [@atthevergeof](https://github.com/atthevergeof)]
9+
- Fixed a bug in `TestRunner.TriggerWorkflow()` where the return value was being incorrectly set to the (disposed) workflow run history API response. The response is now correctly set to the workflow trigger API response. This bug only occurred for workflows that have a non-HTTP trigger (which is then replaced by a HTTP trigger by the framework).
10+
<br />
11+
:warning: ***This is a breaking change. Previously the status code for the response would have been HTTP 200 (OK), now it will be HTTP 202 (Accepted).***
12+
13+
LogicAppUnit.Samples.LogicApps.Tests:
14+
15+
- Added an `HttpAsyncWorkflowTest` workflow and unit tests to demonstrate the use of the testing framework with HTTP triggers and asynchronous responses.
16+
17+
Thanks to [@easchi](https://github.com/eashi) and [@atthevergeof](https://github.com/atthevergeof) for their contributions.
18+
19+
120
# 1.5.0 (14th April 2023)
221

322
LogicAppUnit Testing Framework:

LogicAppUnit.Samples.LogicApps.Tests/BuiltInConnectorWorkflowTest/BuiltInConnectorWorkflowTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void BuiltInConnectorWorkflowTest_When_No_Language_Code()
5555

5656
// Check workflow response
5757
// The workflow does not have a 'Response' action, so no content to validate
58-
Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode);
58+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
5959

6060
// Check action result
6161
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Execute_Query_to_get_Language_Name"));
@@ -108,7 +108,7 @@ public void BuiltInConnectorWorkflowTest_When_Valid_Language_Code()
108108

109109
// Check workflow response
110110
// The workflow does not have a 'Response' action, so no content to validate
111-
Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode);
111+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
112112

113113
// Check action result
114114
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Execute_Query_to_get_Language_Name"));
@@ -162,7 +162,7 @@ public void BuiltInConnectorWorkflowTest_When_Invalid_Language_Code()
162162

163163
// Check workflow response
164164
// The workflow does not have a 'Response' action, so no content to validate
165-
Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode);
165+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
166166

167167
// Check action result
168168
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Execute_Query_to_get_Language_Name"));

LogicAppUnit.Samples.LogicApps.Tests/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public static class Constants
1111
// Workflows
1212
public static readonly string BUILT_IN_CONNECTOR_WORKFLOW = "built-in-connector-test-workflow";
1313
public static readonly string HTTP_WORKFLOW = "http-test-workflow";
14+
public static readonly string HTTP_ASYNC_WORKFLOW = "http-async-test-workflow";
1415
public static readonly string INVOKE_WORKFLOW = "invoke-test-workflow";
1516
public static readonly string LOOP_WORKFLOW = "loop-test-workflow";
1617
public static readonly string MANAGED_API_CONNECTOR_WORKFLOW = "managed-api-connector-test-workflow";
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
using LogicAppUnit.Helper;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using System.Net;
4+
using System.Net.Http;
5+
using System.Threading;
6+
7+
namespace LogicAppUnit.Samples.LogicApps.Tests.HttpAsyncTriggerWorkflowTest
8+
{
9+
/// <summary>
10+
/// Test cases for the <i>http-async-test-workflow</i> workflow which uses an asynchronous response for the HTTP trigger.
11+
/// </summary>
12+
[TestClass]
13+
public class HttpAsyncWorkflowTest : WorkflowTestBase
14+
{
15+
[TestInitialize]
16+
public void TestInitialize()
17+
{
18+
Initialize(Constants.LOGIC_APP_TEST_EXAMPLE_BASE_PATH, Constants.HTTP_ASYNC_WORKFLOW);
19+
}
20+
21+
[ClassCleanup]
22+
public static void CleanResources()
23+
{
24+
Close();
25+
}
26+
27+
/// <summary>
28+
/// Tests that the correct response is returned when the HTTP call to the Service One API to get the customer details fails.
29+
/// </summary>
30+
[TestMethod]
31+
public void HttpAsyncWorkflowTest_When_Get_Customer_Details_Fails()
32+
{
33+
using (ITestRunner testRunner = CreateTestRunner())
34+
{
35+
// Configure async response handling
36+
testRunner.WaitForAsynchronousResponse(30);
37+
38+
// Mock the HTTP calls and customize responses
39+
testRunner.AddApiMocks = (request) =>
40+
{
41+
HttpResponseMessage mockedResponse = new HttpResponseMessage();
42+
if (request.RequestUri.AbsolutePath == "/api/v1/customers/12345" && request.Method == HttpMethod.Get)
43+
{
44+
mockedResponse.RequestMessage = request;
45+
mockedResponse.StatusCode = HttpStatusCode.InternalServerError;
46+
mockedResponse.Content = ContentHelper.CreatePlainStringContent("Internal server error detected in System One");
47+
}
48+
49+
Thread.Sleep(5000); // wait for 5 seconds to give a gap between (i) the trigger's sync response and (ii) the workflow's async response
50+
return mockedResponse;
51+
};
52+
53+
// Run the workflow
54+
var workflowResponse = testRunner.TriggerWorkflow(
55+
GetWebhookRequest(),
56+
HttpMethod.Post);
57+
58+
// Check workflow run status
59+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
60+
61+
// Check workflow response
62+
testRunner.ExceptionWrapper(() => Assert.AreEqual(HttpStatusCode.InternalServerError, workflowResponse.StatusCode));
63+
Assert.AreEqual("Unable to get customer details: Internal server error detected in System One", workflowResponse.Content.ReadAsStringAsync().Result);
64+
Assert.AreEqual("text/plain; charset=utf-8", workflowResponse.Content.Headers.ContentType.ToString());
65+
66+
// Check action result
67+
Assert.AreEqual(ActionStatus.Failed, testRunner.GetWorkflowActionStatus("Get_Customer_Details_from_Service_One"));
68+
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Success_Response_(Async)"));
69+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Failed_Get_Response_(Async)"));
70+
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Update_Customer_Details_in_Service_Two"));
71+
}
72+
}
73+
74+
/// <summary>
75+
/// Tests that the correct response is returned when the HTTP call to the Service Two API to update the customer details fails.
76+
/// </summary>
77+
[TestMethod]
78+
public void HttpAsyncWorkflowTest_When_Update_Customer_Fails()
79+
{
80+
using (ITestRunner testRunner = CreateTestRunner())
81+
{
82+
// Configure async response handling
83+
testRunner.WaitForAsynchronousResponse(30);
84+
85+
// Mock the HTTP calls and customize responses
86+
testRunner.AddApiMocks = (request) =>
87+
{
88+
HttpResponseMessage mockedResponse = new HttpResponseMessage();
89+
if (request.RequestUri.AbsolutePath == "/api/v1/customers/12345" && request.Method == HttpMethod.Get)
90+
{
91+
mockedResponse.RequestMessage = request;
92+
mockedResponse.StatusCode = HttpStatusCode.OK;
93+
mockedResponse.Content = GetCustomerResponse();
94+
}
95+
else if (request.RequestUri.AbsolutePath == "/api/v1.1/membership/customers/12345" && request.Method == HttpMethod.Put)
96+
{
97+
mockedResponse.RequestMessage = request;
98+
mockedResponse.StatusCode = HttpStatusCode.InternalServerError;
99+
mockedResponse.Content = ContentHelper.CreatePlainStringContent("System Two is not feeling well today");
100+
}
101+
102+
Thread.Sleep(5000); // wait for 5 seconds to give a gap between (i) the trigger's sync response and (ii) the workflow's async response
103+
return mockedResponse;
104+
};
105+
106+
// Run the workflow
107+
var workflowResponse = testRunner.TriggerWorkflow(
108+
GetWebhookRequest(),
109+
HttpMethod.Post);
110+
111+
// Check workflow run status
112+
// Workflow has failed because the last action (Update Customer) has failed
113+
Assert.AreEqual(WorkflowRunStatus.Failed, testRunner.WorkflowRunStatus);
114+
115+
// Check workflow response
116+
// The response is OK because this is an asynchronus response that is sent before the last action (Update Customer) fails
117+
testRunner.ExceptionWrapper(() => Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode));
118+
Assert.AreEqual("Webhook processed successfully", workflowResponse.Content.ReadAsStringAsync().Result);
119+
Assert.AreEqual("text/plain; charset=utf-8", workflowResponse.Content.Headers.ContentType.ToString());
120+
121+
// Check action result
122+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Get_Customer_Details_from_Service_One"));
123+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Success_Response_(Async)"));
124+
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Failed_Get_Response_(Async)"));
125+
Assert.AreEqual(ActionStatus.Failed, testRunner.GetWorkflowActionStatus("Update_Customer_Details_in_Service_Two"));
126+
}
127+
}
128+
129+
/// <summary>
130+
/// Tests that the correct response is returned when the HTTP call to the Service Two API to update the customer details is successful.
131+
/// </summary>
132+
[TestMethod]
133+
public void HttpAsyncWorkflowTest_When_Successful_WaitForAsyncResponse()
134+
{
135+
using (ITestRunner testRunner = CreateTestRunner())
136+
{
137+
// Configure async response handling
138+
testRunner.WaitForAsynchronousResponse(30);
139+
140+
// Mock the HTTP calls and customize responses
141+
testRunner.AddApiMocks = (request) =>
142+
{
143+
HttpResponseMessage mockedResponse = new HttpResponseMessage();
144+
if (request.RequestUri.AbsolutePath == "/api/v1/customers/12345" && request.Method == HttpMethod.Get)
145+
{
146+
mockedResponse.RequestMessage = request;
147+
mockedResponse.StatusCode = HttpStatusCode.OK;
148+
mockedResponse.Content = GetCustomerResponse();
149+
}
150+
else if (request.RequestUri.AbsolutePath == "/api/v1.1/membership/customers/12345" && request.Method == HttpMethod.Put)
151+
{
152+
mockedResponse.RequestMessage = request;
153+
mockedResponse.StatusCode = HttpStatusCode.OK;
154+
mockedResponse.Content = ContentHelper.CreatePlainStringContent("success");
155+
}
156+
157+
Thread.Sleep(5000); // wait for 5 seconds to give a gap between (i) the trigger's sync response and (ii) the workflow's async response and then (iii) the completion of the workflow
158+
return mockedResponse;
159+
};
160+
161+
// Run the workflow
162+
var workflowResponse = testRunner.TriggerWorkflow(
163+
GetWebhookRequest(),
164+
HttpMethod.Post);
165+
166+
// Check workflow run status
167+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
168+
169+
// Check workflow response
170+
testRunner.ExceptionWrapper(() => Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode));
171+
Assert.AreEqual("Webhook processed successfully", workflowResponse.Content.ReadAsStringAsync().Result);
172+
Assert.AreEqual("text/plain; charset=utf-8", workflowResponse.Content.Headers.ContentType.ToString());
173+
174+
// Check action result
175+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Get_Customer_Details_from_Service_One"));
176+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Success_Response_(Async)"));
177+
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Failed_Get_Response_(Async)"));
178+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Update_Customer_Details_in_Service_Two"));
179+
180+
// Check tracked properties
181+
var trackedProps = testRunner.GetWorkflowActionTrackedProperties("Get_Customer_Details_from_Service_One");
182+
Assert.AreEqual("customer", trackedProps["recordType"]);
183+
Assert.AreEqual("12345", trackedProps["recordId"]);
184+
Assert.AreEqual("c2ddb2f2-7bff-4cce-b724-ac2400b12760", trackedProps["correlationId"]);
185+
}
186+
}
187+
188+
private static StringContent GetWebhookRequest()
189+
{
190+
return ContentHelper.CreateJsonStringContent(new
191+
{
192+
id = "71fbcb8e-f974-449a-bb14-ac2400b150aa",
193+
correlationId = "c2ddb2f2-7bff-4cce-b724-ac2400b12760",
194+
sourceSystem = "SystemOne",
195+
timestamp = "2022-08-27T08:45:00.1493711Z",
196+
type = "CustomerUpdated",
197+
customerId = 12345,
198+
resourceId = "12345",
199+
resourceURI = "https://external-service-one.testing.net/api/v1/customer/12345"
200+
});
201+
}
202+
203+
private static StringContent GetCustomerResponse()
204+
{
205+
return ContentHelper.CreateJsonStringContent(new
206+
{
207+
id = 12345,
208+
title = "Mrs",
209+
firstName = "Sarah",
210+
lastName = "Smith",
211+
dateOfBirth = "1973-11-01",
212+
languageCode = "en-GB",
213+
address = new
214+
{
215+
line1 = "8 High Street",
216+
line2 = (string)null,
217+
line3 = (string)null,
218+
town = "Luton",
219+
county = "Bedfordshire",
220+
postcode = "LT12 6TY",
221+
countryCode = "UK",
222+
countryName = "United Kingdom"
223+
}
224+
});
225+
}
226+
}
227+
}

LogicAppUnit.Samples.LogicApps.Tests/HttpWorkflowTest/HttpWorkflowTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace LogicAppUnit.Samples.LogicApps.Tests.HttpWorkflowTest
1010
{
1111
/// <summary>
12-
/// Test cases for the <i>http-test-workflow</i> workflow.
12+
/// Test cases for the <i>http-test-workflow</i> workflow which uses a synchronous response for the HTTP trigger.
1313
/// </summary>
1414
[TestClass]
1515
public class HttpWorkflowTest : WorkflowTestBase

LogicAppUnit.Samples.LogicApps.Tests/InvokeWorkflowTest/InvokeWorkflowTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void InvokeWorkflowTest_When_Not_Priority_Successful()
6464

6565
// Check workflow response
6666
// The workflow does not have a 'Response' action, so no content to validate
67-
Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode);
67+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
6868

6969
// Check action result
7070
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Invoke_a_workflow_(not_Priority)"));
@@ -124,7 +124,7 @@ public void InvokeWorkflowTest_When_Priority_Successful()
124124

125125
// Check workflow response
126126
// The workflow does not have a 'Response' action, so no content to validate
127-
Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode);
127+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
128128

129129
// Check action result
130130
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Invoke_a_workflow_(not_Priority)"));

0 commit comments

Comments
 (0)