From 77138350d286d8b9616c5ebd86df7010b56fd6e0 Mon Sep 17 00:00:00 2001 From: antyadev Date: Tue, 16 Jan 2024 11:04:49 +0200 Subject: [PATCH] added WebSockets example --- examples/Demo/Demo.csproj | 6 +- .../ClientPool/ClientPoolMqttExample.cs | 2 +- .../{Features => MQTT}/ClientPool/config.json | 0 .../ClientPool/docker-compose.yaml | 0 examples/Demo/MQTT/docker-compose.yaml | 4 +- examples/Demo/Program.cs | 6 ++ .../Demo/WebSockets/PingPongWebSocketsTest.cs | 57 ++++++++++++++++++ .../Controllers/WebSocketController.cs | 58 +++++++++++++++++++ examples/WebAppSimulator/Program.cs | 10 +++- .../WebAppSimulator/WebAppSimulator.csproj | 1 + examples/WebAppSimulator/appsettings.json | 2 +- 11 files changed, 135 insertions(+), 11 deletions(-) rename examples/Demo/{Features => MQTT}/ClientPool/ClientPoolMqttExample.cs (98%) rename examples/Demo/{Features => MQTT}/ClientPool/config.json (100%) rename examples/Demo/{Features => MQTT}/ClientPool/docker-compose.yaml (100%) create mode 100644 examples/Demo/WebSockets/PingPongWebSocketsTest.cs create mode 100644 examples/WebAppSimulator/Controllers/WebSocketController.cs diff --git a/examples/Demo/Demo.csproj b/examples/Demo/Demo.csproj index 5a0e63a6..bafbd5ad 100644 --- a/examples/Demo/Demo.csproj +++ b/examples/Demo/Demo.csproj @@ -39,12 +39,13 @@ - + + @@ -70,9 +71,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/examples/Demo/Features/ClientPool/ClientPoolMqttExample.cs b/examples/Demo/MQTT/ClientPool/ClientPoolMqttExample.cs similarity index 98% rename from examples/Demo/Features/ClientPool/ClientPoolMqttExample.cs rename to examples/Demo/MQTT/ClientPool/ClientPoolMqttExample.cs index 81e242b1..80cbfcc9 100644 --- a/examples/Demo/Features/ClientPool/ClientPoolMqttExample.cs +++ b/examples/Demo/MQTT/ClientPool/ClientPoolMqttExample.cs @@ -102,7 +102,7 @@ public void Run() NBomberRunner .RegisterScenarios(scenario) - .LoadConfig("./Features/ClientPool/config.json") + .LoadConfig("./MQTT/ClientPool/config.json") .Run(); } diff --git a/examples/Demo/Features/ClientPool/config.json b/examples/Demo/MQTT/ClientPool/config.json similarity index 100% rename from examples/Demo/Features/ClientPool/config.json rename to examples/Demo/MQTT/ClientPool/config.json diff --git a/examples/Demo/Features/ClientPool/docker-compose.yaml b/examples/Demo/MQTT/ClientPool/docker-compose.yaml similarity index 100% rename from examples/Demo/Features/ClientPool/docker-compose.yaml rename to examples/Demo/MQTT/ClientPool/docker-compose.yaml diff --git a/examples/Demo/MQTT/docker-compose.yaml b/examples/Demo/MQTT/docker-compose.yaml index 3b741cf4..67b51966 100644 --- a/examples/Demo/MQTT/docker-compose.yaml +++ b/examples/Demo/MQTT/docker-compose.yaml @@ -1,8 +1,8 @@ version: '3.4' services: - + emqx: - image: "emqx/emqx:4.2.0" + image: "emqx/emqx:5.0.12" ports: - "1883:1883" - "18083:18083" diff --git a/examples/Demo/Program.cs b/examples/Demo/Program.cs index 6a0e8ff4..8533e02d 100644 --- a/examples/Demo/Program.cs +++ b/examples/Demo/Program.cs @@ -17,6 +17,7 @@ using Demo.MQTT; using Demo.HTTP.WebAppSimulator; using Demo.HTTP.SimpleBookstore; +using Demo.WebSockets; // ------------------------------- // ----- Hello World examples ----- @@ -73,6 +74,11 @@ // new WebAppSimulatorExample().RunHttpUserExample(); // new ExampleSimpleBookstore().Run(); +// ---------------- +// ----- WebSockets ----- +// ---------------- +// new PingPongWebSocketsTest().Run(); + // ---------------- // ----- MQTT ----- // ---------------- diff --git a/examples/Demo/WebSockets/PingPongWebSocketsTest.cs b/examples/Demo/WebSockets/PingPongWebSocketsTest.cs new file mode 100644 index 00000000..b1d3edd0 --- /dev/null +++ b/examples/Demo/WebSockets/PingPongWebSocketsTest.cs @@ -0,0 +1,57 @@ +using NBomber.CSharp; +using NBomber.Data; +using NBomber.WebSockets; + +namespace Demo.WebSockets; + +public class PingPongWebSocketsTest +{ + // To run this example you need to spin up local server examples/simulators/WebAppSimulator + // The server should run on localhost:5233, you should run http profile that configured in WebAppSimulator/Properties/launchSettings.json + + public void Run() + { + var payload = Data.GenerateRandomBytes(1_000_000); // 1MB + + var scenario = Scenario.Create("ping_pong_websockets", async ctx => + { + using var websocket = new WebSocket(new WebSocketConfig()); + + var connect = await Step.Run("connect", ctx, async () => + { + await websocket.Connect("ws://localhost:5233/ws"); + return Response.Ok(); + }); + + var ping = await Step.Run("ping", ctx, async () => + { + await websocket.Send(payload); + return Response.Ok(sizeBytes: payload.Length); + }); + + var pong = await Step.Run("pong", ctx, async () => + { + using var response = await websocket.Receive(); + // var str = Encoding.UTF8.GetString(response.Data.Span); + // var user = JsonSerializer.Deserialize(response.Data.Span); + return Response.Ok(sizeBytes: response.Data.Length); + }); + + var disconnect = await Step.Run("disconnect", ctx, async () => + { + await websocket.Close(); + return Response.Ok(); + }); + + return Response.Ok(); + }) + .WithoutWarmUp() + .WithLoadSimulations( + Simulation.KeepConstant(10, TimeSpan.FromSeconds(30)) + ); + + NBomberRunner + .RegisterScenarios(scenario) + .Run(); + } +} diff --git a/examples/WebAppSimulator/Controllers/WebSocketController.cs b/examples/WebAppSimulator/Controllers/WebSocketController.cs new file mode 100644 index 00000000..f267f03a --- /dev/null +++ b/examples/WebAppSimulator/Controllers/WebSocketController.cs @@ -0,0 +1,58 @@ +using System.Net.WebSockets; +using Microsoft.AspNetCore.Mvc; +using Microsoft.IO; + +namespace WebAppSimulator.Controllers; + +public class WebSocketController : ControllerBase +{ + private static readonly RecyclableMemoryStreamManager MsStreamManager = new(); + private const int BufferSize = 1024 * 16; + + [Route("/ws")] + public async Task Get() + { + if (HttpContext.WebSockets.IsWebSocketRequest) + { + using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); + using var ms = MsStreamManager.GetStream(); + + await Receive(webSocket, ms); + await Send(webSocket, ms); + + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); + } + else + { + HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; + } + } + + private async Task Receive(WebSocket webSocket, RecyclableMemoryStream ms) + { + var endOfMessage = false; + + while (!endOfMessage) + { + var buffer = ms.GetMemory(BufferSize); + var message = await webSocket.ReceiveAsync(buffer, CancellationToken.None); + + if (message.MessageType == WebSocketMessageType.Close) + { + break; + } + + ms.Advance(message.Count); + endOfMessage = message.EndOfMessage; + } + } + + private async Task Send(WebSocket webSocket, RecyclableMemoryStream ms) + { + if (ms.Length > 0) + { + var msg = ms.GetBuffer().AsMemory(0, (int) ms.Length); + await webSocket.SendAsync(msg, WebSocketMessageType.Binary, WebSocketMessageFlags.EndOfMessage, CancellationToken.None); + } + } +} diff --git a/examples/WebAppSimulator/Program.cs b/examples/WebAppSimulator/Program.cs index fa84ddae..ba2f1b22 100644 --- a/examples/WebAppSimulator/Program.cs +++ b/examples/WebAppSimulator/Program.cs @@ -1,3 +1,6 @@ +using System.Buffers; +using System.IO.Pipelines; +using System.Text; using WebAppSimulator.Infra.DAL; namespace WebAppSimulator @@ -6,11 +9,13 @@ public class SQLiteSettings { public string ConnectionString { get; set; } } + public class RedisSettings { public string ConnectionString { get; set; } public string ServerName { get; set; } } + public class Program { public static void Main(string[] args) @@ -37,8 +42,6 @@ public static void Main(string[] args) var rep = new RedisRepository(settings); builder.Services.AddSingleton(rep); } - else - throw new Exception("The base for the test is not specified in the file appsettings.json"); var app = builder.Build(); @@ -46,7 +49,6 @@ public static void Main(string[] args) { app.UseExceptionHandler("/Error"); } - app.UseHttpsRedirection(); if (app.Environment.IsDevelopment()) { @@ -63,12 +65,14 @@ public static void Main(string[] args) app.UseSwaggerUI(); } + // app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.MapControllers(); + app.UseWebSockets(); app.Run(); } diff --git a/examples/WebAppSimulator/WebAppSimulator.csproj b/examples/WebAppSimulator/WebAppSimulator.csproj index 6b14407e..aaf2b573 100644 --- a/examples/WebAppSimulator/WebAppSimulator.csproj +++ b/examples/WebAppSimulator/WebAppSimulator.csproj @@ -17,6 +17,7 @@ + diff --git a/examples/WebAppSimulator/appsettings.json b/examples/WebAppSimulator/appsettings.json index ef91bd46..7ed338c2 100644 --- a/examples/WebAppSimulator/appsettings.json +++ b/examples/WebAppSimulator/appsettings.json @@ -7,7 +7,7 @@ }, "AllowedHosts": "*", - "DbUse": "SQLite", + "DbUse": "none", "SQLiteSettings": { "ConnectionString": "Data Source=DB/UsersDB.db"