This commit is contained in:
Stef Heyenrath
2026-02-11 07:48:03 +01:00
parent c1cf61862e
commit 842a4e0aeb
7 changed files with 194 additions and 33 deletions

View File

@@ -1,6 +1,7 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Stef.Validation; using Stef.Validation;
using WireMock.Settings; using WireMock.Settings;
@@ -64,30 +65,40 @@ internal class WebSocketBuilder : IWebSocketBuilder
return this; return this;
} }
public IWebSocketBuilder WithText(string text) public IWebSocketBuilder WithMessage(Action<IWebSocketMessageBuilder> configure)
{ {
Guard.NotNull(text); Guard.NotNull(configure);
var messageBuilder = new WebSocketMessageBuilder();
configure(messageBuilder);
return WithMessageHandler(async (message, context) => return WithMessageHandler(async (message, context) =>
{ {
await context.SendAsync(text); if (messageBuilder.Delay.HasValue)
{
await Task.Delay(messageBuilder.Delay.Value);
}
await SendMessageAsync(context, messageBuilder);
}); });
} }
public IWebSocketBuilder WithBytes(byte[] bytes) public IWebSocketBuilder WithMessages(Action<IWebSocketMessagesBuilder> configure)
{ {
Guard.NotNull(bytes); Guard.NotNull(configure);
return WithMessageHandler(async (message, context) => var messagesBuilder = new WebSocketMessagesBuilder();
{ configure(messagesBuilder);
await context.SendAsync(bytes);
});
}
public IWebSocketBuilder WithJson(object data)
{
Guard.NotNull(data);
return WithMessageHandler(async (message, context) => return WithMessageHandler(async (message, context) =>
{ {
await context.SendAsJsonAsync(data); foreach (var messageBuilder in messagesBuilder.Messages)
{
if (messageBuilder.Delay.HasValue)
{
await Task.Delay(messageBuilder.Delay.Value);
}
await SendMessageAsync(context, messageBuilder);
}
}); });
} }
@@ -155,4 +166,20 @@ internal class WebSocketBuilder : IWebSocketBuilder
TransformerReplaceNodeOptions = transformerReplaceNodeOptions; TransformerReplaceNodeOptions = transformerReplaceNodeOptions;
return this; return this;
} }
private static async Task SendMessageAsync(IWebSocketContext context, WebSocketMessageBuilder messageBuilder)
{
switch (messageBuilder.Type)
{
case WebSocketMessageBuilder.MessageType.Text:
await context.SendAsync(messageBuilder.MessageText!);
break;
case WebSocketMessageBuilder.MessageType.Bytes:
await context.SendAsync(messageBuilder.MessageBytes!);
break;
case WebSocketMessageBuilder.MessageType.Json:
await context.SendAsJsonAsync(messageBuilder.MessageData!);
break;
}
}
} }

View File

@@ -0,0 +1,59 @@
// Copyright © WireMock.Net
using Stef.Validation;
namespace WireMock.WebSockets;
internal class WebSocketMessageBuilder : IWebSocketMessageBuilder
{
public string? MessageText { get; private set; }
public byte[]? MessageBytes { get; private set; }
public object? MessageData { get; private set; }
public TimeSpan? Delay { get; private set; }
public MessageType Type { get; private set; }
public IWebSocketMessageBuilder WithText(string text)
{
MessageText = Guard.NotNull(text);
Type = MessageType.Text;
return this;
}
public IWebSocketMessageBuilder WithBytes(byte[] bytes)
{
MessageBytes = Guard.NotNull(bytes);
Type = MessageType.Bytes;
return this;
}
public IWebSocketMessageBuilder WithJson(object data)
{
MessageData = Guard.NotNull(data);
Type = MessageType.Json;
return this;
}
public IWebSocketMessageBuilder WithDelay(TimeSpan delay)
{
Delay = delay;
return this;
}
public IWebSocketMessageBuilder WithDelay(int delayInMilliseconds)
{
Guard.Condition(delayInMilliseconds, d => d >= 0, nameof(delayInMilliseconds));
Delay = TimeSpan.FromMilliseconds(delayInMilliseconds);
return this;
}
internal enum MessageType
{
Text,
Bytes,
Json
}
}

View File

@@ -0,0 +1,18 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
namespace WireMock.WebSockets;
internal class WebSocketMessagesBuilder : IWebSocketMessagesBuilder
{
internal List<WebSocketMessageBuilder> Messages { get; } = new();
public IWebSocketMessagesBuilder AddMessage(Action<IWebSocketMessageBuilder> configure)
{
var messageBuilder = new WebSocketMessageBuilder();
configure(messageBuilder);
Messages.Add(messageBuilder);
return this;
}
}

View File

@@ -24,25 +24,18 @@ public interface IWebSocketBuilder
IWebSocketBuilder WithEcho(); IWebSocketBuilder WithEcho();
/// <summary> /// <summary>
/// Send a specific text message in response to any received message /// Configure and send a single message in response to any received message
/// </summary> /// </summary>
/// <param name="text">The text message to send</param> /// <param name="configure">Action to configure the message</param>
[PublicAPI] [PublicAPI]
IWebSocketBuilder WithText(string text); IWebSocketBuilder WithMessage(Action<IWebSocketMessageBuilder> configure);
/// <summary> /// <summary>
/// Send specific binary data in response to any received message /// Configure and send multiple messages in response to any received message
/// </summary> /// </summary>
/// <param name="bytes">The binary data to send</param> /// <param name="configure">Action to configure the messages</param>
[PublicAPI] [PublicAPI]
IWebSocketBuilder WithBytes(byte[] bytes); IWebSocketBuilder WithMessages(Action<IWebSocketMessagesBuilder> configure);
/// <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> /// <summary>
/// Handle incoming WebSocket messages /// Handle incoming WebSocket messages

View File

@@ -0,0 +1,46 @@
// Copyright © WireMock.Net
using JetBrains.Annotations;
namespace WireMock.WebSockets;
/// <summary>
/// WebSocket Message Builder interface for building individual messages with optional delays
/// </summary>
public interface IWebSocketMessageBuilder
{
/// <summary>
/// Send a specific text message
/// </summary>
/// <param name="text">The text message to send</param>
[PublicAPI]
IWebSocketMessageBuilder WithText(string text);
/// <summary>
/// Send specific binary data
/// </summary>
/// <param name="bytes">The binary data to send</param>
[PublicAPI]
IWebSocketMessageBuilder WithBytes(byte[] bytes);
/// <summary>
/// Send a JSON object
/// </summary>
/// <param name="data">The object to serialize and send as JSON</param>
[PublicAPI]
IWebSocketMessageBuilder WithJson(object data);
/// <summary>
/// Set a delay before sending the message (using TimeSpan)
/// </summary>
/// <param name="delay">The delay before sending the message</param>
[PublicAPI]
IWebSocketMessageBuilder WithDelay(TimeSpan delay);
/// <summary>
/// Set a delay before sending the message (using milliseconds)
/// </summary>
/// <param name="delayInMilliseconds">The delay in milliseconds before sending the message</param>
[PublicAPI]
IWebSocketMessageBuilder WithDelay(int delayInMilliseconds);
}

View File

@@ -0,0 +1,18 @@
// Copyright © WireMock.Net
using JetBrains.Annotations;
namespace WireMock.WebSockets;
/// <summary>
/// WebSocket Messages Builder interface for building multiple messages
/// </summary>
public interface IWebSocketMessagesBuilder
{
/// <summary>
/// Add a message to the sequence
/// </summary>
/// <param name="configure">Action to configure the message</param>
[PublicAPI]
IWebSocketMessagesBuilder AddMessage(Action<IWebSocketMessageBuilder> configure);
}

View File

@@ -72,7 +72,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
) )
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithWebSocket(ws => ws .WithWebSocket(ws => ws
.WithText(responseMessage) .WithMessage(m => m.WithText(responseMessage))
) )
); );
@@ -117,7 +117,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
) )
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithWebSocket(ws => ws .WithWebSocket(ws => ws
.WithText(responseMessage) .WithMessage(m => m.WithText(responseMessage))
) )
); );
@@ -161,7 +161,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
) )
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithWebSocket(ws => ws .WithWebSocket(ws => ws
.WithBytes(responseBytes) .WithMessage(m => m.WithBytes(responseBytes))
) )
); );
@@ -207,7 +207,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
) )
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithWebSocket(ws => ws .WithWebSocket(ws => ws
.WithBytes(responseBytes) .WithMessage(m => m.WithBytes(responseBytes))
) )
); );
@@ -258,7 +258,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
) )
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithWebSocket(ws => ws .WithWebSocket(ws => ws
.WithJson(responseData) .WithMessage(m => m.WithJson(responseData))
) )
); );
@@ -311,7 +311,7 @@ public class WebSocketIntegrationTests(ITestOutputHelper output)
) )
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithWebSocket(ws => ws .WithWebSocket(ws => ws
.WithJson(responseData) .WithMessage(m => m.WithJson(responseData))
) )
); );