mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-13 22:07:27 +01:00
* Version 2.x * Setup .NET 9 * 12 * cleanup some #if for NETSTANDARD1_3 * cleanup + fix tests for net8 * openapi * NO ConfigureAwait(false) + cleanup * . * #endif * HashSet * WireMock.Net.NUnit * HttpContext * Add WebSockets (#1423) * Add WebSockets * Add tests * fix * more tests * Add tests * ... * remove IOwin * - * tests * fluent * ok * match * . * byte[] * x * func * func * byte * trans * ... * frameworks......... * jmes * xxx * sc * using var httpClient = new HttpClient(); * usings * maxRetries * up * xunit v3 * ct * --- * ct * ct2 * T Unit * WireMock.Net.TUnitTests / 10 * t unit first * --project * no tunit * t2 * --project * --project * ci - --project * publish ./test/wiremock-coverage.xml * windows * . * log * ... * log * goed * BodyType * . * . * --scenario * ... * pact * ct * . * WireMock.Net.RestClient.AwesomeAssertions (#1427) * WireMock.Net.RestClient.AwesomeAssertions * ok * atpath * fix test * sonar fixes * ports * proxy test * FIX? * --- * await Task.Delay(100, _ct); * ? * --project * Aspire: use IDistributedApplicationEventingSubscriber (#1428) * broadcast * ok * more tsts * . * Collection * up * . * 2 * remove nfluent * <VersionPrefix>2.0.0-preview-02</VersionPrefix> * ... * . * nuget icon * . * <PackageReference Include="JmesPath.Net" Version="1.1.0" /> * x * 500 * . * fix some warnings * ws
564 lines
20 KiB
C#
564 lines
20 KiB
C#
// Copyright © WireMock.Net
|
|
|
|
using System.Net.WebSockets;
|
|
using WireMock.Net.Xunit;
|
|
using WireMock.RequestBuilders;
|
|
using WireMock.ResponseBuilders;
|
|
using WireMock.Server;
|
|
using WireMock.Settings;
|
|
|
|
namespace WireMock.Net.Tests.WebSockets;
|
|
|
|
[Collection(nameof(WireMockServerWebSocketIntegrationTests))]
|
|
public class WireMockServerWebSocketIntegrationTests(ITestOutputHelper output, ITestContextAccessor testContext)
|
|
{
|
|
private readonly CancellationToken _ct = testContext.Current.CancellationToken;
|
|
|
|
[Fact]
|
|
public async Task GetWebSocketConnections_Should_Return_All_Active_Connections()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/test")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithEcho()
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
using var client3 = new ClientWebSocket();
|
|
|
|
var uri = new Uri($"{server.Url}/ws/test");
|
|
|
|
// Act
|
|
await client1.ConnectAsync(uri, _ct);
|
|
await client2.ConnectAsync(uri, _ct);
|
|
await client3.ConnectAsync(uri, _ct);
|
|
|
|
await Task.Delay(500, _ct);
|
|
|
|
// Assert
|
|
var connections = server.GetWebSocketConnections();
|
|
connections.Should().HaveCount(3);
|
|
connections.Should().AllSatisfy(c => c.Should().NotBeNull());
|
|
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client3.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetWebSocketConnections_Should_Return_Empty_When_No_Connections()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/test")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithEcho()
|
|
)
|
|
);
|
|
|
|
// Act
|
|
var connections = server.GetWebSocketConnections();
|
|
|
|
// Assert
|
|
connections.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetWebSocketConnections_Should_Return_Connections_For_Specific_Mapping()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
var mapping1Guid = Guid.NewGuid();
|
|
var mapping2Guid = Guid.NewGuid();
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/echo1")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.WithGuid(mapping1Guid)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithEcho()
|
|
)
|
|
);
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/echo2")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.WithGuid(mapping2Guid)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithEcho()
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
using var client3 = new ClientWebSocket();
|
|
|
|
var uri1 = new Uri($"{server.Url}/ws/echo1");
|
|
var uri2 = new Uri($"{server.Url}/ws/echo2");
|
|
|
|
// Act
|
|
await client1.ConnectAsync(uri1, _ct);
|
|
await client2.ConnectAsync(uri1, _ct);
|
|
await client3.ConnectAsync(uri2, _ct);
|
|
|
|
await Task.Delay(500, _ct);
|
|
|
|
// Assert
|
|
var allConnections = server.GetWebSocketConnections();
|
|
allConnections.Should().HaveCount(3);
|
|
|
|
var mapping1Connections = server.GetWebSocketConnections(mapping1Guid);
|
|
mapping1Connections.Should().HaveCount(2);
|
|
|
|
var mapping2Connections = server.GetWebSocketConnections(mapping2Guid);
|
|
mapping2Connections.Should().HaveCount(1);
|
|
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client3.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AbortWebSocketConnectionAsync_Should_Close_Specific_Connection()
|
|
{
|
|
// Arrange
|
|
var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/test")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(30))
|
|
.WithEcho()
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
|
|
var uri = new Uri($"{server.Url}/ws/test");
|
|
|
|
await client1.ConnectAsync(uri, _ct);
|
|
await client2.ConnectAsync(uri, _ct);
|
|
|
|
await Task.Delay(500, _ct);
|
|
|
|
var connections = server.GetWebSocketConnections();
|
|
connections.Should().HaveCount(2);
|
|
|
|
var connectionIdToAbort = connections.First().ConnectionId;
|
|
|
|
// Act
|
|
await server.AbortWebSocketConnectionAsync(connectionIdToAbort, "Abort by test", _ct);
|
|
|
|
// Assert
|
|
var remainingConnections = server.GetWebSocketConnections();
|
|
remainingConnections.Should().HaveCount(1);
|
|
var remainingConnection = remainingConnections.First();
|
|
remainingConnection.ConnectionId.Should().NotBe(connectionIdToAbort);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BroadcastToWebSocketsAsync_Should_Broadcast_Text_To_Specific_Mapping()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
var broadcastMessage = "Server broadcast message";
|
|
var mappingGuid = Guid.NewGuid();
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/broadcast")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.WithGuid(mappingGuid)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithMessageHandler(async (message, context) =>
|
|
{
|
|
if (message.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
var text = message.Text ?? string.Empty;
|
|
if (text.StartsWith("ready"))
|
|
{
|
|
await context.SendAsync("ready!");
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
|
|
var uri = new Uri($"{server.Url}/ws/broadcast");
|
|
|
|
await client1.ConnectAsync(uri, _ct);
|
|
await client2.ConnectAsync(uri, _ct);
|
|
|
|
// Signal ready
|
|
await client1.SendAsync("ready", cancellationToken: _ct);
|
|
await client2.SendAsync("ready", cancellationToken: _ct);
|
|
|
|
var text1 = await client1.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
var text2 = await client2.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
|
|
text1.Should().Be("ready!");
|
|
text2.Should().Be("ready!");
|
|
|
|
// Act
|
|
await server.BroadcastToWebSocketsAsync(mappingGuid, broadcastMessage, cancellationToken: _ct);
|
|
|
|
// Assert
|
|
var received1 = await client1.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
var received2 = await client2.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
|
|
received1.Should().Be(broadcastMessage);
|
|
received2.Should().Be(broadcastMessage);
|
|
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BroadcastToWebSocketsAsync_Should_Broadcast_Binary_To_Specific_Mapping()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
var broadcastData = new byte[] { 0x01, 0x02, 0x03, 0x04 };
|
|
var mappingGuid = Guid.NewGuid();
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/broadcast-binary")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.WithGuid(mappingGuid)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithMessageHandler(async (message, context) =>
|
|
{
|
|
if (message.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
var text = message.Text ?? string.Empty;
|
|
if (text.StartsWith("ready"))
|
|
{
|
|
await context.SendAsync("ready!");
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
|
|
var uri = new Uri($"{server.Url}/ws/broadcast-binary");
|
|
|
|
await client1.ConnectAsync(uri, _ct);
|
|
await client2.ConnectAsync(uri, _ct);
|
|
|
|
// Signal ready
|
|
await client1.SendAsync("ready", cancellationToken: _ct);
|
|
await client2.SendAsync("ready", cancellationToken: _ct);
|
|
|
|
var text1 = await client1.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
var text2 = await client2.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
|
|
text1.Should().Be("ready!");
|
|
text2.Should().Be("ready!");
|
|
|
|
// Act
|
|
await server.BroadcastToWebSocketsAsync(mappingGuid, broadcastData, cancellationToken: _ct);
|
|
|
|
// Assert
|
|
var received1 = await client1.ReceiveAsBytesAsync(cancellationToken: _ct);
|
|
var received2 = await client2.ReceiveAsBytesAsync(cancellationToken: _ct);
|
|
|
|
received1.Should().BeEquivalentTo(broadcastData);
|
|
received2.Should().BeEquivalentTo(broadcastData);
|
|
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BroadcastToAllWebSocketsAsync_Should_Broadcast_Text_To_All_Mappings()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
var broadcastMessage = "Broadcast to all mappings";
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/mapping1")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithMessageHandler(async (message, context) =>
|
|
{
|
|
if (message.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
var text = message.Text ?? string.Empty;
|
|
if (text.StartsWith("ready"))
|
|
{
|
|
await context.SendAsync("ready!");
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/mapping2")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithMessageHandler(async (message, context) =>
|
|
{
|
|
if (message.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
var text = message.Text ?? string.Empty;
|
|
if (text.StartsWith("ready"))
|
|
{
|
|
await context.SendAsync("ready!");
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
|
|
var uri1 = new Uri($"{server.Url}/ws/mapping1");
|
|
var uri2 = new Uri($"{server.Url}/ws/mapping2");
|
|
|
|
await client1.ConnectAsync(uri1, _ct);
|
|
await client2.ConnectAsync(uri2, _ct);
|
|
|
|
// Signal ready
|
|
await client1.SendAsync("ready", cancellationToken: _ct);
|
|
await client2.SendAsync("ready", cancellationToken: _ct);
|
|
|
|
var text1 = await client1.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
var text2 = await client2.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
|
|
text1.Should().Be("ready!");
|
|
text2.Should().Be("ready!");
|
|
|
|
// Act
|
|
await server.BroadcastToAllWebSocketsAsync(broadcastMessage, cancellationToken: _ct);
|
|
|
|
// Assert - both clients from different mappings should receive the broadcast
|
|
var received1 = await client1.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
var received2 = await client2.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
|
|
received1.Should().Be(broadcastMessage);
|
|
received2.Should().Be(broadcastMessage);
|
|
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BroadcastToAllWebSocketsAsync_Should_Broadcast_Binary_To_All_Mappings()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
var broadcastData = new byte[] { 0xAA, 0xBB, 0xCC };
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/mapping1")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithMessageHandler(async (message, context) =>
|
|
{
|
|
if (message.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
var text = message.Text ?? string.Empty;
|
|
if (text.StartsWith("ready"))
|
|
{
|
|
await context.SendAsync("ready!");
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/mapping2")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithMessageHandler(async (message, context) =>
|
|
{
|
|
if (message.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
var text = message.Text ?? string.Empty;
|
|
if (text.StartsWith("ready"))
|
|
{
|
|
await context.SendAsync("ready!");
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
|
|
var uri1 = new Uri($"{server.Url}/ws/mapping1");
|
|
var uri2 = new Uri($"{server.Url}/ws/mapping2");
|
|
|
|
await client1.ConnectAsync(uri1, _ct);
|
|
await client2.ConnectAsync(uri2, _ct);
|
|
|
|
// Signal ready
|
|
await client1.SendAsync("ready", cancellationToken: _ct);
|
|
await client2.SendAsync("ready", cancellationToken: _ct);
|
|
|
|
var text1 = await client1.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
var text2 = await client2.ReceiveAsTextAsync(cancellationToken: _ct);
|
|
|
|
text1.Should().Be("ready!");
|
|
text2.Should().Be("ready!");
|
|
|
|
// Act
|
|
await server.BroadcastToAllWebSocketsAsync(broadcastData, cancellationToken: _ct);
|
|
|
|
// Assert
|
|
var received1 = await client1.ReceiveAsBytesAsync(cancellationToken: _ct);
|
|
var received2 = await client2.ReceiveAsBytesAsync(cancellationToken: _ct);
|
|
|
|
received1.Should().BeEquivalentTo(broadcastData);
|
|
received2.Should().BeEquivalentTo(broadcastData);
|
|
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetWebSocketConnections_Should_Update_After_Client_Disconnect()
|
|
{
|
|
// Arrange
|
|
using var server = WireMockServer.Start(new WireMockServerSettings
|
|
{
|
|
Logger = new TestOutputHelperWireMockLogger(output),
|
|
Urls = ["ws://localhost:0"]
|
|
});
|
|
|
|
server
|
|
.Given(Request.Create()
|
|
.WithPath("/ws/test")
|
|
.WithWebSocketUpgrade()
|
|
)
|
|
.RespondWith(Response.Create()
|
|
.WithWebSocket(ws => ws
|
|
.WithCloseTimeout(TimeSpan.FromSeconds(5))
|
|
.WithEcho()
|
|
)
|
|
);
|
|
|
|
using var client1 = new ClientWebSocket();
|
|
using var client2 = new ClientWebSocket();
|
|
|
|
var uri = new Uri($"{server.Url}/ws/test");
|
|
|
|
await client1.ConnectAsync(uri, _ct);
|
|
await client2.ConnectAsync(uri, _ct);
|
|
|
|
await Task.Delay(500, _ct);
|
|
|
|
var initialConnections = server.GetWebSocketConnections();
|
|
initialConnections.Should().HaveCount(2);
|
|
|
|
// Act
|
|
await client1.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disconnect", _ct);
|
|
|
|
await Task.Delay(500, _ct);
|
|
|
|
// Assert
|
|
var remainingConnections = server.GetWebSocketConnections();
|
|
remainingConnections.Should().HaveCount(1);
|
|
|
|
await client2.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", _ct);
|
|
}
|
|
} |