elsa-core/test/unit/Elsa.Activities.UnitTests/Http/FlowSendHttpRequestTests.cs

217 lines
8.7 KiB
C#
Raw Normal View History

Add unit tests for `FlowSendHttpRequest` activity and refactor helper utilities (#6997) * Add unit tests for `FlowFork` activity and enhance test utilities - Introduce `FlowForkTests` to validate activity behavior with various branch configurations. - Extend `ActivityExecutionContextExtensions` with methods to retrieve and check outcomes. - Modify `ActivityTestFixture` to ensure activities transition to `Running` status before execution. * Add unit tests for `FlowSwitch` activity and extend test utilities - Implement `FlowSwitchTests` to verify behavior based on switch cases, modes, and literal expressions. - Enhance `ActivityExecutionContextExtensions` with methods to retrieve and check outcomes in execution context. * Update test guidelines to include examples for checking activity outcomes - Add unit test examples for validating multiple and default outcomes. - Extend documentation to describe new `ActivityExecutionContextExtensions` methods: `GetOutcomes` and `HasOutcome`. * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Simplify `GetOutcomes` method in `ActivityExecutionContextExtensions`. * Add unit tests for `FlowSendHttpRequest` activity and refactor helper utilities - Introduce `FlowSendHttpRequestTests` to validate activity behavior across various scenarios. - Add utility methods in `SendHttpRequestTestHelpers` for creating mock responses and exceptions. - Refactor `Helpers` namespace to `Http.Helpers` for better organization. - Update project file to reflect namespace adjustments. * Update test/unit/Elsa.Activities.UnitTests/Elsa.Activities.UnitTests.csproj Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-21 13:36:54 +00:00
using System.Net;
using Elsa.Activities.UnitTests.Http.Helpers;
using Elsa.Extensions;
using Elsa.Http;
using Elsa.Testing.Shared;
using Elsa.Workflows;
namespace Elsa.Activities.UnitTests.Http;
public class FlowSendHttpRequestTests
{
[Theory]
[InlineData("GET", "https://api.example.com/data", "{\"result\": \"success\"}", 200)]
[InlineData("POST", "https://api.example.com/create", "{\"id\": 123}", 201)]
[InlineData("PUT", "https://api.example.com/update", "{\"updated\": true}", 200)]
public async Task Should_Send_Request_And_Set_Status_Code_Output(string method, string url, string jsonResponse, int expectedStatusCode)
{
// Arrange
var expectedUrl = new Uri(url);
var expectedMethod = new HttpMethod(method);
var expectedHttpStatusCode = (HttpStatusCode)expectedStatusCode;
var requestCapture = new SendHttpRequestTestHelpers.RequestCapture();
var responseHandler = SendHttpRequestTestHelpers.CreateResponseHandler(expectedHttpStatusCode, jsonResponse, requestCapture);
var flowSendHttpRequest = CreateFlowSendHttpRequest(expectedUrl, method);
// Act
var context = await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
// Assert
Assert.NotNull(requestCapture.CapturedRequest);
Assert.Equal(expectedMethod, requestCapture.CapturedRequest.Method);
Assert.Equal(expectedUrl, requestCapture.CapturedRequest.RequestUri);
var statusCodeOutput = context.GetActivityOutput(() => flowSendHttpRequest.StatusCode);
Assert.Equal(expectedStatusCode, statusCodeOutput);
}
[Theory]
[InlineData("Bearer token123")]
[InlineData("Basic YWRtaW46cGFzcw==")]
[InlineData("ApiKey abc123")]
public async Task Should_Add_Authorization_Header(string authorizationHeader)
{
// Arrange
var expectedUrl = new Uri("https://api.example.com/secure");
var requestCapture = new SendHttpRequestTestHelpers.RequestCapture();
var responseHandler = SendHttpRequestTestHelpers.CreateResponseHandler(HttpStatusCode.OK, null, requestCapture);
var flowSendHttpRequest = CreateFlowSendHttpRequest(expectedUrl, authorization: authorizationHeader);
// Act
await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
// Assert
Assert.NotNull(requestCapture.CapturedRequest);
Assert.NotNull(requestCapture.CapturedRequest.Headers.Authorization);
Assert.Equal(authorizationHeader, requestCapture.CapturedRequest.Headers.Authorization.ToString());
}
Add OpenTelemetry workflow instrumentation (#7514) * Add OpenTelemetry workflow instrumentation * Fix workflow telemetry metric tags * Tighten telemetry test listeners * Refine workflow telemetry boundaries * Address telemetry review feedback * Complete workflow telemetry coverage * Address telemetry instrumentation review feedback * Handle cancelled workflow telemetry * Refine workflow activity telemetry tags * Address telemetry review feedback * Document OpenTelemetry extension coexistence Agent-Logs-Url: https://github.com/elsa-workflows/elsa-core/sessions/33211c71-c3c9-424c-b7eb-a13ebd4713a3 Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com> * Address telemetry PR review comments * Address telemetry review follow-ups * Preserve workflow executing status transition order * Address telemetry review feedback * Refine workflow telemetry review fixes * Address telemetry review feedback * Address workflow instrumentation review feedback * Fix faulted workflow telemetry tags * Restrict workflow exception mutation * Fix canceled activity telemetry status * Clarify workflow exception access * Cover HTTP trace context propagation * Report cancelled workflow telemetry consistently * Refine telemetry cancellation classification * Record thrown workflow exceptions on context * Tighten workflow telemetry exception handling * Preserve first workflow exception * Handle workflow cancellation separately * Clarify workflow telemetry enum references --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2026-05-21 23:17:05 +00:00
[Fact]
public async Task Should_Propagate_Current_Trace_Context()
{
await SendHttpRequestTestHelpers.AssertPropagatesCurrentTraceContextAsync(async (url, responseHandler) =>
{
var flowSendHttpRequest = CreateFlowSendHttpRequest(url);
await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
});
}
Add unit tests for `FlowSendHttpRequest` activity and refactor helper utilities (#6997) * Add unit tests for `FlowFork` activity and enhance test utilities - Introduce `FlowForkTests` to validate activity behavior with various branch configurations. - Extend `ActivityExecutionContextExtensions` with methods to retrieve and check outcomes. - Modify `ActivityTestFixture` to ensure activities transition to `Running` status before execution. * Add unit tests for `FlowSwitch` activity and extend test utilities - Implement `FlowSwitchTests` to verify behavior based on switch cases, modes, and literal expressions. - Enhance `ActivityExecutionContextExtensions` with methods to retrieve and check outcomes in execution context. * Update test guidelines to include examples for checking activity outcomes - Add unit test examples for validating multiple and default outcomes. - Extend documentation to describe new `ActivityExecutionContextExtensions` methods: `GetOutcomes` and `HasOutcome`. * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Simplify `GetOutcomes` method in `ActivityExecutionContextExtensions`. * Add unit tests for `FlowSendHttpRequest` activity and refactor helper utilities - Introduce `FlowSendHttpRequestTests` to validate activity behavior across various scenarios. - Add utility methods in `SendHttpRequestTestHelpers` for creating mock responses and exceptions. - Refactor `Helpers` namespace to `Http.Helpers` for better organization. - Update project file to reflect namespace adjustments. * Update test/unit/Elsa.Activities.UnitTests/Elsa.Activities.UnitTests.csproj Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-21 13:36:54 +00:00
[Theory]
[MemberData(nameof(StatusCodeOutcomeTestCases))]
public async Task Should_Return_Outcome_Based_On_Status_Code(
int[] expectedStatusCodes,
HttpStatusCode actualStatusCode,
string[] expectedOutcomes)
{
// Arrange
var flowSendHttpRequest = CreateFlowSendHttpRequest(
new("https://api.example.com/test"),
expectedStatusCodes: expectedStatusCodes);
var responseHandler = SendHttpRequestTestHelpers.CreateResponseHandler(actualStatusCode);
// Act
var context = await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
// Assert - Activity should return outcomes based on status code match.
var outcomes = context.GetOutcomes().ToList();
Assert.Equal(expectedOutcomes.Length, outcomes.Count);
foreach (var expectedOutcome in expectedOutcomes)
Assert.Contains(expectedOutcome, outcomes);
}
public static IEnumerable<object[]> StatusCodeOutcomeTestCases()
{
// Expected status codes: 200, 404
// Status code matches - returns status code + Done
yield return [new[] { 200, 404 }, HttpStatusCode.OK, new[] { "200", "Done" }];
yield return [new[] { 200, 404 }, HttpStatusCode.NotFound, new[] { "404", "Done" }];
// Status code doesn't match - returns "Unmatched status code" + Done
yield return [new[] { 200, 404 }, HttpStatusCode.InternalServerError, new[] { "Unmatched status code", "Done" }];
// No expected status codes - returns only Done
yield return [Array.Empty<int>(), HttpStatusCode.OK, new[] { "Done" }];
}
[Fact]
public async Task Should_Return_FailedToConnect_Outcome_On_HttpRequestException()
{
// Arrange
var flowSendHttpRequest = CreateFlowSendHttpRequest(new("https://api.example.com/error"));
var responseHandler = SendHttpRequestTestHelpers.CreateExceptionHandler<HttpRequestException>("Connection failed");
// Act
var context = await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
// Assert
Assert.True(context.HasOutcome("Failed to connect"));
}
[Fact]
public async Task Should_Return_Timeout_Outcome_On_TaskCanceledException()
{
// Arrange
var flowSendHttpRequest = CreateFlowSendHttpRequest(new("https://api.example.com/timeout"));
var responseHandler = SendHttpRequestTestHelpers.CreateExceptionHandler<TaskCanceledException>("Request timed out");
// Act
var context = await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
// Assert
Assert.True(context.HasOutcome("Timeout"));
}
[Fact]
public async Task Should_Set_Response_Headers_Output()
{
// Arrange
var expectedHeaders = new Dictionary<string, string>
{
{ "Custom-Header", "CustomValue" },
{ "X-Rate-Limit", "100" }
};
var responseHandler = SendHttpRequestTestHelpers.CreateResponseHandler(HttpStatusCode.OK, additionalHeaders: expectedHeaders);
var flowSendHttpRequest = CreateFlowSendHttpRequest(new("https://api.example.com/headers"));
// Act
var context = await ExecuteActivityAsync(flowSendHttpRequest, responseHandler);
// Assert
var responseHeadersObj = context.GetActivityOutput(() => flowSendHttpRequest.ResponseHeaders);
var responseHeaders = responseHeadersObj as HttpHeaders;
Assert.NotNull(responseHeaders);
Assert.True(responseHeaders.ContainsKey("Custom-Header"));
Assert.True(responseHeaders.ContainsKey("X-Rate-Limit"));
}
[Fact]
public void Should_Have_Correct_Activity_Attributes()
{
var fixture = new ActivityTestFixture(new FlowSendHttpRequest());
fixture.AssertActivityAttributes(
expectedNamespace: "Elsa",
expectedCategory: "HTTP",
expectedDisplayName: "HTTP Request (flow)",
expectedDescription: "Send an HTTP request.",
expectedKind: ActivityKind.Task
);
}
[Fact]
public void Should_Have_Default_Expected_Status_Codes()
{
// Arrange
var flowSendHttpRequest = new FlowSendHttpRequest();
// Act - Get the default value
var defaultValue = ((IActivityPropertyDefaultValueProvider)flowSendHttpRequest)
.GetDefaultValue(typeof(FlowSendHttpRequest).GetProperty(nameof(FlowSendHttpRequest.ExpectedStatusCodes))!);
// Assert
var defaultStatusCodes = defaultValue as List<int>;
Assert.NotNull(defaultStatusCodes);
Assert.Single(defaultStatusCodes);
Assert.Equal(200, defaultStatusCodes.First());
}
// Private helper methods
private static FlowSendHttpRequest CreateFlowSendHttpRequest(
Uri url,
string method = "GET",
object? content = null,
string? contentType = null,
string? authorization = null,
int[]? expectedStatusCodes = null)
{
return new()
{
Url = new(url),
Method = new(method),
Content = content != null ? new Input<object?>(content) : null!,
ContentType = contentType != null ? new Input<string?>(contentType) : null!,
Authorization = authorization != null ? new Input<string?>(authorization) : null!,
ExpectedStatusCodes = expectedStatusCodes != null ? new Input<ICollection<int>>(expectedStatusCodes) : null!
};
}
private static Task<ActivityExecutionContext> ExecuteActivityAsync(
FlowSendHttpRequest flowSendHttpRequest,
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> responseHandler)
{
return new ActivityTestFixture(flowSendHttpRequest).WithHttpServices(responseHandler).ExecuteAsync();
}
}