using Xunit; using Moq; using Moq.Protected; using System.Net; using Svrnty.MCP.Gateway.Infrastructure.Transport; using Svrnty.MCP.Gateway.Core.Models; namespace Svrnty.MCP.Gateway.Infrastructure.Tests.Transport; /// /// Unit tests for HttpServerTransport following TDD approach. /// Tests HTTP transport implementation. /// public class HttpServerTransportTests { [Fact] public void Constructor_WithValidUrl_CreatesSuccessfully() { // Arrange & Act var transport = new HttpServerTransport("http://localhost:5000"); // Assert Assert.NotNull(transport); Assert.False(transport.IsConnected); } [Fact] public void Constructor_WithNullUrl_ThrowsException() { // Arrange, Act & Assert Assert.Throws(() => new HttpServerTransport(null!)); } [Fact] public async Task ConnectAsync_WithHealthyServer_SetsConnected() { // Arrange var mockHttpMessageHandler = new Mock(); mockHttpMessageHandler.Protected() .Setup>( "SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.OK }); var httpClient = new HttpClient(mockHttpMessageHandler.Object); var transport = new HttpServerTransport("http://localhost:5000", httpClient); // Act await transport.ConnectAsync(); // Assert Assert.True(transport.IsConnected); } [Fact] public async Task SendRequestAsync_WithSuccessfulResponse_ReturnsResponse() { // Arrange var expectedResponse = new GatewayResponse { Success = true, Result = new Dictionary { { "data", "test" } } }; var mockHttpMessageHandler = new Mock(); mockHttpMessageHandler.Protected() .SetupSequence>( "SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage // Health check { StatusCode = HttpStatusCode.OK }) .ReturnsAsync(new HttpResponseMessage // Actual request { StatusCode = HttpStatusCode.OK, Content = new StringContent(System.Text.Json.JsonSerializer.Serialize(expectedResponse)) }); var httpClient = new HttpClient(mockHttpMessageHandler.Object); var transport = new HttpServerTransport("http://localhost:5000", httpClient); await transport.ConnectAsync(); var request = new GatewayRequest { ToolName = "test_tool" }; // Act var response = await transport.SendRequestAsync(request); // Assert Assert.NotNull(response); Assert.True(response.Success); } [Fact] public async Task SendRequestAsync_WithHttpError_ReturnsErrorResponse() { // Arrange var mockHttpMessageHandler = new Mock(); mockHttpMessageHandler.Protected() .SetupSequence>( "SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage // Health check { StatusCode = HttpStatusCode.OK }) .ReturnsAsync(new HttpResponseMessage // Actual request { StatusCode = HttpStatusCode.InternalServerError, ReasonPhrase = "Internal Server Error" }); var httpClient = new HttpClient(mockHttpMessageHandler.Object); var transport = new HttpServerTransport("http://localhost:5000", httpClient); await transport.ConnectAsync(); var request = new GatewayRequest { ToolName = "test_tool" }; // Act var response = await transport.SendRequestAsync(request); // Assert Assert.NotNull(response); Assert.False(response.Success); Assert.Contains("InternalServerError", response.Error); } [Fact] public async Task SendRequestAsync_WithoutConnect_ThrowsException() { // Arrange var transport = new HttpServerTransport("http://localhost:5000"); var request = new GatewayRequest { ToolName = "test" }; // Act & Assert await Assert.ThrowsAsync(() => transport.SendRequestAsync(request)); } [Fact] public async Task DisconnectAsync_SetsNotConnected() { // Arrange var mockHttpMessageHandler = new Mock(); mockHttpMessageHandler.Protected() .Setup>( "SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.OK }); var httpClient = new HttpClient(mockHttpMessageHandler.Object); var transport = new HttpServerTransport("http://localhost:5000", httpClient); await transport.ConnectAsync(); Assert.True(transport.IsConnected); // Act await transport.DisconnectAsync(); // Assert Assert.False(transport.IsConnected); } }