This commit is contained in:
Stef Heyenrath
2026-02-10 19:11:14 +01:00
parent ceab19514f
commit c1cf61862e
11 changed files with 125735 additions and 76 deletions
@@ -136,34 +136,34 @@ public static class Program
// Handle different commands
if (text.StartsWith("/help"))
{
await context.SendTextAsync("Available commands: /help, /time, /echo <text>, /upper <text>, /reverse <text>");
await context.SendAsync("Available commands: /help, /time, /echo <text>, /upper <text>, /reverse <text>");
}
else if (text.StartsWith("/time"))
{
await context.SendTextAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
await context.SendAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
}
else if (text.StartsWith("/echo "))
{
await context.SendTextAsync(text.Substring(6));
await context.SendAsync(text.Substring(6));
}
else if (text.StartsWith("/upper "))
{
await context.SendTextAsync(text.Substring(7).ToUpper());
await context.SendAsync(text.Substring(7).ToUpper());
}
else if (text.StartsWith("/reverse "))
{
var toReverse = text.Substring(9);
var reversed = new string(toReverse.Reverse().ToArray());
await context.SendTextAsync(reversed);
await context.SendAsync(reversed);
}
else if (text == "/quit")
{
await context.SendTextAsync("Goodbye!");
await context.SendAsync("Goodbye!");
await context.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client requested disconnect");
}
else
{
await context.SendTextAsync($"Unknown command: {text}. Type /help for available commands.");
await context.SendAsync($"Unknown command: {text}. Type /help for available commands.");
}
}
})
@@ -263,7 +263,7 @@ public static class Program
.WithWebSocket(ws => ws
.WithMessageHandler(async (msg, ctx) =>
{
await ctx.SendTextAsync("Welcome to the game lobby! Type 'ready' to start or 'quit' to leave.");
await ctx.SendAsync("Welcome to the game lobby! Type 'ready' to start or 'quit' to leave.");
})
)
);
@@ -285,16 +285,16 @@ public static class Program
if (text == "ready")
{
ctx.SetScenarioState("Playing");
await ctx.SendTextAsync("Game started! Type 'attack' to attack, 'defend' to defend, or 'quit' to exit.");
await ctx.SendAsync("Game started! Type 'attack' to attack, 'defend' to defend, or 'quit' to exit.");
}
else if (text == "quit")
{
await ctx.SendTextAsync("You left the lobby. Goodbye!");
await ctx.SendAsync("You left the lobby. Goodbye!");
await ctx.CloseAsync(WebSocketCloseStatus.NormalClosure, "Player quit");
}
else
{
await ctx.SendTextAsync("In lobby. Type 'ready' to start or 'quit' to leave.");
await ctx.SendAsync("In lobby. Type 'ready' to start or 'quit' to leave.");
}
})
)
@@ -316,21 +316,21 @@ public static class Program
if (text == "attack")
{
await ctx.SendTextAsync("You attacked! Critical hit! 💥");
await ctx.SendAsync("You attacked! Critical hit! 💥");
}
else if (text == "defend")
{
await ctx.SendTextAsync("You defended! Shield up! 🛡️");
await ctx.SendAsync("You defended! Shield up! 🛡️");
}
else if (text == "quit")
{
ctx.SetScenarioState("GameOver");
await ctx.SendTextAsync("Game over! Thanks for playing.");
await ctx.SendAsync("Game over! Thanks for playing.");
await ctx.CloseAsync(WebSocketCloseStatus.NormalClosure, "Game ended");
}
else
{
await ctx.SendTextAsync("Unknown action. Type 'attack', 'defend', or 'quit'.");
await ctx.SendAsync("Unknown action. Type 'attack', 'defend', or 'quit'.");
}
})
)
@@ -418,7 +418,7 @@ public static class Program
.WithWebSocket(ws => ws
.WithMessageHandler(async (msg, ctx) =>
{
await ctx.SendTextAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
await ctx.SendAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
})
)
);
@@ -440,7 +440,7 @@ public static class Program
length = msg.Text?.Length ?? 0,
type = msg.MessageType.ToString()
};
await ctx.SendJsonAsync(response);
await ctx.SendAsJsonAsync(response);
})
)
);
@@ -456,7 +456,7 @@ public static class Program
.WithAcceptProtocol("chat")
.WithMessageHandler(async (msg, ctx) =>
{
await ctx.SendTextAsync($"Using protocol: chat. Message: {msg.Text}");
await ctx.SendAsync($"Using protocol: chat. Message: {msg.Text}");
})
)
);
@@ -546,7 +546,7 @@ public static class Program
{
if (message.MessageType == WebSocketMessageType.Text)
{
await context.SendTextAsync($"Echo: {message.Text}");
await context.SendAsync($"Echo: {message.Text}");
}
})
)
@@ -586,7 +586,7 @@ public static class Program
.WithWebSocket(ws => ws
.WithMessageHandler(async (msg, ctx) =>
{
await ctx.SendTextAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
await ctx.SendAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
})
)
);
@@ -607,7 +607,7 @@ public static class Program
message = msg.Text,
connectionId = ctx.ConnectionId
};
await ctx.SendJsonAsync(response);
await ctx.SendAsJsonAsync(response);
})
)
);
@@ -626,7 +626,7 @@ public static class Program
.WithWebSocket(ws => ws
.WithMessageHandler(async (msg, ctx) =>
{
await ctx.SendTextAsync("Welcome! Type 'ready' to start.");
await ctx.SendAsync("Welcome! Type 'ready' to start.");
})
)
);
@@ -645,7 +645,7 @@ public static class Program
if (msg.Text?.ToLower() == "ready")
{
ctx.SetScenarioState("Playing");
await ctx.SendTextAsync("Game started!");
await ctx.SendAsync("Game started!");
}
})
)
@@ -64,6 +64,33 @@ internal class WebSocketBuilder : IWebSocketBuilder
return this;
}
public IWebSocketBuilder WithText(string text)
{
Guard.NotNull(text);
return WithMessageHandler(async (message, context) =>
{
await context.SendAsync(text);
});
}
public IWebSocketBuilder WithBytes(byte[] bytes)
{
Guard.NotNull(bytes);
return WithMessageHandler(async (message, context) =>
{
await context.SendAsync(bytes);
});
}
public IWebSocketBuilder WithJson(object data)
{
Guard.NotNull(data);
return WithMessageHandler(async (message, context) =>
{
await context.SendAsJsonAsync(data);
});
}
public IWebSocketBuilder WithMessageHandler(Func<WebSocketMessage, IWebSocketContext, Task> handler)
{
MessageHandler = Guard.NotNull(handler);
@@ -53,7 +53,7 @@ internal class WebSocketConnectionRegistry
{
var tasks = _connections.Values
.Where(c => c.WebSocket.State == WebSocketState.Open)
.Select(c => c.SendTextAsync(text, cancellationToken));
.Select(c => c.SendAsync(text, cancellationToken));
await Task.WhenAll(tasks);
}
@@ -1,10 +1,7 @@
// Copyright © WireMock.Net
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Stef.Validation;
@@ -68,7 +65,7 @@ public class WireMockWebSocketContext : IWebSocketContext
}
/// <inheritdoc />
public Task SendTextAsync(string text, CancellationToken cancellationToken = default)
public Task SendAsync(string text, CancellationToken cancellationToken = default)
{
var bytes = Encoding.UTF8.GetBytes(text);
return WebSocket.SendAsync(
@@ -80,7 +77,7 @@ public class WireMockWebSocketContext : IWebSocketContext
}
/// <inheritdoc />
public Task SendBytesAsync(byte[] bytes, CancellationToken cancellationToken = default)
public Task SendAsync(byte[] bytes, CancellationToken cancellationToken = default)
{
return WebSocket.SendAsync(
new ArraySegment<byte>(bytes),
@@ -91,10 +88,10 @@ public class WireMockWebSocketContext : IWebSocketContext
}
/// <inheritdoc />
public Task SendJsonAsync(object data, CancellationToken cancellationToken = default)
public Task SendAsJsonAsync(object data, CancellationToken cancellationToken = default)
{
var json = JsonConvert.SerializeObject(data);
return SendTextAsync(json, cancellationToken);
return SendAsync(json, cancellationToken);
}
/// <inheritdoc />
@@ -124,7 +121,7 @@ public class WireMockWebSocketContext : IWebSocketContext
scenarioState.NextState = nextState;
scenarioState.Started = true;
scenarioState.Finished = nextState == null;
// Reset counter when manually setting state
scenarioState.Counter = 0;
}
@@ -23,6 +23,27 @@ public interface IWebSocketBuilder
[PublicAPI]
IWebSocketBuilder WithEcho();
/// <summary>
/// Send a specific text message in response to any received message
/// </summary>
/// <param name="text">The text message to send</param>
[PublicAPI]
IWebSocketBuilder WithText(string text);
/// <summary>
/// Send specific binary data in response to any received message
/// </summary>
/// <param name="bytes">The binary data to send</param>
[PublicAPI]
IWebSocketBuilder WithBytes(byte[] bytes);
/// <summary>
/// Send a JSON object in response to any received message
/// </summary>
/// <param name="data">The object to serialize and send as JSON</param>
[PublicAPI]
IWebSocketBuilder WithJson(object data);
/// <summary>
/// Handle incoming WebSocket messages
/// </summary>
@@ -41,17 +41,17 @@ public interface IWebSocketContext
/// <summary>
/// Send text message to the client
/// </summary>
Task SendTextAsync(string text, CancellationToken cancellationToken = default);
Task SendAsync(string text, CancellationToken cancellationToken = default);
/// <summary>
/// Send binary message to the client
/// </summary>
Task SendBytesAsync(byte[] bytes, CancellationToken cancellationToken = default);
Task SendAsync(byte[] bytes, CancellationToken cancellationToken = default);
/// <summary>
/// Send JSON message to the client
/// </summary>
Task SendJsonAsync(object data, CancellationToken cancellationToken = default);
Task SendAsJsonAsync(object data, CancellationToken cancellationToken = default);
/// <summary>
/// Close the WebSocket connection
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,32 @@
// Copyright © WireMock.Net
using System.Net.WebSockets;
using System.Text;
namespace WireMock.Net.Tests.WebSockets;
internal static class ClientWebSocketExtensions
{
internal static Task SendAsync(this ClientWebSocket client, string text, bool endOfMessage = true, CancellationToken cancellationToken = default)
{
return client.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(text)), WebSocketMessageType.Text, endOfMessage, cancellationToken);
}
internal static async Task<string> ReceiveAsTextAsync(this ClientWebSocket client, CancellationToken cancellationToken = default)
{
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), cancellationToken);
if (result.MessageType != WebSocketMessageType.Text)
{
throw new InvalidOperationException($"Expected a text message but received a {result.MessageType} message.");
}
if (!result.EndOfMessage)
{
throw new InvalidOperationException("Received message is too large for the buffer. Consider increasing the buffer size.");
}
return Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
}
}
@@ -44,8 +44,47 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
client.State.Should().Be(WebSocketState.Open);
var testMessage = "Hello, WebSocket!";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(testMessage);
// Assert
var received = await client.ReceiveAsTextAsync();
received.Should().Be(testMessage);
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
[Fact]
public async Task WithText_Should_Send_Configured_Text()
{
// Arrange
using var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new TestOutputHelperWireMockLogger(output),
Urls = ["ws://localhost:0"]
});
var responseMessage = "This is a predefined response";
server
.Given(Request.Create()
.WithPath("/ws/message")
.WithWebSocketUpgrade()
)
.RespondWith(Response.Create()
.WithWebSocket(ws => ws
.WithText(responseMessage)
)
);
using var client = new ClientWebSocket();
var uri = new Uri($"{server.Url!}/ws/message");
// Act
await client.ConnectAsync(uri, CancellationToken.None);
client.State.Should().Be(WebSocketState.Open);
var testMessage = "Any message from client";
await client.SendAsync(testMessage);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -54,7 +93,247 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
result.MessageType.Should().Be(WebSocketMessageType.Text);
result.EndOfMessage.Should().BeTrue();
var received = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
received.Should().Be(testMessage);
received.Should().Be(responseMessage);
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
[Fact]
public async Task WithText_Should_Send_Same_Text_For_Multiple_Messages()
{
// Arrange
using var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new TestOutputHelperWireMockLogger(output),
Urls = ["ws://localhost:0"]
});
var responseMessage = "Fixed response";
server
.Given(Request.Create()
.WithPath("/ws/message")
.WithWebSocketUpgrade()
)
.RespondWith(Response.Create()
.WithWebSocket(ws => ws
.WithText(responseMessage)
)
);
using var client = new ClientWebSocket();
var uri = new Uri($"{server.Url!}/ws/message");
await client.ConnectAsync(uri, CancellationToken.None);
var testMessages = new[] { "First", "Second", "Third" };
// Act & Assert
foreach (var testMessage in testMessages)
{
await client.SendAsync(testMessage);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
var received = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
received.Should().Be(responseMessage, $"should always return the fixed response regardless of input message '{testMessage}'");
}
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
[Fact]
public async Task WithBytes_Should_Send_Configured_Bytes()
{
// Arrange
using var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new TestOutputHelperWireMockLogger(output),
Urls = ["ws://localhost:0"]
});
var responseBytes = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF };
server
.Given(Request.Create()
.WithPath("/ws/binary")
.WithWebSocketUpgrade()
)
.RespondWith(Response.Create()
.WithWebSocket(ws => ws
.WithBytes(responseBytes)
)
);
using var client = new ClientWebSocket();
var uri = new Uri($"{server.Url!}/ws/binary");
// Act
await client.ConnectAsync(uri, CancellationToken.None);
client.State.Should().Be(WebSocketState.Open);
var testMessage = "Any message from client";
await client.SendAsync(testMessage);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
// Assert
result.MessageType.Should().Be(WebSocketMessageType.Binary);
result.EndOfMessage.Should().BeTrue();
var receivedData = new byte[result.Count];
Array.Copy(receiveBuffer, receivedData, result.Count);
receivedData.Should().BeEquivalentTo(responseBytes);
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
[Fact]
public async Task WithBytes_Should_Send_Same_Bytes_For_Multiple_Messages()
{
// Arrange
using var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new TestOutputHelperWireMockLogger(output),
Urls = ["ws://localhost:0"]
});
var responseBytes = new byte[] { 0x01, 0x02, 0x03 };
server
.Given(Request.Create()
.WithPath("/ws/binary")
.WithWebSocketUpgrade()
)
.RespondWith(Response.Create()
.WithWebSocket(ws => ws
.WithBytes(responseBytes)
)
);
using var client = new ClientWebSocket();
var uri = new Uri($"{server.Url!}/ws/binary");
await client.ConnectAsync(uri, CancellationToken.None);
var testMessages = new[] { "First", "Second", "Third" };
// Act & Assert
foreach (var testMessage in testMessages)
{
await client.SendAsync(testMessage);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
result.MessageType.Should().Be(WebSocketMessageType.Binary);
var receivedData = new byte[result.Count];
Array.Copy(receiveBuffer, receivedData, result.Count);
receivedData.Should().BeEquivalentTo(responseBytes, $"should always return the fixed bytes regardless of input message '{testMessage}'");
}
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
[Fact]
public async Task WithJson_Should_Send_Configured_Json()
{
// Arrange
using var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new TestOutputHelperWireMockLogger(output),
Urls = ["ws://localhost:0"]
});
var responseData = new
{
status = "ok",
message = "This is a predefined JSON response",
timestamp = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Utc)
};
server
.Given(Request.Create()
.WithPath("/ws/json")
.WithWebSocketUpgrade()
)
.RespondWith(Response.Create()
.WithWebSocket(ws => ws
.WithJson(responseData)
)
);
using var client = new ClientWebSocket();
var uri = new Uri($"{server.Url!}/ws/json");
// Act
await client.ConnectAsync(uri, CancellationToken.None);
client.State.Should().Be(WebSocketState.Open);
var testMessage = "Any message from client";
await client.SendAsync(testMessage);
var receiveBuffer = new byte[2048];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
// Assert
result.MessageType.Should().Be(WebSocketMessageType.Text);
result.EndOfMessage.Should().BeTrue();
var received = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
var json = JObject.Parse(received);
json["status"]!.ToString().Should().Be("ok");
json["message"]!.ToString().Should().Be("This is a predefined JSON response");
json["timestamp"].Should().NotBeNull();
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
[Fact]
public async Task WithJson_Should_Send_Same_Json_For_Multiple_Messages()
{
// Arrange
using var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new TestOutputHelperWireMockLogger(output),
Urls = ["ws://localhost:0"]
});
var responseData = new
{
id = 42,
name = "Fixed JSON Response"
};
server
.Given(Request.Create()
.WithPath("/ws/json")
.WithWebSocketUpgrade()
)
.RespondWith(Response.Create()
.WithWebSocket(ws => ws
.WithJson(responseData)
)
);
using var client = new ClientWebSocket();
var uri = new Uri($"{server.Url!}/ws/json");
await client.ConnectAsync(uri, CancellationToken.None);
var testMessages = new[] { "First", "Second", "Third" };
// Act & Assert
foreach (var testMessage in testMessages)
{
await client.SendAsync(testMessage);
var receiveBuffer = new byte[2048];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
var received = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
var json = JObject.Parse(received);
json["id"]!.Value<int>().Should().Be(42);
json["name"]!.ToString().Should().Be("Fixed JSON Response", $"should always return the fixed JSON regardless of input message '{testMessage}'");
}
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
@@ -87,8 +366,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act & Assert
foreach (var testMessage in testMessages)
{
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(testMessage);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -164,8 +442,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
await client.ConnectAsync(uri, CancellationToken.None);
// Act
var sendBytes = Encoding.UTF8.GetBytes(string.Empty);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(string.Empty);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -201,7 +478,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
if (text.StartsWith("/help"))
{
await context.SendTextAsync("Available commands: /help, /time, /echo <text>, /upper <text>, /reverse <text>");
await context.SendAsync("Available commands: /help, /time, /echo <text>, /upper <text>, /reverse <text>");
}
}
})
@@ -213,8 +490,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
await client.ConnectAsync(uri, CancellationToken.None);
// Act
var sendBytes = Encoding.UTF8.GetBytes("/help");
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync("/help");
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -254,25 +530,29 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
if (text.StartsWith("/help"))
{
await context.SendTextAsync("Available commands: /help, /time, /echo <text>, /upper <text>, /reverse <text>");
await context.SendAsync("Available commands: /help, /time, /echo <text>, /upper <text>, /reverse <text>");
}
else if (text.StartsWith("/time"))
{
await context.SendTextAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
await context.SendAsync($"Server time: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
}
else if (text.StartsWith("/echo "))
{
await context.SendTextAsync(text.Substring(6));
await context.SendAsync(text.Substring(6));
}
else if (text.StartsWith("/upper "))
{
await context.SendTextAsync(text.Substring(7).ToUpper());
await context.SendAsync(text.Substring(7).ToUpper());
}
else if (text.StartsWith("/reverse "))
{
var toReverse = text.Substring(9);
var reversed = new string(toReverse.Reverse().ToArray());
await context.SendTextAsync(reversed);
await context.SendAsync(reversed);
}
else if (text.StartsWith("/close"))
{
await context.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing connection");
}
}
})
@@ -285,18 +565,17 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
var commands = new (string, Action<string>)[]
{
("/help", (string response) => response.Should().Contain("Available commands")),
("/time", (string response) => response.Should().Contain("Server time")),
("/echo Test", (string response) => response.Should().Be("Test")),
("/upper test", (string response) => response.Should().Be("TEST")),
("/reverse hello", (string response) => response.Should().Be("olleh"))
("/help", response => response.Should().Contain("Available commands")),
("/time", response => response.Should().Contain("Server time")),
("/echo Test", response => response.Should().Be("Test")),
("/upper test", response => response.Should().Be("TEST")),
("/reverse hello", response => response.Should().Be("olleh"))
};
// Act & Assert
foreach (var (command, assertion) in commands)
{
var sendBytes = Encoding.UTF8.GetBytes(command);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(command);
var receiveBuffer = new byte[1024];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -305,6 +584,8 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
assertion(received);
}
await client.SendAsync("/close");
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test complete", CancellationToken.None);
}
@@ -335,7 +616,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
length = msg.Text?.Length ?? 0,
type = msg.MessageType.ToString()
};
await ctx.SendJsonAsync(response);
await ctx.SendAsJsonAsync(response);
})
)
);
@@ -346,8 +627,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act
var testMessage = "Test JSON message";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(testMessage);
var receiveBuffer = new byte[2048];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -392,7 +672,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
type = msg.MessageType.ToString(),
connectionId = ctx.ConnectionId.ToString()
};
await ctx.SendJsonAsync(response);
await ctx.SendAsJsonAsync(response);
})
)
);
@@ -406,8 +686,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act & Assert
foreach (var testMessage in testMessages)
{
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(testMessage);
var receiveBuffer = new byte[2048];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -459,7 +738,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
new { id = 2, name = "Item2" }
}
};
await ctx.SendJsonAsync(response);
await ctx.SendAsJsonAsync(response);
})
)
);
@@ -470,8 +749,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act
var testMessage = "Complex test";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client.SendAsync(testMessage);
var receiveBuffer = new byte[2048];
var result = await client.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
@@ -540,8 +818,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act - Send message from client1
var testMessage = "Hello everyone!";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client1.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client1.SendAsync(testMessage);
// Assert - All clients should receive the broadcast
var receiveBuffer1 = new byte[1024];
@@ -616,8 +893,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act - Send message from client1 (client2 is now closed)
var testMessage = "Still here";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client1.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client1.SendAsync(testMessage);
// Assert - Only client1 should receive
var receiveBuffer1 = new byte[1024];
@@ -680,8 +956,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act - Send message from client1
var testMessage = "JSON broadcast test";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await client1.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client1.SendAsync(testMessage);
// Assert - Both clients should receive JSON
var receiveBuffer1 = new byte[2048];
@@ -757,8 +1032,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act & Assert
foreach (var msg in messages)
{
var sendBytes = Encoding.UTF8.GetBytes(msg);
await client1.SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await client1.SendAsync(msg);
var receiveBuffer1 = new byte[1024];
var result1 = await client1.ReceiveAsync(new ArraySegment<byte>(receiveBuffer1), CancellationToken.None);
@@ -826,8 +1100,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
// Act - Send message from first client
var testMessage = "Mass broadcast";
var sendBytes = Encoding.UTF8.GetBytes(testMessage);
await clients[0].SendAsync(new ArraySegment<byte>(sendBytes), WebSocketMessageType.Text, true, CancellationToken.None);
await clients[0].SendAsync(testMessage);
// Assert - All clients should receive
var receiveTasks = clients.Select(async client =>
File diff suppressed because it is too large Load Diff