Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling. - Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options. - Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation. - Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios. - Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling. - Included tests for UdpTransportOptions to verify default values and modification capabilities. - Enhanced service registration tests for Udp transport services in the dependency injection container.
288 lines
8.5 KiB
C#
288 lines
8.5 KiB
C#
using FluentAssertions;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Moq;
|
|
using StellaOps.Gateway.WebService.Middleware;
|
|
using StellaOps.Router.Common.Abstractions;
|
|
using StellaOps.Router.Common.Models;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Gateway.WebService.Tests;
|
|
|
|
/// <summary>
|
|
/// Unit tests for <see cref="EndpointResolutionMiddleware"/>.
|
|
/// </summary>
|
|
public sealed class EndpointResolutionMiddlewareTests
|
|
{
|
|
private readonly Mock<IGlobalRoutingState> _routingStateMock;
|
|
private readonly Mock<RequestDelegate> _nextMock;
|
|
private bool _nextCalled;
|
|
|
|
public EndpointResolutionMiddlewareTests()
|
|
{
|
|
_routingStateMock = new Mock<IGlobalRoutingState>();
|
|
_nextMock = new Mock<RequestDelegate>();
|
|
_nextMock.Setup(n => n(It.IsAny<HttpContext>()))
|
|
.Callback(() => _nextCalled = true)
|
|
.Returns(Task.CompletedTask);
|
|
}
|
|
|
|
private EndpointResolutionMiddleware CreateMiddleware()
|
|
{
|
|
return new EndpointResolutionMiddleware(_nextMock.Object);
|
|
}
|
|
|
|
private static HttpContext CreateHttpContext(string method = "GET", string path = "/api/test")
|
|
{
|
|
var context = new DefaultHttpContext();
|
|
context.Request.Method = method;
|
|
context.Request.Path = path;
|
|
context.Response.Body = new MemoryStream();
|
|
return context;
|
|
}
|
|
|
|
private static EndpointDescriptor CreateEndpoint(
|
|
string serviceName = "test-service",
|
|
string method = "GET",
|
|
string path = "/api/test")
|
|
{
|
|
return new EndpointDescriptor
|
|
{
|
|
ServiceName = serviceName,
|
|
Version = "1.0.0",
|
|
Method = method,
|
|
Path = path
|
|
};
|
|
}
|
|
|
|
#region Matching Endpoint Tests
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithMatchingEndpoint_SetsHttpContextItem()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint = CreateEndpoint();
|
|
var context = CreateHttpContext();
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/test"))
|
|
.Returns(endpoint);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeTrue();
|
|
context.Items[RouterHttpContextKeys.EndpointDescriptor].Should().Be(endpoint);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithMatchingEndpoint_CallsNext()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint = CreateEndpoint();
|
|
var context = CreateHttpContext();
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/test"))
|
|
.Returns(endpoint);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeTrue();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Unknown Path Tests
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithUnknownPath_Returns404()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var context = CreateHttpContext(path: "/api/unknown");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/unknown"))
|
|
.Returns((EndpointDescriptor?)null);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeFalse();
|
|
context.Response.StatusCode.Should().Be(StatusCodes.Status404NotFound);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithUnknownPath_WritesErrorResponse()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var context = CreateHttpContext(path: "/api/unknown");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/unknown"))
|
|
.Returns((EndpointDescriptor?)null);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
context.Response.Body.Seek(0, SeekOrigin.Begin);
|
|
using var reader = new StreamReader(context.Response.Body);
|
|
var responseBody = await reader.ReadToEndAsync();
|
|
|
|
responseBody.Should().Contain("not found");
|
|
responseBody.Should().Contain("/api/unknown");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HTTP Method Tests
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithPostMethod_ResolvesCorrectly()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint = CreateEndpoint(method: "POST");
|
|
var context = CreateHttpContext(method: "POST");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("POST", "/api/test"))
|
|
.Returns(endpoint);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeTrue();
|
|
context.Items[RouterHttpContextKeys.EndpointDescriptor].Should().Be(endpoint);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithDeleteMethod_ResolvesCorrectly()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint = CreateEndpoint(method: "DELETE", path: "/api/users/123");
|
|
var context = CreateHttpContext(method: "DELETE", path: "/api/users/123");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("DELETE", "/api/users/123"))
|
|
.Returns(endpoint);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithWrongMethod_Returns404()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var context = CreateHttpContext(method: "DELETE", path: "/api/test");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("DELETE", "/api/test"))
|
|
.Returns((EndpointDescriptor?)null);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeFalse();
|
|
context.Response.StatusCode.Should().Be(StatusCodes.Status404NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Path Variations Tests
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithParameterizedPath_ResolvesCorrectly()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint = CreateEndpoint(path: "/api/users/{id}");
|
|
var context = CreateHttpContext(path: "/api/users/123");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/users/123"))
|
|
.Returns(endpoint);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeTrue();
|
|
context.Items[RouterHttpContextKeys.EndpointDescriptor].Should().Be(endpoint);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithRootPath_ResolvesCorrectly()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint = CreateEndpoint(path: "/");
|
|
var context = CreateHttpContext(path: "/");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/"))
|
|
.Returns(endpoint);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_nextCalled.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invoke_WithEmptyPath_PassesEmptyStringToRouting()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var context = CreateHttpContext(path: "");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", ""))
|
|
.Returns((EndpointDescriptor?)null);
|
|
|
|
// Act
|
|
await middleware.Invoke(context, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
_routingStateMock.Verify(r => r.ResolveEndpoint("GET", ""), Times.Once);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Multiple Calls Tests
|
|
|
|
[Fact]
|
|
public async Task Invoke_MultipleCalls_EachResolvesIndependently()
|
|
{
|
|
// Arrange
|
|
var middleware = CreateMiddleware();
|
|
var endpoint1 = CreateEndpoint(path: "/api/users");
|
|
var endpoint2 = CreateEndpoint(path: "/api/items");
|
|
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/users"))
|
|
.Returns(endpoint1);
|
|
_routingStateMock.Setup(r => r.ResolveEndpoint("GET", "/api/items"))
|
|
.Returns(endpoint2);
|
|
|
|
var context1 = CreateHttpContext(path: "/api/users");
|
|
var context2 = CreateHttpContext(path: "/api/items");
|
|
|
|
// Act
|
|
await middleware.Invoke(context1, _routingStateMock.Object);
|
|
await middleware.Invoke(context2, _routingStateMock.Object);
|
|
|
|
// Assert
|
|
context1.Items[RouterHttpContextKeys.EndpointDescriptor].Should().Be(endpoint1);
|
|
context2.Items[RouterHttpContextKeys.EndpointDescriptor].Should().Be(endpoint2);
|
|
}
|
|
|
|
#endregion
|
|
}
|