diff --git a/test/unit/Elsa.Activities.UnitTests/Http/SendHttpRequestTests.cs b/test/unit/Elsa.Activities.UnitTests/Http/SendHttpRequestTests.cs deleted file mode 100644 index d14199041..000000000 --- a/test/unit/Elsa.Activities.UnitTests/Http/SendHttpRequestTests.cs +++ /dev/null @@ -1,367 +0,0 @@ -using System.Net; -using System.Text; -using Elsa.Activities.UnitTests.Helpers; -using Elsa.Extensions; -using Elsa.Http; -using Elsa.Testing.Shared; -using Elsa.Workflows; -using Elsa.Workflows.Attributes; -using Microsoft.Extensions.DependencyInjection; -using NSubstitute; - -namespace Elsa.Activities.UnitTests.HTTP; - -public class SendHttpRequestTests -{ - [Fact] - public async Task Should_Send_GET_Request_And_Handle_Success_Response() - { - // Arrange - var expectedUrl = new Uri("https://api.example.com/data"); - var mockHttpClientFactory = Substitute.For(); - - var responseContent = new StringContent("{\"result\": \"success\"}", Encoding.UTF8, "application/json"); - var httpResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = responseContent - }; - - HttpRequestMessage? capturedRequest = null; - var testHandler = new TestHttpMessageHandler((request, _) => - { - capturedRequest = request; - return Task.FromResult(httpResponse); - }); - - var httpClient = new HttpClient(testHandler); - mockHttpClientFactory.CreateClient(Arg.Any()).Returns(httpClient); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(expectedUrl), - Method = new("GET"), - // Note: Setting ExpectedStatusCodes can cause workflow scheduling issues in test environments, - // because the activity may attempt to schedule additional branches for each expected status code, - // which can interfere with the test's control flow and assertions. To avoid this, we leave - // ExpectedStatusCodes empty in this test. - ExpectedStatusCodes = new List() - }; - - // Act - var context = await ExecuteAsync(sendHttpRequest, mockHttpClientFactory); - - // Assert - Assert.NotNull(capturedRequest); - Assert.Equal(HttpMethod.Get, capturedRequest.Method); - Assert.Equal(expectedUrl, capturedRequest.RequestUri); - - var statusCodeOutput = context.GetActivityOutput(() => sendHttpRequest.StatusCode); - Assert.Equal(200, statusCodeOutput); - } - - [Fact] - public async Task Should_Send_POST_Request_With_JSON_Content() - { - // Arrange - var expectedUrl = new Uri("https://api.example.com/create"); - var requestContent = new { name = "test", value = 42 }; - var contentType = "application/json"; - var mockHttpClientFactory = Substitute.For(); - - var httpResponse = new HttpResponseMessage(HttpStatusCode.Created); - - HttpRequestMessage? capturedRequest = null; - var testHandler = new TestHttpMessageHandler((request, _) => - { - capturedRequest = request; - return Task.FromResult(httpResponse); - }); - - var httpClient = new HttpClient(testHandler); - mockHttpClientFactory.CreateClient(Arg.Any()).Returns(httpClient); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(expectedUrl), - Method = new("POST"), - Content = new(requestContent), - ContentType = new(contentType), - ExpectedStatusCodes = new List() - }; - - // Act - await ExecuteAsync(sendHttpRequest, mockHttpClientFactory); - - // Assert - Assert.NotNull(capturedRequest); - Assert.Equal(HttpMethod.Post, capturedRequest.Method); - Assert.Equal(expectedUrl, capturedRequest.RequestUri); - Assert.NotNull(capturedRequest.Content); - } - - [Fact] - public async Task Should_Add_Authorization_Header() - { - // Arrange - var expectedUrl = new Uri("https://api.example.com/secure"); - var authorizationHeader = "Bearer token123"; - var mockHttpClientFactory = Substitute.For(); - - var httpResponse = new HttpResponseMessage(HttpStatusCode.OK); - - HttpRequestMessage? capturedRequest = null; - var testHandler = new TestHttpMessageHandler((request, _) => - { - capturedRequest = request; - return Task.FromResult(httpResponse); - }); - - var httpClient = new HttpClient(testHandler); - mockHttpClientFactory.CreateClient(Arg.Any()).Returns(httpClient); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(expectedUrl), - Method = new("GET"), - Authorization = new(authorizationHeader), - ExpectedStatusCodes = new List() - }; - - // Act - await ExecuteAsync(sendHttpRequest, mockHttpClientFactory); - - // Assert - Assert.NotNull(capturedRequest); - Assert.NotNull(capturedRequest.Headers.Authorization); - Assert.Equal(authorizationHeader, capturedRequest.Headers.Authorization.ToString()); - } - - [Fact] - public Task Should_Execute_Matching_Status_Code_Activity() - { - // Arrange - var mockHttpClientFactory = Substitute.For(); - var mockHttpClient = Substitute.For(); - var mockActivity404 = Substitute.For(); - var mockActivity200 = Substitute.For(); - - var httpResponse = new HttpResponseMessage(HttpStatusCode.NotFound); - mockHttpClientFactory.CreateClient(Arg.Any()).Returns(mockHttpClient); - mockHttpClient.SendAsync(Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(httpResponse)); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(new Uri("https://api.example.com/notfound")), - Method = new("GET"), - // Test the configuration without actually scheduling activities - ExpectedStatusCodes = new List - { - new(200, mockActivity200), - new(404, mockActivity404) - } - }; - - // Act & Assert - This will fail due to scheduling, so we'll just test the configuration - var matchingCase = sendHttpRequest.ExpectedStatusCodes.FirstOrDefault(x => x.StatusCode == 404); - Assert.NotNull(matchingCase); - Assert.Equal(mockActivity404, matchingCase.Activity); - - // Test that we can identify the correct status code without execution - Assert.Equal(2, sendHttpRequest.ExpectedStatusCodes.Count); - return Task.CompletedTask; - } - - [Fact] - public Task Should_Execute_UnmatchedStatusCode_Activity_When_No_Match() - { - // Arrange - var mockUnmatchedActivity = Substitute.For(); - var mockActivity200 = Substitute.For(); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(new Uri("https://api.example.com/error")), - Method = new("GET"), - ExpectedStatusCodes = new List - { - new(200, mockActivity200) - }, - UnmatchedStatusCode = mockUnmatchedActivity - }; - - // Act & Assert - Test configuration without execution - var matchingCase = sendHttpRequest.ExpectedStatusCodes.FirstOrDefault(x => x.StatusCode == 500); - Assert.Null(matchingCase); - - // Verify UnmatchedStatusCode activity is set - Assert.Equal(mockUnmatchedActivity, sendHttpRequest.UnmatchedStatusCode); - return Task.CompletedTask; - } - - [Fact] - public Task Should_Handle_HttpRequestException_And_Execute_FailedToConnect_Activity() - { - // Arrange - var mockFailedToConnectActivity = Substitute.For(); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(new Uri("https://unreachable.example.com")), - Method = new("GET"), - FailedToConnect = mockFailedToConnectActivity - }; - - // Act & Assert - Test configuration without execution - Assert.Equal(mockFailedToConnectActivity, sendHttpRequest.FailedToConnect); - return Task.CompletedTask; - } - - [Fact] - public Task Should_Handle_TaskCanceledException_And_Execute_Timeout_Activity() - { - // Arrange - var mockTimeoutActivity = Substitute.For(); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(new Uri("https://slow.example.com")), - Method = new("GET"), - Timeout = mockTimeoutActivity - }; - - // Act & Assert - Test configuration without execution - Assert.Equal(mockTimeoutActivity, sendHttpRequest.Timeout); - return Task.CompletedTask; - } - - [Fact] - public async Task Should_Set_Response_Headers_Output() - { - // Arrange - var mockHttpClientFactory = Substitute.For(); - - var httpResponse = new HttpResponseMessage(HttpStatusCode.OK); - httpResponse.Headers.Add("Custom-Header", "CustomValue"); - httpResponse.Headers.Add("X-Rate-Limit", "100"); - - var testHandler = new TestHttpMessageHandler((_, _) => - Task.FromResult(httpResponse)); - - var httpClient = new HttpClient(testHandler); - mockHttpClientFactory.CreateClient(Arg.Any()).Returns(httpClient); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(new Uri("https://api.example.com/headers")), - Method = new("GET"), - ExpectedStatusCodes = new List() - }; - - // Act - var context = await ExecuteAsync(sendHttpRequest, mockHttpClientFactory); - - // Assert - var responseHeadersObj = context.GetActivityOutput(() => sendHttpRequest.ResponseHeaders); - var responseHeaders = responseHeadersObj as HttpHeaders; - Assert.NotNull(responseHeaders); - Assert.True(responseHeaders.ContainsKey("Custom-Header")); - Assert.True(responseHeaders.ContainsKey("X-Rate-Limit")); - } - - [Fact] - public async Task Should_Parse_JSON_Response_Content() - { - // Arrange - var mockHttpClientFactory = Substitute.For(); - - var jsonContent = "{\"id\": 123, \"name\": \"test\"}"; - var responseContent = new StringContent(jsonContent, Encoding.UTF8, "application/json"); - var httpResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = responseContent - }; - - var testHandler = new TestHttpMessageHandler((_, _) => - Task.FromResult(httpResponse)); - - var httpClient = new HttpClient(testHandler); - mockHttpClientFactory.CreateClient(Arg.Any()).Returns(httpClient); - - var sendHttpRequest = new SendHttpRequest - { - Url = new(new Uri("https://api.example.com/json")), - Method = new("GET"), - ExpectedStatusCodes = new List() - }; - - // Act - var context = await ExecuteAsync(sendHttpRequest, mockHttpClientFactory); - - // Assert - var parsedContent = context.GetActivityOutput(() => sendHttpRequest.ParsedContent); - var statusCode = context.GetActivityOutput(() => sendHttpRequest.StatusCode); - var httpResponseResult = (HttpResponseMessage)context.GetActivityOutput(() => sendHttpRequest.Result)!; - - Assert.NotNull(parsedContent); - Assert.Equal(200, statusCode); - - // Verify the response was received and stored - Assert.NotNull(httpResponseResult); - Assert.Equal(HttpStatusCode.OK, httpResponseResult.StatusCode); - } - - [Fact] - public void Should_Have_Correct_Activity_Attributes() - { - // Arrange & Act - var activityType = typeof(SendHttpRequest); - var activityAttribute = activityType.GetCustomAttributes(typeof(ActivityAttribute), false) - .Cast().FirstOrDefault(); - - // Assert - Assert.NotNull(activityAttribute); - Assert.Equal("Elsa", activityAttribute.Namespace); - Assert.Equal("HTTP", activityAttribute.Category); - Assert.Equal("Send an HTTP request.", activityAttribute.Description); - Assert.Equal("HTTP Request", activityAttribute.DisplayName); - Assert.Equal(ActivityKind.Task, activityAttribute.Kind); - } - - [Fact] - public void Should_Inherit_From_SendHttpRequestBase() - { - // Arrange & Act - var sendHttpRequest = new SendHttpRequest(); - - // Assert - Assert.IsAssignableFrom(sendHttpRequest); - } - - [Fact] - public void Should_Create_HttpStatusCodeCase_With_Status_And_Activity() - { - // Arrange - const int statusCode = 200; - var mockActivity = Substitute.For(); - - // Act - var httpStatusCodeCase = new HttpStatusCodeCase(statusCode, mockActivity); - - // Assert - Assert.Equal(statusCode, httpStatusCodeCase.StatusCode); - Assert.Equal(mockActivity, httpStatusCodeCase.Activity); - } - - private static Task ExecuteAsync(IActivity activity, IHttpClientFactory httpClientFactory) - { - return new ActivityTestFixture(activity) - .WithHttpServices() - .ConfigureServices(services => - { - services.AddSingleton(httpClientFactory); - services.AddLogging(); - }) - .ExecuteAsync(); - } -}