From 824134bc0f74aa861467f64e95051c4d57886f53 Mon Sep 17 00:00:00 2001 From: antyadev Date: Tue, 1 Nov 2022 15:32:13 +0200 Subject: [PATCH] - separated Response API for F# and C# - moved Response.API to NBomber project --- .../Features/CustomSettings/config.json | 4 +- .../CSharpDev/HelloWorld/EmptyScenario.cs | 1 - .../CSharpDev/HelloWorld/HelloWorldExample.cs | 3 +- .../CSharpDev/HelloWorld/ParallelScenarios.cs | 3 +- .../CSharpDev/HelloWorld/ScenarioWithInit.cs | 3 +- .../HelloWorld/ScenarioWithStepRetry.cs | 1 - .../CSharpDev/HelloWorld/ScenarioWithSteps.cs | 1 - .../HelloWorld/ScenarioWithTimeout.cs | 1 - examples/CSharpDev/Http/SimpleHttpTest.cs | 5 +- examples/CSharpDev/Mqtt/SimpleMqttTest.cs | 5 +- src/NBomber/Api/CSharp.fs | 88 +++++++++++++++++++ src/NBomber/Api/FSharp.fs | 36 ++++++++ src/NBomber/Contracts.fs | 28 ++++++ src/NBomber/Domain/Scenario.fs | 8 +- src/NBomber/Domain/Step.fs | 15 ++-- src/NBomber/NBomber.fsproj | 2 +- 16 files changed, 176 insertions(+), 28 deletions(-) diff --git a/examples/CSharpDev/Features/CustomSettings/config.json b/examples/CSharpDev/Features/CustomSettings/config.json index 6048793b..be61aaec 100644 --- a/examples/CSharpDev/Features/CustomSettings/config.json +++ b/examples/CSharpDev/Features/CustomSettings/config.json @@ -8,7 +8,7 @@ "ScenariosSettings": [ { "ScenarioName": "my_scenario", - "WarmUpDuration": "00:00:00", + "WarmUpDuration": "00:00:05", "LoadSimulationsSettings": [ { "RampConstant": [10, "00:00:05"] }, @@ -25,7 +25,7 @@ ], "ReportFileName": "my_report_name", - "ReportFolder": "./my_reports", + "ReportFolder": "./reports", "ReportFormats": [ "Html", "Md", "Txt", "Csv" ] } } diff --git a/examples/CSharpDev/HelloWorld/EmptyScenario.cs b/examples/CSharpDev/HelloWorld/EmptyScenario.cs index 1834f14b..33f75d90 100644 --- a/examples/CSharpDev/HelloWorld/EmptyScenario.cs +++ b/examples/CSharpDev/HelloWorld/EmptyScenario.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; diff --git a/examples/CSharpDev/HelloWorld/HelloWorldExample.cs b/examples/CSharpDev/HelloWorld/HelloWorldExample.cs index 07fa55c9..f933f025 100644 --- a/examples/CSharpDev/HelloWorld/HelloWorldExample.cs +++ b/examples/CSharpDev/HelloWorld/HelloWorldExample.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; @@ -16,7 +15,7 @@ public void Run() // NBomber will measure how much time it takes to execute your logic await Task.Delay(1000); - return Response.Ok(statusCode: "200", sizeBytes: 1000); + return Response.Ok(); }) .WithoutWarmUp() .WithLoadSimulations( diff --git a/examples/CSharpDev/HelloWorld/ParallelScenarios.cs b/examples/CSharpDev/HelloWorld/ParallelScenarios.cs index 8994be9f..be7c0e9a 100644 --- a/examples/CSharpDev/HelloWorld/ParallelScenarios.cs +++ b/examples/CSharpDev/HelloWorld/ParallelScenarios.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; @@ -12,7 +11,7 @@ public void Run() var scenario1 = Scenario.Create("scenario_1", async context => { await Task.Delay(1000); - return Response.Ok(statusCode: "300", sizeBytes: 1000); + return Response.Ok(statusCode: "200", sizeBytes: 1000); }) .WithoutWarmUp() .WithLoadSimulations( diff --git a/examples/CSharpDev/HelloWorld/ScenarioWithInit.cs b/examples/CSharpDev/HelloWorld/ScenarioWithInit.cs index 7dca26cf..2ca596b8 100644 --- a/examples/CSharpDev/HelloWorld/ScenarioWithInit.cs +++ b/examples/CSharpDev/HelloWorld/ScenarioWithInit.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; @@ -18,11 +17,13 @@ public void Run() .WithLoadSimulations(Simulation.KeepConstant(copies: 1, during: TimeSpan.FromSeconds(10))) .WithInit(context => { + // You can do here any initialization logic: populate the database, etc. context.Logger.Information("MY INIT"); return Task.CompletedTask; }) .WithClean(context => { + // You can do here any cleaning logic: clearing the database, etc. context.Logger.Information("MY CLEAN"); return Task.CompletedTask; }); diff --git a/examples/CSharpDev/HelloWorld/ScenarioWithStepRetry.cs b/examples/CSharpDev/HelloWorld/ScenarioWithStepRetry.cs index f3a7a3dd..167d2ef5 100644 --- a/examples/CSharpDev/HelloWorld/ScenarioWithStepRetry.cs +++ b/examples/CSharpDev/HelloWorld/ScenarioWithStepRetry.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; diff --git a/examples/CSharpDev/HelloWorld/ScenarioWithSteps.cs b/examples/CSharpDev/HelloWorld/ScenarioWithSteps.cs index 521ee487..fae5e1a2 100644 --- a/examples/CSharpDev/HelloWorld/ScenarioWithSteps.cs +++ b/examples/CSharpDev/HelloWorld/ScenarioWithSteps.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; diff --git a/examples/CSharpDev/HelloWorld/ScenarioWithTimeout.cs b/examples/CSharpDev/HelloWorld/ScenarioWithTimeout.cs index e2818f4d..6033d75d 100644 --- a/examples/CSharpDev/HelloWorld/ScenarioWithTimeout.cs +++ b/examples/CSharpDev/HelloWorld/ScenarioWithTimeout.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.HelloWorld; diff --git a/examples/CSharpDev/Http/SimpleHttpTest.cs b/examples/CSharpDev/Http/SimpleHttpTest.cs index 990588f8..5c4f8e4f 100644 --- a/examples/CSharpDev/Http/SimpleHttpTest.cs +++ b/examples/CSharpDev/Http/SimpleHttpTest.cs @@ -1,6 +1,5 @@ using System; using System.Net.Http; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.Http; @@ -15,8 +14,8 @@ public void Run() { var httpResponse = await httpClient.GetAsync("https://nbomber.com"); return httpResponse.IsSuccessStatusCode - ? Response.Ok() - : Response.Fail(); + ? Response.Ok(statusCode: httpResponse.StatusCode.ToString()) + : Response.Fail(statusCode: httpResponse.StatusCode.ToString()); }) .WithoutWarmUp() .WithLoadSimulations( diff --git a/examples/CSharpDev/Mqtt/SimpleMqttTest.cs b/examples/CSharpDev/Mqtt/SimpleMqttTest.cs index 80938295..d347d0b0 100644 --- a/examples/CSharpDev/Mqtt/SimpleMqttTest.cs +++ b/examples/CSharpDev/Mqtt/SimpleMqttTest.cs @@ -4,7 +4,6 @@ using MQTTnet.Client; using MQTTnet.Client.Connecting; using MQTTnet.Client.Options; -using NBomber.Contracts; using NBomber.CSharp; namespace CSharpDev.Mqtt; @@ -31,7 +30,9 @@ public void Run() return result.ResultCode == MqttClientConnectResultCode.Success ? Response.Ok() : Response.Fail( - $"MQTT connection code is: {result.ResultCode}, reason: {result.ReasonString}"); + statusCode: MqttClientConnectResultCode.Success.ToString(), + message: $"MQTT connection code is: {result.ResultCode}, reason: {result.ReasonString}" + ); }); var subscribe = await Step.Run("subscribe", ctx, async () => diff --git a/src/NBomber/Api/CSharp.fs b/src/NBomber/Api/CSharp.fs index 094051ab..9f117b41 100644 --- a/src/NBomber/Api/CSharp.fs +++ b/src/NBomber/Api/CSharp.fs @@ -11,6 +11,94 @@ open NBomber open NBomber.Contracts open NBomber.Contracts.Stats +type Response() = + + static let _okEmpty = { StatusCode = ""; IsError = false; SizeBytes = 0; Message = ""; LatencyMs = 0; Payload = None } + static let _failEmpty = { StatusCode = ""; IsError = true; SizeBytes = 0; Message = ""; LatencyMs = 0; Payload = None } + + static member Ok() = _okEmpty + static member Fail() = _failEmpty + + static member Ok( + [] statusCode: string, + [] sizeBytes: int, + [] message: string, + [] latencyMs: float) : Response = + + { StatusCode = statusCode + IsError = false + SizeBytes = sizeBytes + Message = if isNull message then String.Empty else message + LatencyMs = latencyMs + Payload = None } + + static member Ok<'T>( + [] statusCode: string, + [] sizeBytes: int, + [] message: string, + [] latencyMs: float) : Response<'T> = + + { StatusCode = statusCode + IsError = false + SizeBytes = sizeBytes + Message = if isNull message then String.Empty else message + LatencyMs = latencyMs + Payload = None } + + static member Ok<'T>( + payload: 'T, + [] statusCode: string, + [] sizeBytes: int, + [] message: string, + [] latencyMs: float) : Response<'T> = + + { StatusCode = statusCode + IsError = false + SizeBytes = sizeBytes + Message = if isNull message then String.Empty else message + LatencyMs = latencyMs + Payload = Some payload } + + static member Fail( + [] statusCode: string, + [] message: string, + [] sizeBytes: int, + [] latencyMs: float) : Response = + + { StatusCode = statusCode + IsError = true + SizeBytes = sizeBytes + Message = if isNull message then String.Empty else message + LatencyMs = latencyMs + Payload = None } + + static member Fail<'T>( + [] statusCode: string, + [] message: string, + [] sizeBytes: int, + [] latencyMs: float) : Response<'T> = + + { StatusCode = statusCode + IsError = true + SizeBytes = sizeBytes + Message = if isNull message then String.Empty else message + LatencyMs = latencyMs + Payload = None } + + static member Fail<'T>( + payload: 'T, + [] statusCode: string, + [] message: string, + [] sizeBytes: int, + [] latencyMs: float) : Response<'T> = + + { StatusCode = statusCode + IsError = true + SizeBytes = sizeBytes + Message = if isNull message then String.Empty else message + LatencyMs = latencyMs + Payload = Some payload } + /// Step represents a single user action like login, logout, etc. type Step = diff --git a/src/NBomber/Api/FSharp.fs b/src/NBomber/Api/FSharp.fs index 3279313d..ca28f912 100644 --- a/src/NBomber/Api/FSharp.fs +++ b/src/NBomber/Api/FSharp.fs @@ -20,6 +20,42 @@ open NBomber.Errors open NBomber.Domain.ScenarioContext open NBomber.DomainServices +type Response() = + + static let _okEmpty = { StatusCode = ""; IsError = false; SizeBytes = 0; Message = ""; LatencyMs = 0; Payload = None } + static let _failEmpty = { StatusCode = ""; IsError = true; SizeBytes = 0; Message = ""; LatencyMs = 0; Payload = None } + + static member ok () = _okEmpty + static member fail () = _failEmpty + + static member ok<'T>( + ?payload: 'T, + ?statusCode: string, + ?sizeBytes: int, + ?message: string, + ?latencyMs: float) = + + { StatusCode = statusCode |> Option.defaultValue "" + IsError = false + SizeBytes = sizeBytes |> Option.defaultValue 0 + Message = message |> Option.defaultValue "" + LatencyMs = latencyMs |> Option.defaultValue 0 + Payload = payload } + + static member fail<'T>( + ?statusCode: string, + ?message: string, + ?payload: 'T, + ?sizeBytes: int, + ?latencyMs: float) = + + { StatusCode = statusCode |> Option.defaultValue "" + IsError = true + SizeBytes = sizeBytes |> Option.defaultValue 0 + Message = message |> Option.defaultValue "" + LatencyMs = latencyMs |> Option.defaultValue 0 + Payload = payload } + /// Step represents a single user action like login, logout, etc. [] type Step = diff --git a/src/NBomber/Contracts.fs b/src/NBomber/Contracts.fs index 81cabecd..aa34863b 100644 --- a/src/NBomber/Contracts.fs +++ b/src/NBomber/Contracts.fs @@ -50,7 +50,9 @@ type NBomberContext = { namespace NBomber.Contracts.Internal +open System open CommandLine +open NBomber open NBomber.Configuration open NBomber.Contracts open NBomber.Contracts.Stats @@ -88,3 +90,29 @@ type SessionArgs = { member this.GetScenariosSettings() = this.NBomberConfig.GlobalSettings.Value.ScenariosSettings.Value member this.GetUseHintsAnalyzer() = this.NBomberConfig.GlobalSettings.Value.EnableHintsAnalyzer.Value + +module internal ResponseInternal = + + let emptyFail<'T> : Response<'T> = + { StatusCode = "" + IsError = true + SizeBytes = 0 + Message = String.Empty + LatencyMs = 0 + Payload = None } + + let failUnhandled<'T> (ex: Exception) : Response<'T> = + { StatusCode = Constants.UnhandledExceptionCode + IsError = true + SizeBytes = 0 + LatencyMs = 0 + Message = ex.Message + Payload = None } + + let failTimeout<'T> : Response<'T> = + { StatusCode = Constants.TimeoutStatusCode + IsError = true + SizeBytes = 0 + LatencyMs = 0 + Message = "operation timeout" + Payload = None } diff --git a/src/NBomber/Domain/Scenario.fs b/src/NBomber/Domain/Scenario.fs index a05f194d..f077f331 100644 --- a/src/NBomber/Domain/Scenario.fs +++ b/src/NBomber/Domain/Scenario.fs @@ -188,8 +188,8 @@ let measure (name: string) (ctx: ScenarioContext) (run: IScenarioContext -> Task let context = ctx :> IScenarioContext context.Logger.Fatal(ex, $"Operation timeout for Scenario : {0}", context.ScenarioInfo.ScenarioName) - let error = Response.fail(message = "operation timeout", statusCode = Constants.TimeoutStatusCode) - let result = { Name = name; ClientResponse = error; EndTimeMs = endTime; LatencyMs = latency } + let response = ResponseInternal.failTimeout + let result = { Name = name; ClientResponse = response; EndTimeMs = endTime; LatencyMs = latency } ctx.StatsActor.Publish(AddMeasurement result) | ex -> @@ -199,7 +199,7 @@ let measure (name: string) (ctx: ScenarioContext) (run: IScenarioContext -> Task let context = ctx :> IScenarioContext context.Logger.Fatal(ex, $"Unhandled exception for Scenario: {0}", context.ScenarioInfo.ScenarioName) - let error = Response.fail(ex, statusCode = Constants.UnhandledExceptionCode) - let result = { Name = name; ClientResponse = error; EndTimeMs = endTime; LatencyMs = latency } + let response = ResponseInternal.failUnhandled ex + let result = { Name = name; ClientResponse = response; EndTimeMs = endTime; LatencyMs = latency } ctx.StatsActor.Publish(AddMeasurement result) } diff --git a/src/NBomber/Domain/Step.fs b/src/NBomber/Domain/Step.fs index d03f899b..c419e1f2 100644 --- a/src/NBomber/Domain/Step.fs +++ b/src/NBomber/Domain/Step.fs @@ -3,7 +3,6 @@ module internal NBomber.Domain.Step open System open System.Threading.Tasks -open NBomber open NBomber.Contracts open NBomber.Contracts.Internal open NBomber.Domain.ScenarioContext @@ -27,10 +26,11 @@ let measure (name: string) (ctx: ScenarioContext) (run: unit -> Task IScenarioContext context.Logger.Fatal(ex, $"Operation timeout for Scenario: {0}, Step: {1}", context.ScenarioInfo.ScenarioName, name) - let error = Response.fail<'T>(message = "operation timeout", statusCode = Constants.TimeoutStatusCode) - let result = { Name = name; ClientResponse = error; EndTimeMs = endTime; LatencyMs = latency } + let response = ResponseInternal.failTimeout + let result = { Name = name; ClientResponse = response; EndTimeMs = endTime; LatencyMs = latency } + ctx.StatsActor.Publish(AddMeasurement result) - return error + return response | ex -> let endTime = ctx.Timer.Elapsed.TotalMilliseconds @@ -39,8 +39,9 @@ let measure (name: string) (ctx: ScenarioContext) (run: unit -> Task IScenarioContext context.Logger.Fatal(ex, $"Unhandled exception for Scenario: {0}, Step: {1}", context.ScenarioInfo.ScenarioName, name) - let error = Response.fail<'T>(ex, statusCode = Constants.UnhandledExceptionCode) - let result = { Name = name; ClientResponse = error; EndTimeMs = endTime; LatencyMs = latency } + let response = ResponseInternal.failUnhandled ex + let result = { Name = name; ClientResponse = response; EndTimeMs = endTime; LatencyMs = latency } + ctx.StatsActor.Publish(AddMeasurement result) - return error + return response } diff --git a/src/NBomber/NBomber.fsproj b/src/NBomber/NBomber.fsproj index 756e9661..fee65409 100644 --- a/src/NBomber/NBomber.fsproj +++ b/src/NBomber/NBomber.fsproj @@ -69,7 +69,7 @@ - +