diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointContentTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointContentTests.cs index a137fb13b..3e4eee55b 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointContentTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointContentTests.cs @@ -12,13 +12,11 @@ public class HttpEndpointContentTests(App app) : AppComponentTest(app) public async Task JsonContent_ValidJson_ReturnsEchoedJson() { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); var testData = new { Name = "John", Age = 30, City = "New York" }; var jsonContent = JsonSerializer.Serialize(testData); - var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); // Act - var response = await client.PostAsync("test/json-content", content); + var response = await PostJsonContentAsync(jsonContent); var responseContent = await response.Content.ReadAsStringAsync(); // Assert @@ -31,93 +29,107 @@ public class HttpEndpointContentTests(App app) : AppComponentTest(app) Assert.Equal("John", nameProperty.GetString()); } - [Fact] - public async Task JsonContent_InvalidJson_ReturnsBadRequest() + [Theory] + [InlineData("{ \"name\": \"John\", invalid }", HttpStatusCode.BadRequest)] + [InlineData("", HttpStatusCode.OK, "No content received")] + public async Task JsonContent_InvalidOrEmpty_ReturnsExpectedResponse( + string jsonContent, + HttpStatusCode expectedStatusCode, + string? expectedContentFragment = null) { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var invalidJson = "{ \"name\": \"John\", invalid }"; - var content = new StringContent(invalidJson, Encoding.UTF8, "application/json"); - // Act - var response = await client.PostAsync("test/json-content", content); - - // Assert - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - } - - [Fact] - public async Task JsonContent_EmptyBody_ReturnsNoContentMessage() - { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new StringContent("", Encoding.UTF8, "application/json"); - - // Act - var response = await client.PostAsync("test/json-content", content); + var response = await PostJsonContentAsync(jsonContent); var responseContent = await response.Content.ReadAsStringAsync(); // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("No content received", responseContent); + Assert.Equal(expectedStatusCode, response.StatusCode); + if (expectedContentFragment != null) + { + Assert.Contains(expectedContentFragment, responseContent); + } } - [Fact] - public async Task FormData_ValidFormData_ReturnsExtractedFields() + [Theory] + [InlineData("John Doe", "john@example.com", "Name: John Doe", "Email: john@example.com")] + [InlineData("Jane Smith", "jane@test.org", "Name: Jane Smith", "Email: jane@test.org")] + public async Task FormData_ValidData_ReturnsExtractedFields( + string name, + string email, + string expectedNameFragment, + string expectedEmailFragment) { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); var formData = new List> { - new("name", "John Doe"), - new("email", "john@example.com") + new("name", name), + new("email", email) }; - var content = new FormUrlEncodedContent(formData); // Act - var response = await client.PostAsync("test/form-data", content); + var response = await PostFormDataAsync(formData); var responseContent = await response.Content.ReadAsStringAsync(); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("Name: John Doe", responseContent); - Assert.Contains("Email: john@example.com", responseContent); + Assert.Contains(expectedNameFragment, responseContent); + Assert.Contains(expectedEmailFragment, responseContent); } [Fact] public async Task FormData_MissingFields_ReturnsUnknownValues() { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); var formData = new List> { new("other", "value") }; - var content = new FormUrlEncodedContent(formData); // Act - var response = await client.PostAsync("test/form-data", content); + var response = await PostFormDataAsync(formData); var responseContent = await response.Content.ReadAsStringAsync(); // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("Name: unknown", responseContent); - Assert.Contains("Email: unknown", responseContent); + AssertOkResponseContains(response, responseContent, "Name: unknown", "Email: unknown"); } [Fact] public async Task FormData_EmptyForm_ReturnsNoFormDataMessage() { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new StringContent("", Encoding.UTF8, "text/plain"); - // Act - var response = await client.PostAsync("test/form-data", content); + var response = await PostEmptyFormAsync(); var responseContent = await response.Content.ReadAsStringAsync(); // Assert + AssertOkResponseContains(response, responseContent, "No form data received"); + } + + private async Task PostJsonContentAsync(string jsonContent) + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); + return await client.PostAsync("test/json-content", content); + } + + private async Task PostFormDataAsync(IEnumerable> formData) + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new FormUrlEncodedContent(formData); + return await client.PostAsync("test/form-data", content); + } + + private async Task PostEmptyFormAsync() + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new StringContent("", Encoding.UTF8, "text/plain"); + return await client.PostAsync("test/form-data", content); + } + + private static void AssertOkResponseContains(HttpResponseMessage response, string responseContent, params string[] expectedFragments) + { Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("No form data received", responseContent); + foreach (var fragment in expectedFragments) + { + Assert.Contains(fragment, responseContent); + } } } diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointFileUploadTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointFileUploadTests.cs index 58813f67e..5b78b03e1 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointFileUploadTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointFileUploadTests.cs @@ -7,113 +7,145 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.Http; public class HttpEndpointFileUploadTests(App app) : AppComponentTest(app) { - [Fact] - public async Task FileUpload_SingleFile_ReturnsFileDetails() + [Theory] + [InlineData("Test file content", "test.txt", "text/plain", "17 bytes")] + [InlineData("Sample document", "sample.txt", "text/plain", "15 bytes")] + [InlineData("", "empty.txt", "text/plain", "0 bytes")] + public async Task FileUpload_SingleFile_ReturnsExpectedMetadata( + string fileContent, + string fileName, + string contentType, + string expectedSizeText) { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); - var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("Test file content")); - fileContent.Headers.ContentType = new("text/plain"); - content.Add(fileContent, "file", "test.txt"); + var fileData = Encoding.UTF8.GetBytes(fileContent); // Act - var response = await client.PostAsync("test/file-upload", content); + var response = await PostSingleFileAsync(fileData, fileName, contentType); var responseContent = await response.Content.ReadAsStringAsync(); // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("test.txt", responseContent); - Assert.Contains("17 bytes", responseContent); // "Test file content" is 17 bytes - Assert.Contains("text/plain", responseContent); + AssertOkResponseContains(response, responseContent, fileName, expectedSizeText, contentType); } [Fact] public async Task FileUpload_MultipleFiles_ReturnsAllFileDetails() { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); - - var file1Content = new ByteArrayContent(Encoding.UTF8.GetBytes("File 1 content")); - file1Content.Headers.ContentType = new("text/plain"); - content.Add(file1Content, "file1", "file1.txt"); - - var file2Content = new ByteArrayContent(Encoding.UTF8.GetBytes("File 2 content")); - file2Content.Headers.ContentType = new("text/plain"); - content.Add(file2Content, "file2", "file2.txt"); + var files = new[] + { + ("File 1 content", "file1.txt", "text/plain"), + ("File 2 content", "file2.txt", "text/plain") + }; // Act - var response = await client.PostAsync("test/file-upload", content); + var response = await PostMultipleFilesAsync(files); var responseContent = await response.Content.ReadAsStringAsync(); // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("file1.txt", responseContent); - Assert.Contains("file2.txt", responseContent); - Assert.Contains("14 bytes", responseContent); // Each file is 14 bytes + AssertOkResponseContains(response, responseContent, "file1.txt", "file2.txt", "14 bytes"); } [Fact] public async Task FileUpload_NoFiles_ReturnsNoFilesMessage() { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); - content.Add(new StringContent("value"), "field"); - // Act - var response = await client.PostAsync("test/file-upload", content); + var response = await PostFormDataWithoutFilesAsync(); var responseContent = await response.Content.ReadAsStringAsync(); // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("No files uploaded", responseContent); - } - - [Fact] - public async Task FileUpload_EmptyFile_ReturnsZeroBytesFile() - { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); - var fileContent = new ByteArrayContent([]); - fileContent.Headers.ContentType = new("text/plain"); - content.Add(fileContent, "file", "empty.txt"); - - // Act - var response = await client.PostAsync("test/file-upload", content); - var responseContent = await response.Content.ReadAsStringAsync(); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("empty.txt", responseContent); - Assert.Contains("0 bytes", responseContent); + AssertOkResponseContains(response, responseContent, "No files uploaded"); } [Fact] public async Task FileUpload_WithFormFields_ProcessesBothFilesAndFields() { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); - - // Add file - var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("Test content")); - fileContent.Headers.ContentType = new("text/plain"); - content.Add(fileContent, "file", "test.txt"); - - // Add form field - content.Add(new StringContent("John Doe"), "name"); + var fileData = Encoding.UTF8.GetBytes("Test content"); + var formFields = new[] { ("name", "John Doe") }; // Act - var response = await client.PostAsync("test/file-upload", content); + var response = await PostFileWithFormFieldsAsync(fileData, "test.txt", "text/plain", formFields); var responseContent = await response.Content.ReadAsStringAsync(); // Assert + AssertOkResponseContains(response, responseContent, "test.txt", "12 bytes"); + } + + private async Task PostSingleFileAsync( + byte[] fileData, + string fileName, + string contentType) + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new MultipartFormDataContent(); + + var fileContent = new ByteArrayContent(fileData); + fileContent.Headers.ContentType = new(contentType); + content.Add(fileContent, "file", fileName); + + return await client.PostAsync("test/file-upload", content); + } + + private async Task PostMultipleFilesAsync( + (string content, string fileName, string contentType)[] files) + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new MultipartFormDataContent(); + + for (int i = 0; i < files.Length; i++) + { + var file = files[i]; + var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes(file.content)); + fileContent.Headers.ContentType = new(file.contentType); + content.Add(fileContent, $"file{i + 1}", file.fileName); + } + + return await client.PostAsync("test/file-upload", content); + } + + private async Task PostFormDataWithoutFilesAsync() + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new MultipartFormDataContent(); + content.Add(new StringContent("value"), "field"); + + return await client.PostAsync("test/file-upload", content); + } + + private async Task PostFileWithFormFieldsAsync( + byte[] fileData, + string fileName, + string contentType, + (string name, string value)[] formFields) + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + using var content = new MultipartFormDataContent(); + + // Add file + var fileContent = new ByteArrayContent(fileData); + fileContent.Headers.ContentType = new(contentType); + content.Add(fileContent, "file", fileName); + + // Add form fields + foreach (var (name, value) in formFields) + { + content.Add(new StringContent(value), name); + } + + return await client.PostAsync("test/file-upload", content); + } + + private static void AssertOkResponseContains( + HttpResponseMessage response, + string responseContent, + params string[] expectedFragments) + { Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Contains("test.txt", responseContent); - Assert.Contains("12 bytes", responseContent); // "Test content" is 12 bytes + foreach (var fragment in expectedFragments) + { + Assert.Contains(fragment, responseContent); + } } } diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointQueryStringAndHeadersTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointQueryStringAndHeadersTests.cs index a5e2be31e..15186dba2 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointQueryStringAndHeadersTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointQueryStringAndHeadersTests.cs @@ -5,57 +5,44 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.Http; public class HttpEndpointQueryStringAndHeadersTests(App app) : AppComponentTest(app) { - [Fact] - public async Task QueryStringAndHeaders_WithParameters_ReturnsExtractedData() + [Theory] + [InlineData("name=John", "TestAgent/1.0", "Name: John", "UserAgent: TestAgent/1.0")] + [InlineData("name=Jane", "CustomAgent/2.0", "Name: Jane", "UserAgent: CustomAgent/2.0")] + [InlineData("name=John&age=30&city=NewYork", "TestAgent/1.0", "Name: John", "UserAgent: TestAgent/1.0")] + public async Task QueryStringAndHeaders_WithParameters_ReturnsExtractedData( + string queryString, + string userAgent, + string expectedNameFragment, + string expectedUserAgentFragment) { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - client.DefaultRequestHeaders.Add("User-Agent", "TestAgent/1.0"); - // Act - var response = await client.GetStringAsync("test/query-headers?name=John"); + var response = await GetQueryHeadersResponseAsync(queryString, userAgent); // Assert - Assert.Contains("Name: John", response); - Assert.Contains("UserAgent: TestAgent/1.0", response); + Assert.Contains(expectedNameFragment, response); + Assert.Contains(expectedUserAgentFragment, response); } [Fact] public async Task QueryStringAndHeaders_NoParameters_ReturnsDefaultValues() { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - // Act - var response = await client.GetStringAsync("test/query-headers"); + var response = await GetQueryHeadersResponseAsync(); // Assert Assert.Contains("Name: unknown", response); Assert.Contains("UserAgent:", response); // Should contain UserAgent even if empty } - [Fact] - public async Task QueryStringAndHeaders_MultipleQueryParameters_ReturnsFirstParameterValue() - { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - - // Act - var response = await client.GetStringAsync("test/query-headers?name=John&age=30&city=NewYork"); - - // Assert - Assert.Contains("Name: John", response); - } - [Fact] public async Task QueryStringAndHeaders_UrlEncodedQueryString_ReturnsDecodedValue() { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); var encodedName = Uri.EscapeDataString("John Doe"); + var queryString = $"name={encodedName}"; // Act - var response = await client.GetStringAsync($"test/query-headers?name={encodedName}"); + var response = await GetQueryHeadersResponseAsync(queryString); // Assert Assert.Contains("Name: John Doe", response); @@ -65,15 +52,48 @@ public class HttpEndpointQueryStringAndHeadersTests(App app) : AppComponentTest( public async Task QueryStringAndHeaders_CustomHeaders_ReturnsHeaderValues() { // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - client.DefaultRequestHeaders.Add("X-Custom-Header", "CustomValue"); - client.DefaultRequestHeaders.Add("User-Agent", "CustomAgent/2.0"); + var customHeaders = new Dictionary + { + ["X-Custom-Header"] = "CustomValue", + ["User-Agent"] = "CustomAgent/2.0" + }; // Act - var response = await client.GetStringAsync("test/query-headers?name=Jane"); + var response = await GetQueryHeadersResponseAsync("name=Jane", customHeaders: customHeaders); // Assert Assert.Contains("Name: Jane", response); Assert.Contains("UserAgent: CustomAgent/2.0", response); } + + private async Task GetQueryHeadersResponseAsync( + string? queryString = null, + string? userAgent = null, + Dictionary? customHeaders = null) + { + var client = WorkflowServer.CreateHttpWorkflowClient(); + + // Add headers + if (!string.IsNullOrEmpty(userAgent)) + { + client.DefaultRequestHeaders.Add("User-Agent", userAgent); + } + + if (customHeaders != null) + { + foreach (var header in customHeaders) + { + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + + // Build URL + var url = "test/query-headers"; + if (!string.IsNullOrEmpty(queryString)) + { + url += $"?{queryString}"; + } + + return await client.GetStringAsync(url); + } } diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointSecurityAndEdgeCasesTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointSecurityAndEdgeCasesTests.cs index 4e460727c..87adb358e 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointSecurityAndEdgeCasesTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointSecurityAndEdgeCasesTests.cs @@ -7,26 +7,12 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.Http; public class HttpEndpointSecurityAndEdgeCasesTests(App app) : AppComponentTest(app) { - - [Fact] - public async Task HttpEndpoint_WithAuthentication_RequiresAuthorization() - { - // Arrange - var client = WorkflowServer.CreateHttpWorkflowClient(); - - // Act - Try to access secure endpoint without authentication - var response = await client.GetAsync("test/secure"); - - // Assert - Should require authorization (exact behavior depends on auth configuration) - Assert.NotEqual(HttpStatusCode.OK, response.StatusCode); - } - [Fact] public async Task HttpEndpoint_BlockedFileExtensions_RejectsBlockedFiles() { // Arrange var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); + using var content = new MultipartFormDataContent(); var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("Malicious file")); fileContent.Headers.ContentType = new("application/octet-stream"); content.Add(fileContent, "file", "malware.exe"); // .exe is in blocked extensions @@ -43,7 +29,7 @@ public class HttpEndpointSecurityAndEdgeCasesTests(App app) : AppComponentTest(a { // Arrange var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); + using var content = new MultipartFormDataContent(); var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("Safe file content")); fileContent.Headers.ContentType = new("text/plain"); content.Add(fileContent, "file", "document.txt"); // .txt is not in blocked extensions @@ -177,7 +163,7 @@ public class HttpEndpointSecurityAndEdgeCasesTests(App app) : AppComponentTest(a { // Arrange var client = WorkflowServer.CreateHttpWorkflowClient(); - var content = new MultipartFormDataContent(); + using var content = new MultipartFormDataContent(); var emptyFile = new ByteArrayContent(Array.Empty()); emptyFile.Headers.ContentType = new("text/plain"); content.Add(emptyFile, "file", "empty.txt"); diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointTests.cs index 097451326..e4345c694 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/HttpEndpointTests.cs @@ -99,7 +99,7 @@ public class HttpEndpointTests(App app) : AppComponentTest(app) var tasks = new List>(); // Act - Send 10 concurrent requests - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { var index = i; tasks.Add(client.GetStringAsync($"test/users/user-{index}/orders/order-{index}")); diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/SecurityTestWorkflows.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/BlockedFileExtensionWorkflow.cs similarity index 67% rename from test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/SecurityTestWorkflows.cs rename to test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/BlockedFileExtensionWorkflow.cs index e64fc51d4..11ca85d6b 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/SecurityTestWorkflows.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/BlockedFileExtensionWorkflow.cs @@ -1,45 +1,14 @@ using System.Net; using Elsa.Http; -using Elsa.Workflows.Activities; using Elsa.Workflows.Activities.Flowchart.Activities; using Elsa.Workflows.Activities.Flowchart.Models; using Microsoft.AspNetCore.Http; namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.Http.Workflows; -public class SecurityTestWorkflow : WorkflowBase -{ - private static readonly string DefinitionId = Guid.NewGuid().ToString(); - - protected override void Build(IWorkflowBuilder builder) - { - builder.WithDefinitionId(DefinitionId); - - builder.Root = new Sequence - { - Activities = - [ - new HttpEndpoint - { - Path = new("test/secure"), - SupportedMethods = new([HttpMethods.Get, HttpMethods.Post]), - CanStartWorkflow = true - }, - // Hardcoded response that definitely returns Unauthorized (401) - new WriteHttpResponse - { - Content = new("SECURITY_TEST_UNAUTHORIZED"), - ContentType = new("text/plain"), - StatusCode = new(HttpStatusCode.Unauthorized) - } - ] - }; - } -} - public class BlockedFileExtensionWorkflow : WorkflowBase { - public static readonly string DefinitionId = Guid.NewGuid().ToString(); + private static readonly string DefinitionId = Guid.NewGuid().ToString(); protected override void Build(IWorkflowBuilder builder) { diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/RouteParametersWorkflow.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/RouteParametersWorkflow.cs index f8be07ee1..7d643d45b 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/RouteParametersWorkflow.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/Workflows/RouteParametersWorkflow.cs @@ -30,33 +30,47 @@ public class RouteParametersWorkflow : WorkflowBase { Content = new(context => { - // WORKAROUND: Since route table isn't populated during tests, - // manually parse the request URL to extract parameters - try + var routeData = routeDataVariable.Get(context); + + // First, try to get route parameters from the proper route data + var userId = "unknown"; + var orderId = "unknown"; + + if (routeData is { Count: > 0 }) { - var httpContext = context.GetRequiredService().HttpContext; - var path = httpContext?.Request?.Path.Value ?? ""; - - // Pattern: /workflows/test/users/{userId}/orders/{orderId} - var match = System.Text.RegularExpressions.Regex.Match(path, @"/workflows/test/users/([^/]+)/orders/([^/]+)"); - if (match.Success && match.Groups.Count >= 3) - { - return $"UserId: {match.Groups[1].Value}, OrderId: {match.Groups[2].Value}"; - } - - // Fallback: try simple splitting - var parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries); - if (parts.Length >= 6 && parts[1] == "test" && parts[2] == "users" && parts[4] == "orders") - { - return $"UserId: {parts[3]}, OrderId: {parts[5]}"; - } - - return "Could not parse route parameters"; + // Proper route data is available + userId = routeData.TryGetValue("userid", out var value) ? value.ToString() ?? "unknown" : "unknown"; + orderId = routeData.TryGetValue("orderid", out var value1) ? value1.ToString() ?? "unknown" : "unknown"; } - catch + else { - return "UserId: unknown, OrderId: unknown"; + // Fallback: Extract from HttpContext if route data is not populated + try + { + var httpContext = context.GetRequiredService().HttpContext; + var path = httpContext?.Request?.Path.Value ?? ""; + + // Split path and look for the users/{userId}/orders/{orderId} pattern + var parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries); + + // Find the users pattern in the path + for (int i = 0; i < parts.Length - 3; i++) + { + if (parts[i] == "users" && i + 2 < parts.Length && parts[i + 2] == "orders" && i + 3 < parts.Length) + { + userId = Uri.UnescapeDataString(parts[i + 1]); + orderId = Uri.UnescapeDataString(parts[i + 3]); + break; + } + } + } + catch + { + // Keep defaults if parsing fails + } } + + return $"UserId: {userId}, OrderId: {orderId}"; }), ContentType = new("text/plain"), StatusCode = new(HttpStatusCode.OK) diff --git a/test/integration/Elsa.Workflows.IntegrationTests/Activities/Http/HttpEndpointIntegrationTests.cs b/test/integration/Elsa.Workflows.IntegrationTests/Activities/Http/HttpEndpointIntegrationTests.cs deleted file mode 100644 index a3f4c04e9..000000000 --- a/test/integration/Elsa.Workflows.IntegrationTests/Activities/Http/HttpEndpointIntegrationTests.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Text.Json; -using Elsa.Http; - -namespace Elsa.Workflows.IntegrationTests.Activities.Http; - -public class HttpEndpointIntegrationTests -{ - [Fact] - public async Task HttpEndpoint_ConcurrentRequests_ProcessesAllSuccessfully() - { - // Arrange - Test concurrent HttpEndpoint activity instantiation and configuration - var tasks = new List>(); - - // Act - Create multiple HttpEndpoint activities concurrently - for (int i = 0; i < 10; i++) - { - var index = i; - var task = Task.Run(() => - { - var endpoint = new HttpEndpoint - { - Path = new($"test/concurrent/user-{index}"), - SupportedMethods = new(["GET", "POST"]) - }; - return endpoint; - }); - tasks.Add(task); - } - - var endpoints = await Task.WhenAll(tasks); - - // Assert - Verify all HttpEndpoint activities were created successfully - Assert.Equal(10, endpoints.Length); - - for (int i = 0; i < 10; i++) - { - var endpoint = endpoints[i]; - Assert.NotNull(endpoint); - - // Verify the path input was set correctly - Assert.NotNull(endpoint.Path); - - // Verify the supported methods input was set correctly - Assert.NotNull(endpoint.SupportedMethods); - } - } - - [Fact] - public async Task HttpEndpoint_LargeJsonPayload_ProcessesCorrectly() - { - // Arrange - var largeObject = new - { - Users = Enumerable.Range(1, 100).Select(i => new - { - Id = i, - Name = $"User {i}", - Email = $"user{i}@example.com", - Data = new string('x', 100) // 100 characters per user - }).ToArray() - }; - - var jsonContent = JsonSerializer.Serialize(largeObject); - - // Act & Assert - Test JSON processing capability - var parsedBack = JsonSerializer.Deserialize(jsonContent); - Assert.True(parsedBack.TryGetProperty("Users", out var usersProperty)); - Assert.Equal(JsonValueKind.Array, usersProperty.ValueKind); - Assert.Equal(100, usersProperty.GetArrayLength()); - } - - [Fact] - public async Task HttpEndpoint_UnicodeContent_ProcessesCorrectly() - { - // Arrange - var originalMessage = "Hello 世界! 🌍 Ñandú"; - var unicodeData = new { Message = originalMessage }; - var jsonContent = JsonSerializer.Serialize(unicodeData, new JsonSerializerOptions { WriteIndented = true }); - - // Act - Parse the JSON to simulate processing - var parsedResponse = JsonSerializer.Deserialize(jsonContent); - - // Assert - Assert.True(parsedResponse.TryGetProperty("Message", out var messageProperty), - $"Response should contain 'Message' property. Actual response: {jsonContent}"); - - var actualMessage = messageProperty.GetString(); - Assert.Equal(originalMessage, actualMessage); - } - - [Fact] - public async Task HttpEndpoint_SpecialCharactersInRoute_HandlesCorrectly() - { - // Test URI encoding/decoding - var specialUserId = "user@domain.com"; - var specialOrderId = "order-with-special-chars!@#$%"; - - var encodedUserId = Uri.EscapeDataString(specialUserId); - var encodedOrderId = Uri.EscapeDataString(specialOrderId); - - // Verify encoding/decoding works - Assert.Equal(specialUserId, Uri.UnescapeDataString(encodedUserId)); - Assert.Equal(specialOrderId, Uri.UnescapeDataString(encodedOrderId)); - } -}