mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-23 01:50:36 +01:00
BodyType
This commit is contained in:
@@ -50,5 +50,20 @@ public enum BodyType
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use Server-Sent Events (string)
|
/// Use Server-Sent Events (string)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SseString
|
SseString,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WebSocket message in clear text.
|
||||||
|
/// </summary>
|
||||||
|
WebSocketText,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WebSocket message in binary format.
|
||||||
|
/// </summary>
|
||||||
|
WebSocketBinary,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WebSocket close message.
|
||||||
|
/// </summary>
|
||||||
|
WebSocketClose
|
||||||
}
|
}
|
||||||
@@ -2,21 +2,14 @@
|
|||||||
|
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using WireMock.Constants;
|
using WireMock.Constants;
|
||||||
using WireMock.Logging;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Matchers.Request;
|
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.Owin;
|
using WireMock.Owin;
|
||||||
using WireMock.Owin.ActivityTracing;
|
using WireMock.Owin.ActivityTracing;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Types;
|
|
||||||
using WireMock.Util;
|
|
||||||
using WireMock.WebSockets;
|
using WireMock.WebSockets;
|
||||||
|
|
||||||
namespace WireMock.ResponseProviders;
|
namespace WireMock.ResponseProviders;
|
||||||
@@ -175,7 +168,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogWebSocketMessage(context, WebSocketMessageDirection.Receive, result.MessageType, null, receiveActivity);
|
context.LogWebSocketMessage(WebSocketMessageDirection.Receive, result.MessageType, null, receiveActivity);
|
||||||
|
|
||||||
await context.CloseAsync(
|
await context.CloseAsync(
|
||||||
WebSocketCloseStatus.NormalClosure,
|
WebSocketCloseStatus.NormalClosure,
|
||||||
@@ -204,7 +197,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log the receive operation
|
// Log the receive operation
|
||||||
LogWebSocketMessage(context, WebSocketMessageDirection.Receive, result.MessageType, textContent, receiveActivity);
|
context.LogWebSocketMessage(WebSocketMessageDirection.Receive, result.MessageType, textContent, receiveActivity);
|
||||||
|
|
||||||
// Echo back (this will be logged by context.SendAsync)
|
// Echo back (this will be logged by context.SendAsync)
|
||||||
await context.WebSocket.SendAsync(
|
await context.WebSocket.SendAsync(
|
||||||
@@ -276,7 +269,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogWebSocketMessage(context, WebSocketMessageDirection.Receive, result.MessageType, null, receiveActivity);
|
context.LogWebSocketMessage(WebSocketMessageDirection.Receive, result.MessageType, null, receiveActivity);
|
||||||
|
|
||||||
await context.CloseAsync(
|
await context.CloseAsync(
|
||||||
WebSocketCloseStatus.NormalClosure,
|
WebSocketCloseStatus.NormalClosure,
|
||||||
@@ -302,7 +295,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
|
|
||||||
// Log the receive operation
|
// Log the receive operation
|
||||||
object? data = message.Text != null ? message.Text : message.Bytes;
|
object? data = message.Text != null ? message.Text : message.Bytes;
|
||||||
LogWebSocketMessage(context, WebSocketMessageDirection.Receive, result.MessageType, data, receiveActivity);
|
context.LogWebSocketMessage(WebSocketMessageDirection.Receive, result.MessageType, data, receiveActivity);
|
||||||
|
|
||||||
// Call custom handler
|
// Call custom handler
|
||||||
await handler(message, context).ConfigureAwait(false);
|
await handler(message, context).ConfigureAwait(false);
|
||||||
@@ -396,7 +389,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogWebSocketMessage(context, direction, result.MessageType, null, activity);
|
context.LogWebSocketMessage(direction, result.MessageType, null, activity);
|
||||||
|
|
||||||
await destination.CloseAsync(
|
await destination.CloseAsync(
|
||||||
result.CloseStatus ?? WebSocketCloseStatus.NormalClosure,
|
result.CloseStatus ?? WebSocketCloseStatus.NormalClosure,
|
||||||
@@ -431,7 +424,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log the proxy operation
|
// Log the proxy operation
|
||||||
LogWebSocketMessage(context, direction, result.MessageType, data, activity);
|
context.LogWebSocketMessage(direction, result.MessageType, data, activity);
|
||||||
|
|
||||||
await destination.SendAsync(
|
await destination.SendAsync(
|
||||||
new ArraySegment<byte>(buffer, 0, result.Count),
|
new ArraySegment<byte>(buffer, 0, result.Count),
|
||||||
@@ -501,7 +494,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
Array.Copy(buffer, (byte[])data, result.Count);
|
Array.Copy(buffer, (byte[])data, result.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogWebSocketMessage(context, WebSocketMessageDirection.Receive, result.MessageType, data, receiveActivity);
|
context.LogWebSocketMessage(WebSocketMessageDirection.Receive, result.MessageType, data, receiveActivity);
|
||||||
|
|
||||||
if (result.MessageType == WebSocketMessageType.Close)
|
if (result.MessageType == WebSocketMessageType.Close)
|
||||||
{
|
{
|
||||||
@@ -529,101 +522,6 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder) : IResponsePr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LogWebSocketMessage(
|
|
||||||
WireMockWebSocketContext context,
|
|
||||||
WebSocketMessageDirection direction,
|
|
||||||
WebSocketMessageType messageType,
|
|
||||||
object? data,
|
|
||||||
Activity? activity)
|
|
||||||
{
|
|
||||||
// Skip logging if log count limit is disabled
|
|
||||||
if (context.Options.MaxRequestLogCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create body data
|
|
||||||
IBodyData bodyData;
|
|
||||||
if (messageType == WebSocketMessageType.Text && data is string textContent)
|
|
||||||
{
|
|
||||||
bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = textContent,
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (messageType == WebSocketMessageType.Binary && data is byte[] binary)
|
|
||||||
{
|
|
||||||
bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsBytes = binary,
|
|
||||||
DetectedBodyType = BodyType.Bytes
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = messageType.ToString(),
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a pseudo-request or pseudo-response depending on direction
|
|
||||||
RequestMessage? requestMessage = null;
|
|
||||||
IResponseMessage? responseMessage = null;
|
|
||||||
|
|
||||||
var method = $"WS_{direction.ToString().ToUpperInvariant()}";
|
|
||||||
|
|
||||||
if (direction == WebSocketMessageDirection.Receive)
|
|
||||||
{
|
|
||||||
// Received message - log as request
|
|
||||||
requestMessage = new RequestMessage(
|
|
||||||
new UrlDetails(context.RequestMessage.Url),
|
|
||||||
method,
|
|
||||||
context.RequestMessage.ClientIP,
|
|
||||||
bodyData,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DateTime = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Sent message - log as response
|
|
||||||
responseMessage = new ResponseMessage
|
|
||||||
{
|
|
||||||
Method = method,
|
|
||||||
StatusCode = HttpStatusCode.SwitchingProtocols, // WebSocket status
|
|
||||||
BodyData = bodyData,
|
|
||||||
DateTime = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create log entry
|
|
||||||
var logEntry = new LogEntry
|
|
||||||
{
|
|
||||||
Guid = Guid.NewGuid(),
|
|
||||||
RequestMessage = requestMessage,
|
|
||||||
ResponseMessage = responseMessage,
|
|
||||||
MappingGuid = context.Mapping.Guid,
|
|
||||||
MappingTitle = context.Mapping.Title
|
|
||||||
};
|
|
||||||
|
|
||||||
// Enrich activity if present
|
|
||||||
if (activity != null && context.Options.ActivityTracingOptions != null)
|
|
||||||
{
|
|
||||||
WireMockActivitySource.EnrichWithLogEntry(activity, logEntry, context.Options.ActivityTracingOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log using LogLogEntry
|
|
||||||
context.Logger.LogLogEntry(logEntry, context.Options.MaxRequestLogCount is null or > 0);
|
|
||||||
|
|
||||||
activity?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static WebSocketMessage CreateWebSocketMessage(WebSocketReceiveResult result, byte[] buffer)
|
private static WebSocketMessage CreateWebSocketMessage(WebSocketReceiveResult result, byte[] buffer)
|
||||||
{
|
{
|
||||||
var message = new WebSocketMessage
|
var message = new WebSocketMessage
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ internal class LogEntryMapper(IWireMockMiddlewareOptions options)
|
|||||||
{
|
{
|
||||||
case BodyType.String:
|
case BodyType.String:
|
||||||
case BodyType.FormUrlEncoded:
|
case BodyType.FormUrlEncoded:
|
||||||
|
case BodyType.WebSocketText:
|
||||||
|
case BodyType.WebSocketClose:
|
||||||
logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString;
|
logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -51,6 +53,7 @@ internal class LogEntryMapper(IWireMockMiddlewareOptions options)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BodyType.Bytes:
|
case BodyType.Bytes:
|
||||||
|
case BodyType.WebSocketBinary:
|
||||||
logRequestModel.BodyAsBytes = logEntry.RequestMessage.BodyData.BodyAsBytes;
|
logRequestModel.BodyAsBytes = logEntry.RequestMessage.BodyData.BodyAsBytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -126,6 +129,8 @@ internal class LogEntryMapper(IWireMockMiddlewareOptions options)
|
|||||||
{
|
{
|
||||||
case BodyType.String:
|
case BodyType.String:
|
||||||
case BodyType.FormUrlEncoded:
|
case BodyType.FormUrlEncoded:
|
||||||
|
case BodyType.WebSocketText:
|
||||||
|
case BodyType.WebSocketClose:
|
||||||
if (!string.IsNullOrEmpty(logEntry.ResponseMessage.BodyData.IsFuncUsed) && options.DoNotSaveDynamicResponseInLogEntry == true)
|
if (!string.IsNullOrEmpty(logEntry.ResponseMessage.BodyData.IsFuncUsed) && options.DoNotSaveDynamicResponseInLogEntry == true)
|
||||||
{
|
{
|
||||||
logResponseModel.Body = logEntry.ResponseMessage.BodyData.IsFuncUsed;
|
logResponseModel.Body = logEntry.ResponseMessage.BodyData.IsFuncUsed;
|
||||||
@@ -141,6 +146,7 @@ internal class LogEntryMapper(IWireMockMiddlewareOptions options)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BodyType.Bytes:
|
case BodyType.Bytes:
|
||||||
|
case BodyType.WebSocketBinary:
|
||||||
logResponseModel.BodyAsBytes = logEntry.ResponseMessage.BodyData.BodyAsBytes;
|
logResponseModel.BodyAsBytes = logEntry.ResponseMessage.BodyData.BodyAsBytes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ using System.Text;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Matchers.Request;
|
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Owin;
|
using WireMock.Owin;
|
||||||
using WireMock.Owin.ActivityTracing;
|
using WireMock.Owin.ActivityTracing;
|
||||||
@@ -93,51 +91,97 @@ public class WireMockWebSocketContext : IWebSocketContext
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendAsyncInternal(
|
/// <inheritdoc />
|
||||||
ArraySegment<byte> buffer,
|
public async Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription)
|
||||||
WebSocketMessageType messageType,
|
|
||||||
bool endOfMessage,
|
|
||||||
object? data,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
Activity? activity = null;
|
await WebSocket.CloseAsync(closeStatus, statusDescription, CancellationToken.None);
|
||||||
var shouldTrace = Options.ActivityTracingOptions is not null;
|
|
||||||
|
|
||||||
if (shouldTrace)
|
LogWebSocketMessage(WebSocketMessageDirection.Send, WebSocketMessageType.Close, $"CloseStatus: {closeStatus}, Description: {statusDescription}", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SetScenarioState(string nextState)
|
||||||
|
{
|
||||||
|
SetScenarioState(nextState, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SetScenarioState(string nextState, string? description)
|
||||||
|
{
|
||||||
|
if (Mapping.Scenario == null)
|
||||||
{
|
{
|
||||||
activity = WireMockActivitySource.StartWebSocketMessageActivity(WebSocketMessageDirection.Send, Mapping.Guid);
|
return;
|
||||||
WireMockActivitySource.EnrichWithWebSocketMessage(
|
|
||||||
activity,
|
|
||||||
messageType,
|
|
||||||
buffer.Count,
|
|
||||||
endOfMessage,
|
|
||||||
data as string,
|
|
||||||
Options.ActivityTracingOptions
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
// Use the same logic as WireMockMiddleware
|
||||||
|
if (Options.Scenarios.TryGetValue(Mapping.Scenario, out var scenarioState))
|
||||||
{
|
{
|
||||||
await WebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken).ConfigureAwait(false);
|
// Directly set the next state (bypass counter logic for manual WebSocket state changes)
|
||||||
|
scenarioState.NextState = nextState;
|
||||||
|
scenarioState.Started = true;
|
||||||
|
scenarioState.Finished = nextState == null;
|
||||||
|
|
||||||
// Log the send operation
|
// Reset counter when manually setting state
|
||||||
if (Options.MaxRequestLogCount is null or > 0)
|
scenarioState.Counter = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create new scenario state if it doesn't exist
|
||||||
|
Options.Scenarios.TryAdd(Mapping.Scenario, new ScenarioState
|
||||||
{
|
{
|
||||||
LogWebSocketMessage(WebSocketMessageDirection.Send, messageType, data, activity);
|
Name = Mapping.Scenario,
|
||||||
}
|
NextState = nextState,
|
||||||
}
|
Started = true,
|
||||||
catch (Exception ex)
|
Finished = nextState == null,
|
||||||
{
|
Counter = 0
|
||||||
WireMockActivitySource.RecordException(activity, ex);
|
});
|
||||||
throw;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
activity?.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogWebSocketMessage(
|
/// <inheritdoc />
|
||||||
|
public async Task BroadcastTextAsync(string text, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (Registry != null)
|
||||||
|
{
|
||||||
|
await Registry.BroadcastTextAsync(text, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update scenario state following the same pattern as WireMockMiddleware.UpdateScenarioState
|
||||||
|
/// This is called automatically when the WebSocket connection is established.
|
||||||
|
/// </summary>
|
||||||
|
internal void UpdateScenarioState()
|
||||||
|
{
|
||||||
|
if (Mapping.Scenario == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure scenario exists
|
||||||
|
if (!Options.Scenarios.TryGetValue(Mapping.Scenario, out var scenario))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow exact same logic as WireMockMiddleware.UpdateScenarioState
|
||||||
|
// Increase the number of times this state has been executed
|
||||||
|
scenario.Counter++;
|
||||||
|
|
||||||
|
// Only if the number of times this state is executed equals the required StateTimes,
|
||||||
|
// proceed to next state and reset the counter to 0
|
||||||
|
if (scenario.Counter == (Mapping.TimesInSameState ?? 1))
|
||||||
|
{
|
||||||
|
scenario.NextState = Mapping.NextState;
|
||||||
|
scenario.Counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else just update Started and Finished
|
||||||
|
scenario.Started = true;
|
||||||
|
scenario.Finished = Mapping.NextState == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void LogWebSocketMessage(
|
||||||
WebSocketMessageDirection direction,
|
WebSocketMessageDirection direction,
|
||||||
WebSocketMessageType messageType,
|
WebSocketMessageType messageType,
|
||||||
object? data,
|
object? data,
|
||||||
@@ -150,7 +194,7 @@ public class WireMockWebSocketContext : IWebSocketContext
|
|||||||
bodyData = new BodyData
|
bodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsString = textContent,
|
BodyAsString = textContent,
|
||||||
DetectedBodyType = BodyType.String
|
DetectedBodyType = BodyType.WebSocketText
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (messageType == WebSocketMessageType.Binary && data is byte[] binary)
|
else if (messageType == WebSocketMessageType.Binary && data is byte[] binary)
|
||||||
@@ -158,7 +202,7 @@ public class WireMockWebSocketContext : IWebSocketContext
|
|||||||
bodyData = new BodyData
|
bodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsBytes = binary,
|
BodyAsBytes = binary,
|
||||||
DetectedBodyType = BodyType.Bytes
|
DetectedBodyType = BodyType.WebSocketBinary
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -166,7 +210,7 @@ public class WireMockWebSocketContext : IWebSocketContext
|
|||||||
bodyData = new BodyData
|
bodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsString = messageType.ToString(),
|
BodyAsString = messageType.ToString(),
|
||||||
DetectedBodyType = BodyType.String
|
DetectedBodyType = BodyType.WebSocketClose
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,93 +269,47 @@ public class WireMockWebSocketContext : IWebSocketContext
|
|||||||
activity?.Dispose();
|
activity?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
private async Task SendAsyncInternal(
|
||||||
public async Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription)
|
ArraySegment<byte> buffer,
|
||||||
|
WebSocketMessageType messageType,
|
||||||
|
bool endOfMessage,
|
||||||
|
object? data,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await WebSocket.CloseAsync(closeStatus, statusDescription, CancellationToken.None);
|
Activity? activity = null;
|
||||||
|
var shouldTrace = Options.ActivityTracingOptions is not null;
|
||||||
|
|
||||||
LogWebSocketMessage(WebSocketMessageDirection.Send, WebSocketMessageType.Close, $"CloseStatus: {closeStatus}, Description: {statusDescription}", null);
|
if (shouldTrace)
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void SetScenarioState(string nextState)
|
|
||||||
{
|
|
||||||
SetScenarioState(nextState, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void SetScenarioState(string nextState, string? description)
|
|
||||||
{
|
|
||||||
if (Mapping.Scenario == null)
|
|
||||||
{
|
{
|
||||||
return;
|
activity = WireMockActivitySource.StartWebSocketMessageActivity(WebSocketMessageDirection.Send, Mapping.Guid);
|
||||||
|
WireMockActivitySource.EnrichWithWebSocketMessage(
|
||||||
|
activity,
|
||||||
|
messageType,
|
||||||
|
buffer.Count,
|
||||||
|
endOfMessage,
|
||||||
|
data as string,
|
||||||
|
Options.ActivityTracingOptions
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the same logic as WireMockMiddleware
|
try
|
||||||
if (Options.Scenarios.TryGetValue(Mapping.Scenario, out var scenarioState))
|
|
||||||
{
|
{
|
||||||
// Directly set the next state (bypass counter logic for manual WebSocket state changes)
|
await WebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken).ConfigureAwait(false);
|
||||||
scenarioState.NextState = nextState;
|
|
||||||
scenarioState.Started = true;
|
|
||||||
scenarioState.Finished = nextState == null;
|
|
||||||
|
|
||||||
// Reset counter when manually setting state
|
// Log the send operation
|
||||||
scenarioState.Counter = 0;
|
if (Options.MaxRequestLogCount is null or > 0)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create new scenario state if it doesn't exist
|
|
||||||
Options.Scenarios.TryAdd(Mapping.Scenario, new ScenarioState
|
|
||||||
{
|
{
|
||||||
Name = Mapping.Scenario,
|
LogWebSocketMessage(WebSocketMessageDirection.Send, messageType, data, activity);
|
||||||
NextState = nextState,
|
}
|
||||||
Started = true,
|
|
||||||
Finished = nextState == null,
|
|
||||||
Counter = 0
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update scenario state following the same pattern as WireMockMiddleware.UpdateScenarioState
|
|
||||||
/// This is called automatically when the WebSocket connection is established.
|
|
||||||
/// </summary>
|
|
||||||
internal void UpdateScenarioState()
|
|
||||||
{
|
|
||||||
if (Mapping.Scenario == null)
|
|
||||||
{
|
{
|
||||||
return;
|
WireMockActivitySource.RecordException(activity, ex);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
// Ensure scenario exists
|
|
||||||
if (!Options.Scenarios.TryGetValue(Mapping.Scenario, out var scenario))
|
|
||||||
{
|
{
|
||||||
return;
|
activity?.Dispose();
|
||||||
}
|
|
||||||
|
|
||||||
// Follow exact same logic as WireMockMiddleware.UpdateScenarioState
|
|
||||||
// Increase the number of times this state has been executed
|
|
||||||
scenario.Counter++;
|
|
||||||
|
|
||||||
// Only if the number of times this state is executed equals the required StateTimes,
|
|
||||||
// proceed to next state and reset the counter to 0
|
|
||||||
if (scenario.Counter == (Mapping.TimesInSameState ?? 1))
|
|
||||||
{
|
|
||||||
scenario.NextState = Mapping.NextState;
|
|
||||||
scenario.Counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else just update Started and Finished
|
|
||||||
scenario.Started = true;
|
|
||||||
scenario.Finished = Mapping.NextState == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task BroadcastTextAsync(string text, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
if (Registry != null)
|
|
||||||
{
|
|
||||||
await Registry.BroadcastTextAsync(text, cancellationToken);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user