Skip to content

Commit 2d336c9

Browse files
authored
Changes for 1.8.0.
1 parent 40a69b3 commit 2d336c9

File tree

23 files changed

+639
-112
lines changed

23 files changed

+639
-112
lines changed

.azure-devops/pipelines/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ parameters:
1414
jobs:
1515
- job: build
1616
displayName: 'Build'
17-
timeoutInMinutes: 20
17+
timeoutInMinutes: 30
1818

1919
strategy:
2020
matrix:

.editorconfig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
; This file is for unifying the coding style for different editors and IDEs.
2+
; More information at http://EditorConfig.org
3+
4+
# top-most EditorConfig file
5+
root = true
6+
7+
# Don't use tabs for indentation
8+
[*]
9+
indent_style = space
10+
11+
# Code files
12+
[*.{cs,csx}]
13+
indent_size = 4
14+
15+
# XML project files
16+
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}]
17+
indent_size = 2
18+
19+
# YAML files
20+
[*.{yaml,yml}]
21+
indent_size = 2
22+
23+
# JSON files
24+
[*.json]
25+
indent_size = 2
126

227
# CA1307: Specify StringComparison for clarity
328
# Clarity of intent is not required, this is non-localizable code.

ChangeLog.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1+
# 1.8.0 (24th October 2023)
2+
3+
LogicAppUnit Testing Framework:
4+
5+
- Added new methods `TestRunner.WorkflowWasTerminated`, `TestRunner.WorkflowTerminationCode` and `TestRunner.WorkflowTerminationMessage` to allow the effects of a `Terminate` action in a workflow to be tested.
6+
- Mock responses can be configured using the fluent API in the test class initialization method, using the `WorkflowTestBase.AddMockResponse()` method. Mock responses configured using this method will be used by every test runner that is created in the same test class, and have a lower priority compared to the mock responses created using `ITestRunner.AddMockResponse()` and `ITestRunner.AddApiMocks`. This feature removes the need to repeatedly configure the same mocked responses in multiple tests in a test class.
7+
- The HTTP status code for the default mock response can now be set in the `testConfiguration.json` file using the `runner.defaultHttpResponseStatusCode` option. Previously the status code was hard-coded to HTTP 200 (OK). The default value for this option is HTTP 200 (OK) to ensure backwards compatibility.
8+
- Added a new feature to remove the chunking configuration for HTTP actions (`runtimeConfiguration.contentTransfer.transferMode`). This feature is enabled/disabled in the `testConfiguration.json` file using the `workflow.removeHttpChunkingConfiguration` option. The default value for this option is `true`. [[Issue #24](https://github.com/LogicAppUnit/TestingFramework/issues/24)]
9+
- Added `IMockResponseBuilder.WithAccepted()` as a short-cut when creating a response with a HTTP 202 (Accepted) status code.
10+
11+
112
# 1.7.0 (27th July 2023)
213

314
LogicAppUnit Testing Framework:
415

5-
- Mock responses can be configured using a fluent API, this includes the definition of the request matching conditions and the response.
16+
- Mock responses can be configured using `ITestRunner.AddMockResponse()` and a fluent API, this includes the definition of the request matching conditions and the response.
617
- Removed public methods `ContentHelper.SerializeObject()`, `ContentHelper.DeserializeObject()` and `ContentHelper.JClone()`, these were for internal use only and are now obsolete.
718
- Include the LogicAppUnit version at the end of the test log.
819
- The maximum execution time for a workflow can now be set in the `testConfiguration.json` file using the `runner.maxWorkflowExecutionDuration` option. Previously this duration was hard-coded to 5 minutes. The default value for this option is 300 seconds (5 minutes).
@@ -29,8 +40,6 @@ LogicAppUnit.Samples.LogicApps.Tests:
2940

3041
- Added a `http-async-workflow` workflow and unit tests to demonstrate the use of the testing framework with HTTP triggers and asynchronous responses.
3142

32-
Thanks to [@easchi](https://github.com/eashi) and [@atthevergeof](https://github.com/atthevergeof) for their contributions.
33-
3443

3544
# 1.5.0 (14th April 2023)
3645

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public void BuiltInConnectorWorkflowTest_When_No_Language_Code()
5353
// Check workflow run status
5454
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
5555

56+
// Check the workflow termination status
57+
Assert.IsFalse(testRunner.WorkflowWasTerminated);
58+
Assert.IsNull(testRunner.WorkflowTerminationCode);
59+
Assert.IsNull(testRunner.WorkflowTerminationMessage);
60+
5661
// Check workflow response
5762
// The workflow does not have a 'Response' action, so no content to validate
5863
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
@@ -106,6 +111,11 @@ public void BuiltInConnectorWorkflowTest_When_Valid_Language_Code()
106111
// Check workflow run status
107112
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
108113

114+
// Check the workflow termination status
115+
Assert.IsFalse(testRunner.WorkflowWasTerminated);
116+
Assert.IsNull(testRunner.WorkflowTerminationCode);
117+
Assert.IsNull(testRunner.WorkflowTerminationMessage);
118+
109119
// Check workflow response
110120
// The workflow does not have a 'Response' action, so no content to validate
111121
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
@@ -159,6 +169,9 @@ public void BuiltInConnectorWorkflowTest_When_Invalid_Language_Code()
159169
// Check workflow run status
160170
// This workflow has terminated with failure
161171
Assert.AreEqual(WorkflowRunStatus.Failed, testRunner.WorkflowRunStatus);
172+
Assert.IsTrue(testRunner.WorkflowWasTerminated);
173+
Assert.AreEqual((int)HttpStatusCode.InternalServerError, testRunner.WorkflowTerminationCode);
174+
Assert.AreEqual("Language Code 'xx-GB' is not valid", testRunner.WorkflowTerminationMessage);
162175

163176
// Check workflow response
164177
// The workflow does not have a 'Response' action, so no content to validate

LogicAppUnit.Samples.LogicApps.Tests/FluentWorkflow/FluentWorkflowResponseBuilderTest.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,28 @@ public void FluentWorkflowTest_ResponseBuilder_ContentResource()
400400
}
401401
}
402402

403+
/// <summary>
404+
/// Tests the response when neither a response builder, nor a delegate response, have been configured. A HTTP 200 (OK) response should be received with no content.
405+
/// </summary>
406+
[TestMethod]
407+
public void FluentWorkflowTest_ResponseBuilder_NoResponseConfigured()
408+
{
409+
using (ITestRunner testRunner = CreateTestRunner())
410+
{
411+
// Run the workflow
412+
var workflowResponse = testRunner.TriggerWorkflow(
413+
GetRequest(),
414+
HttpMethod.Post);
415+
416+
// Check workflow run status
417+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
418+
419+
// Check workflow response
420+
Assert.AreEqual(HttpStatusCode.OK, workflowResponse.StatusCode);
421+
Assert.AreEqual("", workflowResponse.Content.ReadAsStringAsync().Result);
422+
}
423+
}
424+
403425
private static StringContent GetRequest()
404426
{
405427
return ContentHelper.CreateJsonStringContent(new
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using LogicAppUnit.Helper;
2+
using LogicAppUnit.Mocking;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
using System.Net;
5+
using System.Net.Http;
6+
7+
namespace LogicAppUnit.Samples.LogicApps.Tests.FluentWorkflow
8+
{
9+
/// <summary>
10+
/// Test cases for the <i>fluent-workflow</i> workflow and the Response Builder features, when the test base class defines a mock response.
11+
/// </summary>
12+
[TestClass]
13+
public class FluentWorkflowResponseBuilderWithBaseTest : WorkflowTestBase
14+
{
15+
[TestInitialize]
16+
public void TestInitialize()
17+
{
18+
Initialize(Constants.LOGIC_APP_TEST_EXAMPLE_BASE_PATH, Constants.FLUENT_REQUEST_MATCHING_WORKFLOW);
19+
20+
// Configure mock responses for all tests
21+
// The request matcher will match all requests because there are no match criteria
22+
AddMockResponse("DefinedInTestClass",
23+
MockRequestMatcher.Create())
24+
.RespondWith(
25+
MockResponseBuilder.Create()
26+
.WithNoContent());
27+
}
28+
29+
[ClassCleanup]
30+
public static void CleanResources()
31+
{
32+
Close();
33+
}
34+
35+
/// <summary>
36+
/// Tests the response builder when no mock response is configured in the test and therefore the mock response in the test class is matched.
37+
/// </summary>
38+
[TestMethod]
39+
public void FluentWorkflowTest_ResponseBuilder_NoTestCaseMock()
40+
{
41+
using (ITestRunner testRunner = CreateTestRunner())
42+
{
43+
// Do not configure mock responses, the test base mock response should match
44+
45+
// Run the workflow
46+
var workflowResponse = testRunner.TriggerWorkflow(
47+
GetRequest(),
48+
HttpMethod.Post);
49+
50+
// Check workflow run status
51+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
52+
53+
// Check workflow response
54+
Assert.AreEqual(HttpStatusCode.NoContent, workflowResponse.StatusCode);
55+
Assert.AreEqual(string.Empty, workflowResponse.Content.ReadAsStringAsync().Result);
56+
}
57+
}
58+
59+
/// <summary>
60+
/// Tests the response builder when a mock response is configured in the test and matches, therefore the mock response in the test class is not used.
61+
/// </summary>
62+
[TestMethod]
63+
public void FluentWorkflowTest_ResponseBuilder_WithTestCaseMockThatMatches()
64+
{
65+
using (ITestRunner testRunner = CreateTestRunner())
66+
{
67+
// Configure mock responses
68+
testRunner
69+
.AddMockResponse("DefinedInTestCase",
70+
MockRequestMatcher.Create())
71+
.RespondWith(
72+
MockResponseBuilder.Create()
73+
.WithStatusCode(HttpStatusCode.Accepted)
74+
.WithContentAsPlainText("Your request has been queued for processing"));
75+
76+
// Run the workflow
77+
var workflowResponse = testRunner.TriggerWorkflow(
78+
GetRequest(),
79+
HttpMethod.Post);
80+
81+
// Check workflow run status
82+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
83+
84+
// Check workflow response
85+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
86+
Assert.AreEqual("Your request has been queued for processing", workflowResponse.Content.ReadAsStringAsync().Result);
87+
}
88+
}
89+
90+
/// <summary>
91+
/// Tests the response builder when a mock response is configured in the test and does not match, therefore the mock response in the test class is matched.
92+
/// </summary>
93+
[TestMethod]
94+
public void FluentWorkflowTest_ResponseBuilder_TestCaseMockNotMatched()
95+
{
96+
using (ITestRunner testRunner = CreateTestRunner())
97+
{
98+
// Configure mock responses
99+
testRunner
100+
.AddMockResponse("DefinedInTestCase",
101+
MockRequestMatcher.Create()
102+
.WithPath(PathMatchType.Contains, "HelloWorld"))
103+
.RespondWith(
104+
MockResponseBuilder.Create()
105+
.WithStatusCode(HttpStatusCode.InternalServerError)
106+
.WithContentAsPlainText("It all went wrong!"));
107+
108+
// Run the workflow
109+
var workflowResponse = testRunner.TriggerWorkflow(
110+
GetRequest(),
111+
HttpMethod.Post);
112+
113+
// Check workflow run status
114+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
115+
116+
// Check workflow response
117+
Assert.AreEqual(HttpStatusCode.NoContent, workflowResponse.StatusCode);
118+
Assert.AreEqual(string.Empty, workflowResponse.Content.ReadAsStringAsync().Result);
119+
}
120+
}
121+
122+
private static StringContent GetRequest()
123+
{
124+
return ContentHelper.CreateJsonStringContent(new
125+
{
126+
name = "",
127+
manufacturer = "Virgin Orbit"
128+
});
129+
}
130+
}
131+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using LogicAppUnit.Mocking;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using System.Net;
4+
using System.Net.Http;
5+
6+
namespace LogicAppUnit.Samples.LogicApps.Tests.HttpChunkingWorkflow
7+
{
8+
/// <summary>
9+
/// Test cases for the <i>http-chunking-workflow</i> workflow which uses a chunked transfer mode within HTTP action.
10+
/// </summary>
11+
[TestClass]
12+
public class HttpChunkingWorkflowTest : WorkflowTestBase
13+
{
14+
[TestInitialize]
15+
public void TestInitialize()
16+
{
17+
Initialize(Constants.LOGIC_APP_TEST_EXAMPLE_BASE_PATH, "http-chunking-workflow");
18+
}
19+
20+
[ClassCleanup]
21+
public static void CleanResources()
22+
{
23+
Close();
24+
}
25+
26+
[TestMethod]
27+
public void ChunkedTransferWorkflow_Success()
28+
{
29+
using (ITestRunner testRunner = CreateTestRunner())
30+
{
31+
// Configure mock responses
32+
testRunner
33+
.AddMockResponse(
34+
MockRequestMatcher.Create()
35+
.UsingGet()
36+
.WithPath(PathMatchType.Exact, "/api/v1/data"))
37+
.RespondWith(
38+
MockResponseBuilder.Create()
39+
.WithSuccess()
40+
.WithContentAsJson(GetDataResponse()));
41+
testRunner
42+
.AddMockResponse(
43+
MockRequestMatcher.Create()
44+
.UsingPost()
45+
.WithPath(PathMatchType.Exact, "/api/v1.1/upload"))
46+
.RespondWithDefault();
47+
48+
// Run the workflow
49+
var workflowResponse = testRunner.TriggerWorkflow(HttpMethod.Post);
50+
51+
// Check workflow run status
52+
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);
53+
54+
// Check workflow response
55+
Assert.AreEqual(HttpStatusCode.Accepted, workflowResponse.StatusCode);
56+
57+
// Check action result
58+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Get_Action"));
59+
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Post_Action"));
60+
}
61+
}
62+
63+
private static dynamic GetDataResponse()
64+
{
65+
return new
66+
{
67+
id = 54624,
68+
title = "Mr",
69+
firstName = "Peter",
70+
lastName = "Smith",
71+
dateOfBirth = "1970-04-25",
72+
languageCode = "en-GB",
73+
address = new
74+
{
75+
line1 = "8 High Street",
76+
line2 = (string)null,
77+
line3 = (string)null,
78+
town = "Luton",
79+
county = "Bedfordshire",
80+
postcode = "LT12 6TY",
81+
countryCode = "UK",
82+
countryName = "United Kingdom"
83+
},
84+
extra = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer et nisl in tellus sodales aliquet in id sem. Suspendisse cursus mollis erat eu ullamcorper. Nulla congue id odio at facilisis. Sed ultrices dolor nisi, sit amet cursus leo pellentesque eget. Praesent sagittis ligula leo. Vestibulum varius eros posuere tortor tristique eleifend. Praesent ornare accumsan nisi sed auctor. Fusce ullamcorper nisi nec mi euismod, in efficitur quam volutpat.Vestibulum at iaculis felis. Fusce augue sem, efficitur ut vulputate quis, cursus nec mi. Nulla sagittis posuere ornare. Morbi lectus eros, luctus non condimentum eget, pretium eget sem. Aliquam convallis sed sem accumsan ultricies. Quisque commodo at odio sit amet iaculis. Curabitur nec lectus vel leo tristique aliquam et a ipsum. Duis tortor augue, gravida sed dui ac, feugiat pulvinar ex. Integer luctus urna at mauris feugiat, nec mattis elit mattis. Fusce dictum odio quis semper blandit. Pellentesque nunc augue, elementum sit amet nunc et."
85+
};
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)