From ccb100b001de34cf4adb162dada81035ba5b17ae Mon Sep 17 00:00:00 2001 From: antyadev Date: Mon, 9 Dec 2024 21:13:54 +0200 Subject: [PATCH] version 5.8.2 --- NBomber.sln | 14 - .../BookstoreSimulator.csproj | 5 +- .../Controllers/DatabasesController.cs | 4 +- .../Controllers/UsersController.cs | 6 +- .../Infra/DAL/UserRepository.cs | 2 +- .../BookstoreSimulator/Pages/Error.cshtml.cs | 6 +- examples/BookstoreSimulator/Program.cs | 8 +- examples/Demo/Demo.csproj | 12 +- .../WebAppSimulator/Pages/Error.cshtml.cs | 6 +- .../WebAppSimulator/WebAppSimulator.csproj | 2 +- examples/xUnitExample/xUnitExample.csproj | 4 +- src/NBomber/NBomber.fsproj | 2 + .../NBomber.IntegrationTests/AssemblyInfo.fs | 8 - .../NBomber.IntegrationTests/CliArgsTests.fs | 95 --- .../ConstantActorSchedulerTests.fs | 124 ---- .../Concurrency/OneTimeActorSchedulerTests.fs | 84 --- .../Concurrency/ScenarioSchedulerTests.fs | 223 ------ .../duplicate_scenarios_config.json | 14 - .../Configuration/infra_config.json | 14 - .../Configuration/missing_fields_config.json | 17 - .../scenario_init_only_config.json | 15 - .../Configuration/test_config.json | 37 - .../Configuration/test_config_2.json | 36 - .../ConfigurationTests.fs | 116 ---- .../DataFeed/DataFeedTests.fs | 271 -------- .../DataFeed/users-feed-data.csv | 6 - .../DataFeed/users-feed-data.json | 10 - .../ExtensionsTests.fs | 20 - .../HintsAnalyzerTests.fs | 129 ---- .../LoadSimulationTests.fs | 86 --- .../NBomber.IntegrationTests/LoggingTests.fs | 65 -- .../MetricsStatsActorTests.fs | 161 ----- .../NBomber.IntegrationTests.fsproj | 78 --- .../NBomberContextTests.fs | 271 -------- .../NBomberRunnerTests.fs | 43 -- .../Plugins/PluginTests.fs | 159 ----- .../Reporting/CSVReportingTests.fs | 78 --- .../Reporting/ReportingConfigurationTests.fs | 161 ----- .../Reporting/ReportingSinkTests.fs | 322 --------- .../ScenarioStatsActorTests.fs | 155 ----- .../ScenarioTests/EmptyScenarioTests.fs | 91 --- .../ScenarioTests/InitCleanStopTests.fs | 297 -------- .../ScenarioTests/ValidationTests.fs | 108 --- .../ScenarioTests/WarmUpTests.fs | 142 ---- .../StatisticsTests.fs | 654 ------------------ .../StepTests/BasicStepTests.fs | 477 ------------- tests/NBomber.IntegrationTests/TestHelper.fs | 178 ----- 47 files changed, 32 insertions(+), 4784 deletions(-) delete mode 100644 tests/NBomber.IntegrationTests/AssemblyInfo.fs delete mode 100644 tests/NBomber.IntegrationTests/CliArgsTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Concurrency/ConstantActorSchedulerTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Concurrency/OneTimeActorSchedulerTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Concurrency/ScenarioSchedulerTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Configuration/duplicate_scenarios_config.json delete mode 100644 tests/NBomber.IntegrationTests/Configuration/infra_config.json delete mode 100644 tests/NBomber.IntegrationTests/Configuration/missing_fields_config.json delete mode 100644 tests/NBomber.IntegrationTests/Configuration/scenario_init_only_config.json delete mode 100644 tests/NBomber.IntegrationTests/Configuration/test_config.json delete mode 100644 tests/NBomber.IntegrationTests/Configuration/test_config_2.json delete mode 100644 tests/NBomber.IntegrationTests/ConfigurationTests.fs delete mode 100644 tests/NBomber.IntegrationTests/DataFeed/DataFeedTests.fs delete mode 100644 tests/NBomber.IntegrationTests/DataFeed/users-feed-data.csv delete mode 100644 tests/NBomber.IntegrationTests/DataFeed/users-feed-data.json delete mode 100644 tests/NBomber.IntegrationTests/ExtensionsTests.fs delete mode 100644 tests/NBomber.IntegrationTests/HintsAnalyzerTests.fs delete mode 100644 tests/NBomber.IntegrationTests/LoadSimulationTests.fs delete mode 100644 tests/NBomber.IntegrationTests/LoggingTests.fs delete mode 100644 tests/NBomber.IntegrationTests/MetricsStatsActorTests.fs delete mode 100644 tests/NBomber.IntegrationTests/NBomber.IntegrationTests.fsproj delete mode 100644 tests/NBomber.IntegrationTests/NBomberContextTests.fs delete mode 100644 tests/NBomber.IntegrationTests/NBomberRunnerTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Plugins/PluginTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Reporting/CSVReportingTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Reporting/ReportingConfigurationTests.fs delete mode 100644 tests/NBomber.IntegrationTests/Reporting/ReportingSinkTests.fs delete mode 100644 tests/NBomber.IntegrationTests/ScenarioStatsActorTests.fs delete mode 100644 tests/NBomber.IntegrationTests/ScenarioTests/EmptyScenarioTests.fs delete mode 100644 tests/NBomber.IntegrationTests/ScenarioTests/InitCleanStopTests.fs delete mode 100644 tests/NBomber.IntegrationTests/ScenarioTests/ValidationTests.fs delete mode 100644 tests/NBomber.IntegrationTests/ScenarioTests/WarmUpTests.fs delete mode 100644 tests/NBomber.IntegrationTests/StatisticsTests.fs delete mode 100644 tests/NBomber.IntegrationTests/StepTests/BasicStepTests.fs delete mode 100644 tests/NBomber.IntegrationTests/TestHelper.fs diff --git a/NBomber.sln b/NBomber.sln index 5e06e854..83ebdee4 100644 --- a/NBomber.sln +++ b/NBomber.sln @@ -17,8 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "simulators", "simulators", EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NBomber", "src\NBomber\NBomber.fsproj", "{53904BB5-68B2-497A-93BD-46423FBD239C}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NBomber.IntegrationTests", "tests\NBomber.IntegrationTests\NBomber.IntegrationTests.fsproj", "{D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -89,18 +87,6 @@ Global {53904BB5-68B2-497A-93BD-46423FBD239C}.Release|x64.Build.0 = Release|Any CPU {53904BB5-68B2-497A-93BD-46423FBD239C}.Release|x86.ActiveCfg = Release|Any CPU {53904BB5-68B2-497A-93BD-46423FBD239C}.Release|x86.Build.0 = Release|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Debug|x64.ActiveCfg = Debug|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Debug|x64.Build.0 = Debug|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Debug|x86.ActiveCfg = Debug|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Debug|x86.Build.0 = Debug|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Release|Any CPU.Build.0 = Release|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Release|x64.ActiveCfg = Release|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Release|x64.Build.0 = Release|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Release|x86.ActiveCfg = Release|Any CPU - {D201E3A0-AE64-41AB-B9CB-3A06D0DEA88C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/BookstoreSimulator/BookstoreSimulator.csproj b/examples/BookstoreSimulator/BookstoreSimulator.csproj index 3b2f40d8..9efdc114 100644 --- a/examples/BookstoreSimulator/BookstoreSimulator.csproj +++ b/examples/BookstoreSimulator/BookstoreSimulator.csproj @@ -2,7 +2,7 @@ net8.0 - enable + disable enable @@ -12,6 +12,7 @@ + @@ -20,6 +21,8 @@ + + diff --git a/examples/BookstoreSimulator/Controllers/DatabasesController.cs b/examples/BookstoreSimulator/Controllers/DatabasesController.cs index 34fdf047..fe0ba182 100644 --- a/examples/BookstoreSimulator/Controllers/DatabasesController.cs +++ b/examples/BookstoreSimulator/Controllers/DatabasesController.cs @@ -17,10 +17,12 @@ public DatabasesController(DB db) [AllowAnonymous] [HttpPut] - public async Task PreparedDB() + public Task PreparedDB() { _db.CleanTables(); _db.CreateTables(); + + return Task.CompletedTask; } } } diff --git a/examples/BookstoreSimulator/Controllers/UsersController.cs b/examples/BookstoreSimulator/Controllers/UsersController.cs index bc66f62b..1885833c 100644 --- a/examples/BookstoreSimulator/Controllers/UsersController.cs +++ b/examples/BookstoreSimulator/Controllers/UsersController.cs @@ -17,7 +17,7 @@ public class UsersController : ControllerBase private readonly JwtSetings _jwtSetings; private readonly SingUpUserRequestValidator _singUpUserRequestValidator; private readonly LoginUserRequestValidator _loginUserRequestValidator; - + public UsersController (UserRepository rep, JwtSetings jwtSetings, SingUpUserRequestValidator singUpUserRequestValidator, @@ -87,9 +87,9 @@ public async Task Login([FromBody] LoginUserRequest request) [Route("logout")] [Authorize] [HttpPost] - public async Task Logout() + public Task Logout() { - return Results.Ok(); + return Task.FromResult(Results.Ok()); } } } diff --git a/examples/BookstoreSimulator/Infra/DAL/UserRepository.cs b/examples/BookstoreSimulator/Infra/DAL/UserRepository.cs index 40da0de1..2d6d4f03 100644 --- a/examples/BookstoreSimulator/Infra/DAL/UserRepository.cs +++ b/examples/BookstoreSimulator/Infra/DAL/UserRepository.cs @@ -94,7 +94,7 @@ public async Task InsertUser(UserDBRecord record) } } - public async Task TryFindUserLoginData(string email) + public async Task TryFindUserLoginData(string email) { try { diff --git a/examples/BookstoreSimulator/Pages/Error.cshtml.cs b/examples/BookstoreSimulator/Pages/Error.cshtml.cs index f55373bc..cd8404a7 100644 --- a/examples/BookstoreSimulator/Pages/Error.cshtml.cs +++ b/examples/BookstoreSimulator/Pages/Error.cshtml.cs @@ -8,9 +8,9 @@ namespace BookstoreSimulator.Pages [IgnoreAntiforgeryToken] public class ErrorModel : PageModel { - public string? RequestId { get; set; } + public string RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + public bool ShowRequestId => string.IsNullOrEmpty(RequestId); private readonly ILogger _logger; @@ -24,4 +24,4 @@ public void OnGet() RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; } } -} \ No newline at end of file +} diff --git a/examples/BookstoreSimulator/Program.cs b/examples/BookstoreSimulator/Program.cs index 94ffceb8..e6c5425b 100644 --- a/examples/BookstoreSimulator/Program.cs +++ b/examples/BookstoreSimulator/Program.cs @@ -89,11 +89,11 @@ public static void Main(string[] args) IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetings.Key)) }; }); - + var settings = builder.Configuration.GetSection("BookstoreSettings").Get(); builder.Services.AddSingleton(_ => new UserRepository(settings, logger)); - builder.Services.AddSingleton(_ => new BookRepository(settings, logger)); + builder.Services.AddSingleton(_ => new BookRepository(settings, logger)); builder.Services.AddSingleton(_ => new OrderRepository(settings, logger)); builder.Services.AddSingleton(_ => new DB(settings, logger)); builder.Services.AddSingleton(_ => new SingUpUserRequestValidator()); @@ -115,8 +115,8 @@ public static void Main(string[] args) { OnPrepareResponse = context => { - context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store"); - context.Context.Response.Headers.Add("Expires", "-1"); + context.Context.Response.Headers.Append("Cache-Control", "no-cache, no-store"); + context.Context.Response.Headers.Append("Expires", "-1"); } }); diff --git a/examples/Demo/Demo.csproj b/examples/Demo/Demo.csproj index 6311a970..d05f0c81 100644 --- a/examples/Demo/Demo.csproj +++ b/examples/Demo/Demo.csproj @@ -67,14 +67,14 @@ - + - - - - + + + + - + diff --git a/examples/WebAppSimulator/Pages/Error.cshtml.cs b/examples/WebAppSimulator/Pages/Error.cshtml.cs index d8f52777..111d8931 100644 --- a/examples/WebAppSimulator/Pages/Error.cshtml.cs +++ b/examples/WebAppSimulator/Pages/Error.cshtml.cs @@ -8,9 +8,9 @@ namespace WebAppSimulator.Pages [IgnoreAntiforgeryToken] public class ErrorModel : PageModel { - public string? RequestId { get; set; } + public string RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + public bool ShowRequestId => string.IsNullOrEmpty(RequestId); private readonly ILogger _logger; @@ -24,4 +24,4 @@ public void OnGet() RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; } } -} \ No newline at end of file +} diff --git a/examples/WebAppSimulator/WebAppSimulator.csproj b/examples/WebAppSimulator/WebAppSimulator.csproj index d83c94a7..9973f43d 100644 --- a/examples/WebAppSimulator/WebAppSimulator.csproj +++ b/examples/WebAppSimulator/WebAppSimulator.csproj @@ -2,7 +2,7 @@ net8.0 - enable + disable enable diff --git a/examples/xUnitExample/xUnitExample.csproj b/examples/xUnitExample/xUnitExample.csproj index 8aedcfd7..8f470a35 100644 --- a/examples/xUnitExample/xUnitExample.csproj +++ b/examples/xUnitExample/xUnitExample.csproj @@ -8,8 +8,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/NBomber/NBomber.fsproj b/src/NBomber/NBomber.fsproj index 0baa6ce8..4cd9cdc7 100644 --- a/src/NBomber/NBomber.fsproj +++ b/src/NBomber/NBomber.fsproj @@ -73,6 +73,7 @@ + @@ -85,6 +86,7 @@ + diff --git a/tests/NBomber.IntegrationTests/AssemblyInfo.fs b/tests/NBomber.IntegrationTests/AssemblyInfo.fs deleted file mode 100644 index f9e2bef7..00000000 --- a/tests/NBomber.IntegrationTests/AssemblyInfo.fs +++ /dev/null @@ -1,8 +0,0 @@ -namespace NBomber.IntegrationTests - -open Xunit - -[] - -do() - diff --git a/tests/NBomber.IntegrationTests/CliArgsTests.fs b/tests/NBomber.IntegrationTests/CliArgsTests.fs deleted file mode 100644 index 7768bbae..00000000 --- a/tests/NBomber.IntegrationTests/CliArgsTests.fs +++ /dev/null @@ -1,95 +0,0 @@ -module Tests.CliArgs - -open System -open System.IO - -open Swensen.Unquote -open Xunit - -open NBomber.Contracts -open NBomber.Domain -open NBomber.FSharp - -let scenario = Scenario.create("scenario", fun ctx -> task { return Response.ok() }) |> Scenario.withoutWarmUp -let scenario2 = Scenario.create("scenario2", fun ctx -> task { return Response.ok() }) |> Scenario.withoutWarmUp - -[] -[] -[] -let ``correct CLI commands should load config`` (command) = - let context = - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.executeCliArgs [command; "Configuration/test_config.json"] - - test <@ context.NBomberConfig.IsSome @> - test <@ context.InfraConfig.IsNone @> - -[] -[] -[] -[] -[] -[] -[] -let ``incorrect CLI command should not load config`` (command) = - let context = - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.executeCliArgs [command; "Configuration/test_config.json"] - - test <@ context.NBomberConfig.IsNone @> - test <@ context.InfraConfig.IsNone @> - -[] -[] -[] -let ``correct CLI commands should load infra config`` (command) = - let context = - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.executeCliArgs [command; "Configuration/infra_config.json"] - - test <@ context.NBomberConfig.IsNone @> - test <@ context.InfraConfig.IsSome @> - -[] -[] -[] -[] -[] -[] -[] -let ``incorrect CLI command should not load infra config`` (command) = - let context = - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.executeCliArgs [command; "Configuration/infra_config.json"] - - test <@ context.NBomberConfig.IsNone @> - test <@ context.InfraConfig.IsNone @> - -[] -[] -[] -let ``CLI commands should throw ex if config file is not found`` (command) = - Assert.Throws(typeof, - fun _ -> NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.executeCliArgs [command; "not_found_config.json"] - |> ignore) - -[] -[] -[] -let ``CLI commands should throw ex if infra config file is not found`` (command) = - Assert.Throws(typeof, - fun _ -> NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.executeCliArgs [command; "not_found_infra_config.json"] - |> ignore) - -[] -[] -[] -let ``TargetScenarios should update NBomberContext`` (command) = - let context = - NBomberRunner.registerScenarios [scenario; scenario2] - |> NBomberRunner.executeCliArgs [command; "scenario2"] - - test <@ context.TargetScenarios.Value.Length = 1 @> - test <@ context.TargetScenarios.Value.Head = "scenario2" @> diff --git a/tests/NBomber.IntegrationTests/Concurrency/ConstantActorSchedulerTests.fs b/tests/NBomber.IntegrationTests/Concurrency/ConstantActorSchedulerTests.fs deleted file mode 100644 index 53432e33..00000000 --- a/tests/NBomber.IntegrationTests/Concurrency/ConstantActorSchedulerTests.fs +++ /dev/null @@ -1,124 +0,0 @@ -module Tests.Concurrency.ConstantActorScheduler - -open System -open System.Threading -open System.Threading.Tasks - -open Serilog -open Swensen.Unquote -open FsToolkit.ErrorHandling -open Xunit - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.FSharp -open NBomber.Domain -open NBomber.Domain.Stats.ScenarioStatsActor -open NBomber.Domain.ScenarioContext -open NBomber.Domain.Concurrency -open NBomber.Domain.Scheduler -open NBomber.Domain.Scheduler.ConstantActorScheduler -open NBomber.Extensions.Internal - -let internal baseScenario = - Scenario.create("test_scn", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withLoadSimulations [KeepConstant(100, seconds 30)] - |> List.singleton - |> Scenario.createScenarios - |> Result.getOk - |> List.head - -let internal logger = LoggerConfiguration().CreateLogger() - -let internal baseScnDep = { - Logger = logger - Scenario = baseScenario - ScenarioCancellationToken = new CancellationTokenSource() - ScenarioOperation = ScenarioOperation.Bombing - ScenarioStatsActor = new ScenarioStatsActor(logger, baseScenario, Constants.DefaultReportingInterval) - ExecStopCommand = fun _ -> () - TestInfo = TestInfo.empty - GetNodeInfo = fun () -> NodeInfo.empty - CurrentTimeBucket = TimeSpan.Zero -} - -[] -let ``AddActors should start actors if there is no actors`` () = - use scheduler = new ConstantActorScheduler(baseScnDep, ConstantActorScheduler.Test.exec) - - let initCount = scheduler.ScheduledActorCount - scheduler.AddActors(5, TimeSpan.Zero) - Task.Delay(milliseconds 10).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ initCount = 0 @> - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 5 @> - -[] -let ``AddActors should start actors to run forever until the finish of scenario duration`` () = - use scheduler = new ConstantActorScheduler(baseScnDep, ConstantActorScheduler.Test.exec) - - scheduler.AddActors(5, TimeSpan.Zero) - Task.Delay(milliseconds 10).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 5 @> - test <@ scheduler.AvailableActors.Count = 5 @> - -[] -let ``RemoveActors should stop some actors and keep them in actor pool`` () = - use scheduler = new ConstantActorScheduler(baseScnDep, ConstantActorScheduler.Test.exec) - - scheduler.AddActors(10, TimeSpan.Zero) - Task.Delay(seconds 2).Wait() - scheduler.RemoveActors(5) - Task.Delay(seconds 2).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 5 @> - test <@ scheduler.AvailableActors.Count = 10 @> - -[] -let ``Stop should stop all working actors`` () = - use scheduler = new ConstantActorScheduler(baseScnDep, ConstantActorScheduler.Test.exec) - - scheduler.AddActors(5, TimeSpan.Zero) - Task.Delay(seconds 2).Wait() - (scheduler :> IDisposable).Dispose() - Task.Delay(seconds 2).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 0 @> - test <@ scheduler.AvailableActors.Count = 5 @> - -[] -let ``RampingConstant should work correctly`` () = - - Scenario.create("scenario", fun ctx -> task { - - let! step = Step.run("step", ctx, fun () -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [RampingConstant(copies = 10, during = seconds 5)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let stats = nodeStats.ScenarioStats[0] - - test <@ stats.AllRequestCount > 0 @> - test <@ stats.Ok.Request.Count > 0 @> diff --git a/tests/NBomber.IntegrationTests/Concurrency/OneTimeActorSchedulerTests.fs b/tests/NBomber.IntegrationTests/Concurrency/OneTimeActorSchedulerTests.fs deleted file mode 100644 index 7055208a..00000000 --- a/tests/NBomber.IntegrationTests/Concurrency/OneTimeActorSchedulerTests.fs +++ /dev/null @@ -1,84 +0,0 @@ -module Tests.Concurrency.OneTimeActorScheduler - -open System -open System.Threading -open System.Threading.Tasks - -open Serilog -open Swensen.Unquote -open Xunit -open FsToolkit.ErrorHandling - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.FSharp -open NBomber.Domain -open NBomber.Domain.Stats.ScenarioStatsActor -open NBomber.Domain.ScenarioContext -open NBomber.Domain.Concurrency -open NBomber.Domain.Scheduler -open NBomber.Domain.Scheduler.OneTimeActorScheduler -open NBomber.Extensions.Internal - -let internal baseScenario = - Scenario.create("test_scn", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withLoadSimulations [KeepConstant(100, seconds 30)] - |> List.singleton - |> Scenario.createScenarios - |> Result.getOk - |> List.head - -let internal logger = LoggerConfiguration().CreateLogger() - -let internal baseScnDep = { - Logger = logger - Scenario = baseScenario - ScenarioCancellationToken = new CancellationTokenSource() - ScenarioOperation = ScenarioOperation.Bombing - ScenarioStatsActor = new ScenarioStatsActor(logger, baseScenario, Constants.DefaultReportingInterval) - ExecStopCommand = fun _ -> () - TestInfo = TestInfo.empty - GetNodeInfo = fun () -> NodeInfo.empty - CurrentTimeBucket = TimeSpan.Zero -} - -[] -let ``InjectActors should start actors if there is no actors`` () = - use scheduler = new OneTimeActorScheduler(baseScnDep, OneTimeActorScheduler.Test.exec) - - let initCount = scheduler.ScheduledActorCount - scheduler.InjectActors(5, TimeSpan.Zero) - Task.Delay(milliseconds 10).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ initCount = 0 @> - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 5 @> - -[] -let ``InjectActors should execute actors once until next turn`` () = - use scheduler = new OneTimeActorScheduler(baseScnDep, OneTimeActorScheduler.Test.exec) - - scheduler.InjectActors(5, TimeSpan.Zero) - Task.Delay(seconds 2).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 0 @> - -[] -let ``Stop should stop all working actors`` () = - use scheduler = new OneTimeActorScheduler(baseScnDep, OneTimeActorScheduler.Test.exec) - - scheduler.InjectActors(5, TimeSpan.Zero) - Task.Delay(milliseconds 10).Wait() - (scheduler :> IDisposable).Dispose() - Task.Delay(seconds 2).Wait() - let workingActors = ScenarioActorPool.Test.getWorkingActors scheduler.AvailableActors - - test <@ scheduler.ScheduledActorCount = 5 @> - test <@ Seq.length workingActors = 0 @> diff --git a/tests/NBomber.IntegrationTests/Concurrency/ScenarioSchedulerTests.fs b/tests/NBomber.IntegrationTests/Concurrency/ScenarioSchedulerTests.fs deleted file mode 100644 index 3b8b8a7b..00000000 --- a/tests/NBomber.IntegrationTests/Concurrency/ScenarioSchedulerTests.fs +++ /dev/null @@ -1,223 +0,0 @@ -module Tests.Concurrency.ScenarioScheduler - -open System -open Swensen.Unquote -open Xunit -open FsToolkit.ErrorHandling -open NBomber -open NBomber.Contracts -open NBomber.Domain.DomainTypes -open NBomber.Domain.Scheduler -open NBomber.Domain.Scheduler.ScenarioScheduler -open NBomber.FSharp - -let getRandomValue minRate maxRate = 42 - -[] -[] // ramp-up -[] // ramp-up -[] // ramp-up -[] // ramp-up -[] // ramp-down -[] // ramp-down -[] // ramp-down -[] // ramp-down -[] // ramp-down -let ``schedule should correctly handle ramp-up or ramp-down for RampingInject`` - (prevCopiesCount: int, rate: int, timeProgress: int, result: int) = - - let constWorkingActorCount = 0 - - let simulation = { - Value = RampingInject(rate, TimeSpan.Zero, TimeSpan.Zero) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.schedule getRandomValue simulation timeProgress constWorkingActorCount - - match command with - | SchedulerCommand.InjectOneTimeActors -> test <@ copiesCount = result @> - | _ -> failwith "invalid command" - -[] -[] // inject -[] // inject -[] // inject -[] // inject -let ``schedule should correctly handle Inject`` - (prevCopiesCount: int, rate: int, timeProgress: int, result: int) = - - let constWorkingActorCount = 0 - - let simulation = { - Value = Inject(rate, TimeSpan.Zero, TimeSpan.Zero) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.schedule getRandomValue simulation timeProgress constWorkingActorCount - - match command with - | SchedulerCommand.InjectOneTimeActors -> test <@ copiesCount = result @> - | _ -> failwith "invalid command" - -[] -[] // ramp-up -[] // ramp-up -[] // ramp-up -[] // ramp-up -let ``schedule should correctly handle ramp-up for RampingConstant`` - (prevCopiesCount: int, copiesCount: int, currentConstActorCount: int, timeProgress: int, result: int) = - - let simulation = { - Value = RampingConstant(copiesCount, TimeSpan.Zero) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.schedule getRandomValue simulation timeProgress currentConstActorCount - - match command with - | SchedulerCommand.AddConstantActors -> test <@ copiesCount = result @> - | _ -> failwith "invalid command" - -[] -[] // ramp-down -[] // ramp-down -[] // ramp-down -let ``schedule should correctly handle ramp-down for RampingConstant`` - (prevCopiesCount: int, copiesCount: int, currentConstActorCount: int, timeProgress: int, result: int) = - - let simulation = { - Value = RampingConstant(copiesCount, TimeSpan.Zero) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.schedule getRandomValue simulation timeProgress currentConstActorCount - - match command with - | SchedulerCommand.RemoveConstantActors -> test <@ copiesCount = result @> - | _ -> failwith "invalid command" - -[] -[] // keep-constant add actors -[] // keep-constant add actors -[] // do nothing -[] // keep-constant remove actors -let ``schedule should correctly handle KeepConstant`` - (prevCopiesCount: int, copiesCount: int, currentConstActorCount: int, timeProgress: int, result: int) = - - let simulation = { - Value = KeepConstant(copiesCount, TimeSpan.Zero) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.schedule getRandomValue simulation timeProgress currentConstActorCount - - match command with - | SchedulerCommand.AddConstantActors -> test <@ copiesCount = result @> - | SchedulerCommand.DoNothing -> test <@ copiesCount = 0 @> - | SchedulerCommand.RemoveConstantActors -> test <@ copiesCount = result @> - | _ -> failwith "invalid command" - -[] -[] // do nothing -[] // do nothing -[] // remove constant actors -let ``schedule should correctly handle Pause`` - (prevCopiesCount: int, currentConstActorCount: int, timeProgress: int, result: int) = - - let simulation = { - Value = Pause(seconds 1) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.schedule getRandomValue simulation timeProgress currentConstActorCount - - match command with - | SchedulerCommand.RemoveConstantActors -> test <@ copiesCount = result @> - | SchedulerCommand.DoNothing -> test <@ copiesCount = 0 @> - | _ -> failwith "invalid command" - -[] -[] // do nothing -[] // remove constant actors -[] // remove constant actors -let ``scheduleCleanPrevSimulation should remove Constant actors in case of switch from Closed to Open model`` - (prevCopiesCount: int, currentConstActorCount: int, result: int) = - - let simulation = { - Value = Pause(seconds 1) - StartTime = TimeSpan.Zero - EndTime = TimeSpan.Zero - Duration = TimeSpan.Zero - PrevActorCount = prevCopiesCount - } - - let struct (command, copiesCount) = - ScenarioScheduler.Test.scheduleCleanPrevSimulation simulation currentConstActorCount - - match command with - | SchedulerCommand.RemoveConstantActors -> test <@ copiesCount = result @> - | SchedulerCommand.DoNothing -> test <@ copiesCount = 0 @> - | _ -> failwith "invalid command" - -[] -[] -let ``should run Inject correctly`` () = - Scenario.create("hello_world_scenario", fun ctx -> task { - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 2, interval = seconds 1, during = seconds 20)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.map(fun nodeStats -> - let reqCount = nodeStats.ScenarioStats[0].Ok.Request.Count - let rps = nodeStats.ScenarioStats[0].Ok.Request.RPS - test <@ reqCount = 40 @> - test <@ nodeStats.AllRequestCount = 40 @> - test <@ rps = 2 @> - ) - |> Result.mapError failwith - |> ignore - -[] -[] -[] -[] -[] -let ``calcTimeDrift should correctly calculate time drift for simulation interval`` - (startInterval: int, endInterval: int, simulationInterval: int, timeDrift: int) = - - let sInterval = TimeSpan.FromSeconds startInterval - let eInterval = TimeSpan.FromSeconds endInterval - let msInterval = TimeSpan.FromSeconds simulationInterval - let tDrift = TimeSpan.FromSeconds timeDrift - - let result = ScenarioScheduler.Test.calcTimeDrift sInterval eInterval msInterval - - test <@ result = tDrift @> \ No newline at end of file diff --git a/tests/NBomber.IntegrationTests/Configuration/duplicate_scenarios_config.json b/tests/NBomber.IntegrationTests/Configuration/duplicate_scenarios_config.json deleted file mode 100644 index 898292ea..00000000 --- a/tests/NBomber.IntegrationTests/Configuration/duplicate_scenarios_config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "GlobalSettings": { - "ScenariosSettings": [ - { - "ScenarioName": "1", - "WarmUpDuration": "00:00:02" - }, - { - "ScenarioName": "1", - "WarmUpDuration": "00:00:02" - } - ] - } -} diff --git a/tests/NBomber.IntegrationTests/Configuration/infra_config.json b/tests/NBomber.IntegrationTests/Configuration/infra_config.json deleted file mode 100644 index 164f4457..00000000 --- a/tests/NBomber.IntegrationTests/Configuration/infra_config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Serilog": { - "MinimumLevel": "Debug", - "WriteTo": [ - { - "Name": "File", - "Args": { - "path": "./logs/log.txt", - "rollingInterval": "Day" - } - } - ] - } -} diff --git a/tests/NBomber.IntegrationTests/Configuration/missing_fields_config.json b/tests/NBomber.IntegrationTests/Configuration/missing_fields_config.json deleted file mode 100644 index 8ef710f6..00000000 --- a/tests/NBomber.IntegrationTests/Configuration/missing_fields_config.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "GlobalSettings": { - "ScenariosSettings": [ - { - "ScenarioName": "test_youtube" - }, - { - "WarmUpDuration": "00:00:05", - "Duration": "00:00:20", - "ConcurrentCopies": 100 - } - ], - "TargetScenarios": [ "test_youtube" ], - "ReportFileName": "custom_report_name_from_json", - "ReportFormats": ["Html", "Txt"] - } -} diff --git a/tests/NBomber.IntegrationTests/Configuration/scenario_init_only_config.json b/tests/NBomber.IntegrationTests/Configuration/scenario_init_only_config.json deleted file mode 100644 index be73bec9..00000000 --- a/tests/NBomber.IntegrationTests/Configuration/scenario_init_only_config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "GlobalSettings": { - "ScenariosSettings": [ - { - "ScenarioName": "init_only_scenario", - - "CustomSettings": { - "TargetHost": "localhost", - "MsgSizeInBytes": 1000, - "PauseMs": 100 - } - } - ] - } -} diff --git a/tests/NBomber.IntegrationTests/Configuration/test_config.json b/tests/NBomber.IntegrationTests/Configuration/test_config.json deleted file mode 100644 index 960ccb2e..00000000 --- a/tests/NBomber.IntegrationTests/Configuration/test_config.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "TestSuite": "gitter.io", - "TestName": "test http api", - - "TargetScenarios": ["test_youtube"], - - "GlobalSettings": { - - "ScenariosSettings": [ - { - "ScenarioName": "test_youtube", - "WarmUpDuration": "00:00:02", - - "LoadSimulationsSettings": [ - { "RampingConstant": [2, "00:00:02"] }, - { "KeepConstant": [2, "00:00:02"] }, - { "RampingInject": [2, "00:00:01", "00:00:02"] }, - { "Inject": [2, "00:00:01", "00:00:02"] } - ], - - "CustomSettings": { - "TargetHost": "localhost", - "MsgSizeInBytes": 1000, - "PauseMs": 100 - }, - - "MaxFailCount": 500 - } - ], - - "ReportFileName": "custom_report_name", - "ReportFolder": "./my_reports", - "ReportFormats": ["Html", "Txt"], - "ReportingInterval": "00:00:30", - "EnableHintsAnalyzer": false - } -} diff --git a/tests/NBomber.IntegrationTests/Configuration/test_config_2.json b/tests/NBomber.IntegrationTests/Configuration/test_config_2.json deleted file mode 100644 index 1ae40edc..00000000 --- a/tests/NBomber.IntegrationTests/Configuration/test_config_2.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "TestSuite": "gitter.io", - "TestName": "test http api", - - "GlobalSettings": { - "ScenariosSettings": [ - { - "ScenarioName": "test_youtube", - "WarmUpDuration": "00:00:02", - - "LoadSimulationsSettings": [ - { "RampingConstant": [2, "00:00:02"] }, - { "KeepConstant": [2, "00:00:02"] }, - { "RampingInject": [2, "00:00:01", "00:00:02"] }, - { "Inject": [2, "00:00:01", "00:00:02"] } - ], - - "ClientFactorySettings": [ - { "FactoryName": "test_pool", "ClientCount": 100 } - ], - - "CustomSettings": { - "TargetHost": "localhost", - "MsgSizeInBytes": 1000, - "PauseMs": 100 - } - } - ], - - "TargetScenarios": [ "test_youtube" ], - "ReportFileName": "custom_report_name", - "ReportFolder": "./my_custom_reports", - "ReportFormats": ["Html", "Txt"], - "ReportingInterval": "00:00:30" - } -} diff --git a/tests/NBomber.IntegrationTests/ConfigurationTests.fs b/tests/NBomber.IntegrationTests/ConfigurationTests.fs deleted file mode 100644 index afcf71cb..00000000 --- a/tests/NBomber.IntegrationTests/ConfigurationTests.fs +++ /dev/null @@ -1,116 +0,0 @@ -namespace Tests.Configuration - -open System -open System.IO - -open Microsoft.FSharp.Core -open Xunit -open FSharp.Json -open Swensen.Unquote - -open NBomber.Contracts -open NBomber.Configuration -open NBomber.Extensions.Internal -open NBomber.FSharp - -[] -type TestCustomSettings = { - TargetHost: string - MsgSizeInBytes: int - PauseMs: int -} - -module JsonConfig = - - [] - let ``parse() should parse json file successfully`` () = - "Configuration/test_config.json" |> File.ReadAllText |> JsonExt.deserialize |> ignore - "Configuration/scenario_init_only_config.json" |> File.ReadAllText |> JsonExt.deserialize |> ignore - - [] - let ``parse() should throw ex if mandatory json fields are missing`` () = - Assert.Throws( - typeof, - fun _ -> - "Configuration/missing_fields_config.json" - |> File.ReadAllText - |> JsonExt.deserialize - |> ignore - ) - - [] - let ``parse() should parse custom settings successfully`` () = - let config = "Configuration/test_config.json" |> File.ReadAllText |> JsonExt.deserialize - let testCustomSettings = - config.GlobalSettings - |> Option.bind(fun x -> x.ScenariosSettings) - |> Option.bind(fun x -> Some x[0]) - |> Option.bind(fun x -> x.CustomSettings) - |> Option.map(Newtonsoft.Json.JsonConvert.DeserializeObject) - - match testCustomSettings with - | Some settings -> - Assert.True(settings.TargetHost.Length > 0) - Assert.True(settings.MsgSizeInBytes > 0) - - | None -> () - -module NBomberRunner = - - [] - let ``loadConfig should support load config via HTTP URL`` () = - - let url = "https://raw.githubusercontent.com/PragmaticFlow/NBomber/dev/tests/NBomber.IntegrationTests/Configuration/test_config.json" - - Scenario.create("scenario_1", fun ctx -> task { - return Response.ok() - }) - |> NBomberRunner.registerScenario - |> NBomberRunner.loadConfig url - |> fun nbContext -> - test <@ nbContext.NBomberConfig.IsSome @> - - [] - let ``loadConfig should throw exception if config is empty or doesn't follow NBomberConfig format`` () = - Assert.Throws( - typeof, - fun _ -> - let url = "https://raw.githubusercontent.com/PragmaticFlow/NBomber.Enterprise.Examples/main/examples/ClusterSimpleHttpDemo/local/coordinator-config.json" - - Scenario.create("scenario_1", fun ctx -> task { - return Response.ok() - }) - |> NBomberRunner.registerScenario - |> NBomberRunner.loadConfig url - |> ignore - ) - - [] - let ``loadInfraConfig should parse json config successfully`` () = - NBomberRunner.registerScenarios [] - |> NBomberRunner.withoutReports - |> NBomberRunner.loadInfraConfig "Configuration/infra_config.json" - - [] - let ``loadInfraConfig should throw ex if json file is not found`` () = - Assert.Throws( - typeof, - fun _ -> NBomberRunner.registerScenarios [] - |> NBomberRunner.withoutReports - |> NBomberRunner.loadInfraConfig "Configuration/infra_config_2.json" - |> ignore - ) - - [] - let ``loadInfraConfig should support load config via HTTP URL`` () = - - let url = "https://raw.githubusercontent.com/PragmaticFlow/NBomber/dev/tests/NBomber.IntegrationTests/Configuration/infra_config.json" - - Scenario.create("scenario_1", fun ctx -> task { - return Response.ok() - }) - |> NBomberRunner.registerScenario - |> NBomberRunner.loadInfraConfig url - |> fun nbContext -> - test <@ nbContext.InfraConfig.IsSome @> - test <@ nbContext.InfraConfig.Value.GetSection("Serilog:MinimumLevel").Value = "Debug" @> diff --git a/tests/NBomber.IntegrationTests/DataFeed/DataFeedTests.fs b/tests/NBomber.IntegrationTests/DataFeed/DataFeedTests.fs deleted file mode 100644 index ecef255b..00000000 --- a/tests/NBomber.IntegrationTests/DataFeed/DataFeedTests.fs +++ /dev/null @@ -1,271 +0,0 @@ -module Tests.Feed - -open System -open System.Threading -open System.Threading.Tasks - -open Xunit -open FsCheck -open FsCheck.Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Infra -open NBomber.DomainServices -open NBomber.FSharp -open Tests.TestHelper -// -// [] -// type User = { -// Id: int -// Name: string -// } -// -// let createBaseContext () = -// let nodeInfo = NodeInfo.init None -// let token = CancellationToken.None -// let dep = Dependency.createFor NodeType.SingleNode -// NBomberContext.createBaseContext dep.TestInfo (fun () -> nodeInfo) token dep.Dep.Logger -// -// [] -// let ``createCircular iterate over array sequentially``(length: int) = -// -// length > 10 ==> lazy -// -// let orderedList = [0 .. length - 1] -// -// let feed = orderedList |> Feed.createCircular "circular" -// -// let context = createBaseContext() -// feed.Init(context).Wait() -// -// let iterateLength = length + length // increase original length -// -// let actual = List.init iterateLength (fun i -> -// let scenarioInfo = NBomber.Domain.Scenario.createScenarioInfo("test_scn", seconds 10, i, ScenarioOperation.Bombing) -// feed.GetNextItem(scenarioInfo, null) -// ) -// -// let final = orderedList |> List.append(orderedList) -// -// test <@ actual = final @> -// -// [] -// let ``createConstant returns next value from seq for the same scenarioThreadId``(length: int) = -// -// length > 10 ==> lazy -// -// let orderedList = [0 .. length - 1] -// let sameValues = orderedList |> List.map(fun i -> i, i) -// -// let feed = orderedList |> Feed.createCircular "circular" -// -// let context = createBaseContext() -// feed.Init(context).Wait() -// -// let actual = List.init length (fun i -> -// let scenarioInfo = NBomber.Domain.Scenario.createScenarioInfo("test_scn", seconds 10, i, ScenarioOperation.Bombing) -// feed.GetNextItem(scenarioInfo, null), feed.GetNextItem(scenarioInfo, null) -// ) -// -// test <@ actual <> sameValues @> -// -// [] -// let ``createConstant returns the same value for the same scenarioInfo``(length: int) = -// -// length > 10 ==> lazy -// -// let orderedList = [0 .. length - 1] -// let sameValues = orderedList |> List.map(fun i -> i, i) -// -// let feed = orderedList |> Feed.createConstant "constant" -// -// let context = createBaseContext() -// feed.Init(context).Wait() -// -// let actual = List.init length (fun i -> -// let scenarioInfo = NBomber.Domain.Scenario.createScenarioInfo("test_scn", seconds 10, i, ScenarioOperation.Bombing) -// feed.GetNextItem(scenarioInfo, null), feed.GetNextItem(scenarioInfo, null) -// ) -// -// test <@ actual = sameValues @> -// -// [] -// let ``createRandom returns the random numbers list for each full iteration``() = -// -// let numbers = [1;2;3;4;5;6;7;8] -// -// let feed1 = numbers |> Feed.createRandom "random" -// let feed2 = numbers |> Feed.createRandom "random" -// -// let context = createBaseContext() -// feed1.Init(context).Wait() -// feed2.Init(context).Wait() -// -// let actual1 = List.init numbers.Length (fun i -> -// let scenarioInfo = NBomber.Domain.Scenario.createScenarioInfo("test_scn", seconds 10, i, ScenarioOperation.Bombing) -// feed1.GetNextItem(scenarioInfo, null) -// ) -// -// let actual2 = List.init numbers.Length (fun i -> -// let scenarioInfo = NBomber.Domain.Scenario.createScenarioInfo("test_scn", seconds 10, i, ScenarioOperation.Bombing) -// feed2.GetNextItem(scenarioInfo, null) -// ) -// -// test <@ actual1 <> actual2 @> -// -// [] -// let ``provides infinite iteration``(numbers: int list, iterationTimes: uint32) = -// -// (numbers.Length > 0 && numbers.Length < 200 && iterationTimes > 0u && iterationTimes < 5000u) ==> lazy -// -// let scenarioInfo = NBomber.Domain.Scenario.createScenarioInfo("test_scn", seconds 10, numbers.Length, ScenarioOperation.Bombing) -// -// let circular = numbers |> Feed.createCircular "circular" -// let constant = numbers |> Feed.createConstant "constant" -// let random = numbers |> Feed.createRandom "random" -// -// let context = createBaseContext() -// circular.Init(context).Wait() -// constant.Init(context).Wait() -// random.Init(context).Wait() -// -// for i = 0 to int iterationTimes do -// circular.GetNextItem(scenarioInfo, null) |> ignore -// constant.GetNextItem(scenarioInfo, null) |> ignore -// random.GetNextItem(scenarioInfo, null) |> ignore -// -// [] -// let ``FeedData.fromJson works correctly``() = -// -// let data = FeedData.fromJson "./DataFeed/users-feed-data.json" -// let users = data |> Seq.toArray -// -// test <@ users.Length > 0 @> -// -// [] -// let ``FeedData.fromCsv works correctly``() = -// -// let data = FeedData.fromCsv "./DataFeed/users-feed-data.csv" -// let users = data |> Seq.toArray -// -// test <@ users.Length > 0 @> -// -// [] -// let ``FeedData fromSeq should support lazy initialize``() = -// -// let mutable data = [-1; -2; -3] -// -// let feed = Feed.createRandomLazy "my_feed" (fun context -> seq { yield! data }) -// -// data <- [1; 2; 3] -// -// let step = Step.create("ok step", feed = feed, execute = fun context -> task { -// do! Task.Delay(milliseconds 100) -// if context.FeedItem > 0 then return Response.ok() -// else return Response.fail() -// }) -// -// Scenario.create "feed test scenario" [step] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 10)] -// |> NBomberRunner.registerScenario -// |> NBomberRunner.run -// |> Result.getOk -// |> fun stats -> test <@ stats.FailCount = 0 @> -// -// [] -// let ``Feed with the same name should be supported``() = -// -// let mutable feed_1_initCount = 0 -// let mutable feed_2_initCount = 0 -// -// let feed1 = { new IFeed with -// member _.FeedName = "same_name" -// -// member _.Init(context) = -// feed_1_initCount <- feed_1_initCount + 1 -// Task.CompletedTask -// -// member _.GetNextItem(scenarioInfo, stepData) = 1 -// } -// -// let feed2 = { new IFeed with -// member _.FeedName = "same_name" -// -// member _.Init(context) = -// feed_2_initCount <- feed_2_initCount + 1 -// Task.CompletedTask -// -// member _.GetNextItem(scenarioInfo, stepData) = 1 -// } -// -// let step1 = Step.create("step_1", feed = feed1, execute = fun context -> task { -// do! Task.Delay(milliseconds 100) -// return Response.ok() -// }) -// -// let step2 = Step.create("step_2", feed = feed2, execute = fun context -> task { -// do! Task.Delay(milliseconds 100) -// return Response.ok() -// }) -// -// let scn1 = -// Scenario.create "scenario_1" [step1] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 5)] -// -// let scn2 = -// Scenario.create "scenario_2" [step2] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 5)] -// -// NBomberRunner.registerScenarios [scn1; scn2] -// |> NBomberRunner.run -// |> Result.getOk -// |> fun stats -> -// test <@ feed_1_initCount = 1 @> -// test <@ feed_2_initCount = 1 @> -// -// [] -// let ``Init for the same instance shared btw steps and scenarios should be invoked only once``() = -// -// let mutable feedInitCount = 0 -// -// let feed = { new IFeed with -// member _.FeedName = "same_name" -// -// member _.Init(context) = -// feedInitCount <- feedInitCount + 1 -// Task.CompletedTask -// -// member _.GetNextItem(scenarioInfo, stepData) = 1 -// } -// -// let step1 = Step.create("step_1", feed = feed, execute = fun context -> task { -// do! Task.Delay(milliseconds 100) -// return Response.ok() -// }) -// -// let step2 = Step.create("step_2", feed = feed, execute = fun context -> task { -// do! Task.Delay(milliseconds 100) -// return Response.ok() -// }) -// -// let scn1 = -// Scenario.create "scenario_1" [step1; step2] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 5)] -// -// let scn2 = -// Scenario.create "scenario_2" [step1] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 5)] -// -// NBomberRunner.registerScenarios [scn1; scn2] -// |> NBomberRunner.run -// |> Result.getOk -// |> fun stats -> test <@ feedInitCount = 1 @> diff --git a/tests/NBomber.IntegrationTests/DataFeed/users-feed-data.csv b/tests/NBomber.IntegrationTests/DataFeed/users-feed-data.csv deleted file mode 100644 index 5536806a..00000000 --- a/tests/NBomber.IntegrationTests/DataFeed/users-feed-data.csv +++ /dev/null @@ -1,6 +0,0 @@ -Id,Name -1,Test User 1 -2,Test User 2 -3,Test User 3 -4,Test User 4 -5,Test User 5 diff --git a/tests/NBomber.IntegrationTests/DataFeed/users-feed-data.json b/tests/NBomber.IntegrationTests/DataFeed/users-feed-data.json deleted file mode 100644 index c1cca05d..00000000 --- a/tests/NBomber.IntegrationTests/DataFeed/users-feed-data.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "Id": 1, - "Name": "Test User 1" - }, - { - "Id": 2, - "Name": "Test User 2" - } -] diff --git a/tests/NBomber.IntegrationTests/ExtensionsTests.fs b/tests/NBomber.IntegrationTests/ExtensionsTests.fs deleted file mode 100644 index 87c24d63..00000000 --- a/tests/NBomber.IntegrationTests/ExtensionsTests.fs +++ /dev/null @@ -1,20 +0,0 @@ -module Tests.Extensions - -open System -open System.Diagnostics -open System.Threading - -open Xunit -open Swensen.Unquote -open FsCheck -open FsCheck.Xunit -open FsToolkit.ErrorHandling - -open NBomber -open NBomber.Extensions.Internal - -[] -let ``String concatWithComma should concat strings with comma`` () = - Assert.Equal("foo, bar, baz", ["foo"; "bar"; "baz"] |> String.concatWithComma) - Assert.Equal("foo", ["foo"] |> String.concatWithComma) - Assert.Equal("", [] |> String.concatWithComma) \ No newline at end of file diff --git a/tests/NBomber.IntegrationTests/HintsAnalyzerTests.fs b/tests/NBomber.IntegrationTests/HintsAnalyzerTests.fs deleted file mode 100644 index 17cc0819..00000000 --- a/tests/NBomber.IntegrationTests/HintsAnalyzerTests.fs +++ /dev/null @@ -1,129 +0,0 @@ -module Tests.HintsAnalyzer - -open System -open System.Threading.Tasks - -open Xunit -open FsCheck.Xunit -open Swensen.Unquote -open FsToolkit.ErrorHandling - -open NBomber -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain -open NBomber.Domain.Stats.Statistics -open NBomber.Infra -open NBomber.FSharp - -let baseNodeStats = { - ScenarioStats = Array.empty - MetricStats = Array.empty - PluginStats = Array.empty - NodeInfo = NodeInfo.init None - TestInfo = { SessionId = ""; TestSuite = ""; TestName = ""; ClusterId = "" } - ReportFiles = Array.empty - AllRequestCount = 0 - AllOkCount = 0 - AllFailCount = 0 - AllBytes = 0 - Duration = TimeSpan.MinValue -} - -let baseScnStats = { - ScenarioName = "scenario" - Ok = MeasurementStats.empty - Fail = MeasurementStats.empty - StepStats = Array.empty - LoadSimulationStats = { SimulationName = ""; Value = 0 } - CurrentOperation = OperationType.None - AllRequestCount = 0 - AllOkCount = 0 - AllFailCount = 0 - AllBytes = 0 - Duration = TimeSpan.MinValue -} - -let baseStepStats = { - StepName = "step" - Ok = { - Request = { Count = 0; RPS = 0.0 } - Latency = { MinMs = 0.0; MeanMs = 0.0; MaxMs = 0.0 - Percent50 = 0.0; Percent75 = 0.0; Percent95 = 0.0; Percent99 = 0.0; StdDev = 0.0 - LatencyCount = { LessOrEq800 = 0; More800Less1200 = 0; MoreOrEq1200 = 0 } } - DataTransfer = { MinBytes = 0; MeanBytes = 0; MaxBytes = 0 - Percent50 = 0; Percent75 = 0; Percent95 = 0; Percent99 = 0; StdDev = 0.0; AllBytes = 0 } - StatusCodes = Array.empty - } - Fail = { - Request = { Count = 0; RPS = 0.0 } - Latency = { MinMs = 0.0; MeanMs = 0.0; MaxMs = 0.0 - Percent50 = 0.0; Percent75 = 0.0; Percent95 = 0.0; Percent99 = 0.0; StdDev = 0.0 - LatencyCount = { LessOrEq800 = 0; More800Less1200 = 0; MoreOrEq1200 = 0 } } - DataTransfer = { MinBytes = 0; MeanBytes = 0; MaxBytes = 0 - Percent50 = 0; Percent75 = 0; Percent95 = 0; Percent99 = 0; StdDev = 0.0; AllBytes = 0 } - StatusCodes = Array.empty - } -} - -[] -let ``analyzeNodeStats should return hint for case when DataTransfer.MinBytes = 0`` (minBytes: uint32) = - - let req = { baseStepStats.Ok.Request with RPS = 1.0 } - let dt = { baseStepStats.Ok.DataTransfer with MinBytes = int minBytes } - let sc = { StatusCode = "200" - IsError = false - Message = "Success" - Count = 1 } - let stepStats = { baseStepStats with Ok = { Request = req; Latency = baseStepStats.Ok.Latency; DataTransfer = dt; StatusCodes = [| sc |] } } - let scnStats = { baseScnStats with StepStats = [| stepStats |] } - let nodeStats = { baseNodeStats with ScenarioStats = [| scnStats |] } - - match HintsAnalyzer.analyzeNodeStats nodeStats with - | hint::tail when minBytes = 0u -> () - | [] when minBytes > 0u -> () - | e -> failwith "analyzer finished with error" - -[] -let ``HintsAnalyzer should be disabled by default`` () = - - Scenario.create("test", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withLoadSimulations [LoadSimulation.KeepConstant(1, seconds 1)] - |> Scenario.withoutWarmUp - |> NBomberRunner.registerScenario - |> NBomberRunner.runWithResult Seq.empty - |> Result.getOk - |> fun result -> - test <@ result.Hints |> Seq.isEmpty @> - -[] -let ``disableHintsAnalyzer should disable hints`` () = - - Scenario.create("test", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withLoadSimulations [LoadSimulation.KeepConstant(1, seconds 1)] - |> Scenario.withoutWarmUp - |> NBomberRunner.registerScenario - |> NBomberRunner.enableHintsAnalyzer false - |> NBomberRunner.runWithResult Seq.empty - |> Result.getOk - |> fun result -> - test <@ result.Hints.Length = 0 @> - -[] -let ``analyzeNodeStats should return hints for case when StatusCodes are not provided`` () = - let req = { baseStepStats.Ok.Request with RPS = 1.0; Count = 1 } - let dt = { baseStepStats.Ok.DataTransfer with MinBytes = 100 } - let stepStats = { baseStepStats with Ok = { StatusCodes = Array.empty; Request = req; Latency = baseStepStats.Ok.Latency; DataTransfer = dt} } - let scnStats = { baseScnStats with StepStats = [| stepStats |] } - let nodeStats = { baseNodeStats with ScenarioStats = [| scnStats |] } - - let hints = HintsAnalyzer.analyzeNodeStats nodeStats - - test <@ hints.Length > 0 @> diff --git a/tests/NBomber.IntegrationTests/LoadSimulationTests.fs b/tests/NBomber.IntegrationTests/LoadSimulationTests.fs deleted file mode 100644 index c941c908..00000000 --- a/tests/NBomber.IntegrationTests/LoadSimulationTests.fs +++ /dev/null @@ -1,86 +0,0 @@ -module Tests.LoadSimulation - -open System -open Xunit -open Swensen.Unquote -open FsToolkit.ErrorHandling -open NBomber -open NBomber.Contracts -open NBomber.Domain -open NBomber.Domain.DomainTypes - -[] -let ``create should correctly calculate and order simulations within timeline for Closed Model`` () = - - result { - let simulations = [ - RampingConstant(10, seconds 20) - KeepConstant(20, seconds 50) - KeepConstant(30, seconds 50) - KeepConstant(1000, seconds 80) - RampingConstant(0, seconds 20) - ] - - let! loadSimulations = LoadSimulation.create "my-scenario" simulations - let planedDuration = LoadSimulation.getPlanedDuration loadSimulations - - let first = loadSimulations |> List.head - let last = loadSimulations |> List.last - - let ascendingOrderByTime = loadSimulations |> List.sortBy(fun x -> x.EndTime) - - test <@ loadSimulations.Length = simulations.Length @> - test <@ first.StartTime <= last.EndTime @> - test <@ planedDuration = last.EndTime @> - test <@ loadSimulations = ascendingOrderByTime @> - test <@ first.PrevActorCount = 0 @> - test <@ last.PrevActorCount = 1000 @> - } - |> ignore - -[] -let ``create should correctly calculate and order simulations within timeline for Open Model`` () = - - result { - let simulations = [ - RampingInject(20, seconds 1, seconds 20) - Inject(20, seconds 1, seconds 30) - RampingInject(0, seconds 1, seconds 20) - ] - - let! loadSimulations = LoadSimulation.create "my-scenario" simulations - let planedDuration = LoadSimulation.getPlanedDuration loadSimulations - - let first = loadSimulations |> List.head - let last = loadSimulations |> List.last - - let ascendingOrderByTime = loadSimulations |> List.sortBy(fun x -> x.EndTime) - - test <@ loadSimulations.Length = simulations.Length @> - test <@ first.StartTime <= last.EndTime @> - test <@ planedDuration = last.EndTime @> - test <@ loadSimulations = ascendingOrderByTime @> - test <@ first.PrevActorCount = 0 @> - test <@ last.PrevActorCount = 20 @> - } - |> ignore - -[] -let ``calcTimeProgress should correctly calculate progress for concrete segment`` () = - - let currentTime1 = TimeSpan.Zero - let currentTime2 = TimeSpan.FromSeconds 1 - let currentTime3 = TimeSpan.FromSeconds 5 - let currentTime4 = TimeSpan.FromSeconds 10 - - let duration = TimeSpan.FromSeconds 20 - - let progress1 = LoadSimulation.calcTimeProgress currentTime1 duration - let progress2 = LoadSimulation.calcTimeProgress currentTime2 duration - let progress3 = LoadSimulation.calcTimeProgress currentTime3 duration - let progress4 = LoadSimulation.calcTimeProgress currentTime4 duration - - test <@ progress1 = 0 @> - test <@ progress2 = 5 @> - test <@ progress3 = 25 @> - test <@ progress4 = 50 @> diff --git a/tests/NBomber.IntegrationTests/LoggingTests.fs b/tests/NBomber.IntegrationTests/LoggingTests.fs deleted file mode 100644 index d3206680..00000000 --- a/tests/NBomber.IntegrationTests/LoggingTests.fs +++ /dev/null @@ -1,65 +0,0 @@ -module Tests.Logging - -open System -open System.Threading.Tasks - -open Serilog -open Serilog.Events -open Serilog.Sinks.InMemory -open Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Contracts -open NBomber.FSharp - -[] -let ``set min logger level should work correctly`` () = - - let inMemorySink1 = new InMemorySink() - let inMemorySink2 = new InMemorySink() - - let createLoggerConfig1 = fun () -> - LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Error) - .WriteTo.Sink(inMemorySink1) - - let createLoggerConfig2 = fun () -> - LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Verbose) - .WriteTo.Sink(inMemorySink2) - - Scenario.create("scenario1", fun ctx -> task { - do! Task.Delay(seconds 0.1) - ctx.Logger.Information "this message should not be printed" - return Response.ok() - }) - |> Scenario.withLoadSimulations [KeepConstant(1, TimeSpan.FromSeconds 3.0)] - |> Scenario.withoutWarmUp - |> NBomberRunner.registerScenario - |> NBomberRunner.withLoggerConfig createLoggerConfig1 - |> NBomberRunner.runWithArgs ["disposeLogger=false"] - |> ignore - - Scenario.create("scenario2", fun ctx -> task { - do! Task.Delay(seconds 0.1) - ctx.Logger.Information "this message should not be printed" - return Response.ok() - }) - |> Scenario.withLoadSimulations [KeepConstant(1, TimeSpan.FromSeconds 3.0)] - |> Scenario.withoutWarmUp - |> NBomberRunner.registerScenario - |> NBomberRunner.withLoggerConfig createLoggerConfig2 - |> NBomberRunner.runWithArgs ["disposeLogger=false"] - |> ignore - - let scenario1LogPrinted = - inMemorySink1.LogEvents - |> Seq.exists(fun x -> x.MessageTemplate.Text = "this message should not be printed") - - let scenario2LogPrinted = - inMemorySink2.LogEvents - |> Seq.exists(fun x -> x.MessageTemplate.Text = "this message should not be printed") - - test <@ scenario1LogPrinted = false @> - test <@ scenario2LogPrinted = true @> diff --git a/tests/NBomber.IntegrationTests/MetricsStatsActorTests.fs b/tests/NBomber.IntegrationTests/MetricsStatsActorTests.fs deleted file mode 100644 index f0d86ce7..00000000 --- a/tests/NBomber.IntegrationTests/MetricsStatsActorTests.fs +++ /dev/null @@ -1,161 +0,0 @@ -module Tests.MetricsStatsActor - -open Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Contracts.Stats -open NBomber.Domain.Stats.MetricsStatsActor -open Tests.TestHelper - -[] -let ``BuildReportingStats should calculate correctly for Gauge`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Gauge) - - metricsActor.Publish(AddMetric { Name = metricName; Value = 3.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 2.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 1.5 }) - - let allMetrics = metricsActor.BuildReportingStats(seconds 1).GetAwaiter().GetResult() - let result = allMetrics[0] - - test <@ result.Percentiles.IsNone @> - test <@ result.Name = metricName @> - test <@ result.Current = 1.5 @> - test <@ result.Max = 0 @> - -[] -let ``BuildReportingStats should calculate correctly for Histogram`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Histogram) - - metricsActor.Publish(AddMetric { Name = metricName; Value = 3.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 2.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 1.5 }) - - let allMetrics = metricsActor.BuildReportingStats(seconds 1).GetAwaiter().GetResult() - let result = allMetrics[0] - - test <@ result.Percentiles.IsNone @> - test <@ result.Name = metricName @> - test <@ result.Current = 1.5 @> - test <@ result.Max = 3.5 @> - -[] -let ``BuildReportingStats should handle invalid args`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - // case 1 - let result1 = metricsActor.BuildReportingStats(seconds 1).GetAwaiter().GetResult() - - // case 2 - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Histogram) - let result2 = metricsActor.BuildReportingStats(seconds 1).GetAwaiter().GetResult() - - // case 3 - metricsActor.Publish(AddMetric { Name = "a"; Value = 3.5 }) - let result3 = metricsActor.BuildReportingStats(seconds 1).GetAwaiter().GetResult() - - test <@ result1.Length = 0 @> - test <@ result2[0].Current = 0 @> - test <@ result3[0].Current = 0 @> - -[] -let ``GetFinalStats should calculate correctly for Gauge`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Gauge) - - metricsActor.Publish(AddMetric { Name = metricName; Value = 3.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 2.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 1.5 }) - - let allMetrics = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - let result = allMetrics[0] - - test <@ result.Percentiles.IsNone @> - test <@ result.Name = metricName @> - test <@ result.Current = 1.5 @> - test <@ result.Max = 0 @> - -[] -let ``GetFinalStats should calculate correctly for Histogram`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Histogram) - - metricsActor.Publish(AddMetric { Name = metricName; Value = 3.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 2.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 1.5 }) - - let allMetrics = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - let result = allMetrics[0] - - test <@ result.Percentiles.IsSome @> - test <@ result.Name = metricName @> - test <@ result.Current = 1.5 @> - test <@ result.Max = 3.5 @> - test <@ result.Percentiles.Value.Mean = 2.5 @> - test <@ result.Percentiles.Value.Percent50 = 2.5 @> - test <@ result.Percentiles.Value.Percent99 = 3.5 @> - -[] -let ``GetFinalStats should handle invalid args`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - // case 1 - let result1 = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - - // case 2 - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Histogram) - let result2 = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - - // case 3 - metricsActor.Publish(AddMetric { Name = "a"; Value = 3.5 }) - let result3 = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - - test <@ result1.Length = 0 @> - test <@ result2[0].Current = 0 @> - test <@ result3[0].Current = 0 @> - -[] -let ``CleanAllMetrics should clean stats`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let metricsActor = new MetricsStatsActor(env.Dep.Logger) - let metricName = "my-metric" - - metricsActor.RegisterMetric(metricName, "MB", 100, MetricType.Gauge) - - metricsActor.Publish(AddMetric { Name = metricName; Value = 3.5 }) - metricsActor.Publish(AddMetric { Name = metricName; Value = 2.5 }) - - let result1 = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - - metricsActor.Publish CleanAllMetrics - - let result2 = metricsActor.GetFinalStats(seconds 1).GetAwaiter().GetResult() - - test <@ result1[0].Current = 2.5 @> - test <@ result2[0].Current = 0 @> diff --git a/tests/NBomber.IntegrationTests/NBomber.IntegrationTests.fsproj b/tests/NBomber.IntegrationTests/NBomber.IntegrationTests.fsproj deleted file mode 100644 index 9d65605e..00000000 --- a/tests/NBomber.IntegrationTests/NBomber.IntegrationTests.fsproj +++ /dev/null @@ -1,78 +0,0 @@ - - - net8.0 - true - true - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - Always - - - Always - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - - diff --git a/tests/NBomber.IntegrationTests/NBomberContextTests.fs b/tests/NBomber.IntegrationTests/NBomberContextTests.fs deleted file mode 100644 index 2c8f47dd..00000000 --- a/tests/NBomber.IntegrationTests/NBomberContextTests.fs +++ /dev/null @@ -1,271 +0,0 @@ -module Tests.NBomberContext - -open System -open System.IO - -open Xunit -open Swensen.Unquote -open FsCheck -open FsCheck.Xunit -open FsToolkit.ErrorHandling - -open NBomber -open NBomber.Configuration -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Contracts.Internal -open NBomber.Extensions.Internal -open NBomber.Errors -open NBomber.DomainServices -open NBomber.FSharp - -let baseGlobalSettings = { - ScenariosSettings = None - ReportFileName = None - ReportFolder = None - ReportFormats = None - ReportingInterval = None - EnableHintsAnalyzer = None - EnableStopTestForcibly = None -} - -let baseScenarioSetting = { - ScenarioName = "test_scenario" - WarmUpDuration = None - LoadSimulationsSettings = None - CustomSettings = None - MaxFailCount = None -} - -let baseScenario = - Scenario.create("1", fun ctx -> task { - return Response.fail() - }) - |> Scenario.withoutWarmUp - -let config = { - TestSuite = Some Constants.DefaultTestSuite - TestName = Some Constants.DefaultTestName - TargetScenarios = Some ["1"] - GlobalSettings = None -} - -let context = - NBomberRunner.registerScenario baseScenario - |> NBomberRunner.enableHintsAnalyzer false - -[] -let ``getTargetScenarios should return all registered scenarios if TargetScenarios are empty`` () = - let context = { context with NBomberConfig = Some config } - match NBomberContext.getTargetScenarios(context) with - | scenarios when scenarios.Length = 1 -> () - | _ -> failwith "" - -[] -let ``getTargetScenarios should return only target scenarios if TargetScenarios are not empty`` () = - let config = { config with TargetScenarios = Some ["10"] } - - let scn1 = { baseScenario with ScenarioName = "1" } - let scn2 = { baseScenario with ScenarioName = "2" } - - let context = { context with NBomberConfig = Some config - RegisteredScenarios = [scn1; scn2] } - - match NBomberContext.getTargetScenarios(context) with - | scenarios when scenarios.Length = 1 && scenarios[0] = "10" -> () - | _ -> failwith "" - -[] -let ``getReportFileNameOrDefault should return from GlobalSettings, if empty then from TestContext, if empty then default name`` - (configValue: string option, contextValue: string option) = - - (configValue.IsNone || configValue.IsSome && not (isNull configValue.Value)) ==> lazy - (contextValue.IsNone || contextValue.IsSome && not (isNull contextValue.Value)) ==> lazy - - let glSettings = { baseGlobalSettings with ReportFileName = configValue } - let config = { config with GlobalSettings = Some glSettings } - - let ctx = { - context with NBomberConfig = Some config - Reporting = { context.Reporting with Formats = [ReportFormat.Txt] - FileName = contextValue } - } - - let currentTime = DateTime.UtcNow - let currentTimeStr = currentTime.ToString("yyyy-MM-dd--HH-mm-ss") - let fileName = ctx |> NBomberContext.getReportFileNameOrDefault(currentTime) - - match configValue, contextValue with - | Some v1, Some v2 -> test <@ fileName = v1 @> - | Some v1, None -> test <@ fileName = v1 @> - | None, Some v2 -> test <@ fileName = v2 @> - | None, None -> test <@ fileName = $"{Constants.DefaultReportName}_{currentTimeStr}" @> - -[] -let ``getReportFormats should return from GlobalSettings, if empty then from TestContext`` - (configValue: ReportFormat list option, contextValue: ReportFormat list) = - - let glSettings = { baseGlobalSettings with ReportFormats = configValue } - let config = { config with GlobalSettings = Some glSettings } - - let ctx = { - context with NBomberConfig = Some config - Reporting = { context.Reporting with Formats = contextValue - FileName = None } - } - - let formats = NBomberContext.getReportFormats(ctx) - match configValue, contextValue with - | Some v, _ -> Assert.True((formats = v)) - - | None, v when List.isEmpty v -> - test <@ formats = List.empty @> - - | None, v -> test <@ formats = contextValue @> - -[] -let ``getHintAnalyzer should be based on EnableHintsAnalyzer from GlobalSettings, if empty then from TestContext`` - (configValue: bool option, contextValue: bool) = - - let glSettings = { baseGlobalSettings with EnableHintsAnalyzer = configValue } - let config = { config with GlobalSettings = Some glSettings } - - let ctx = { - context with - NBomberConfig = Some config - EnableHintsAnalyzer = contextValue - } - - let enable = NBomberContext.getEnableHintAnalyzer ctx - match configValue with - | Some value -> test <@ value = enable @> - | None -> test <@ contextValue = enable @> - -[] -let ``getTestSuite should return from Config, if empty then from TestContext`` - (configValue: string option) = - - match configValue with - | Some value -> - let config = { config with TestSuite = configValue } - let ctx = { context with NBomberConfig = Some config } - let testSuite = NBomberContext.getTestSuite(ctx) - test <@ testSuite = value @> - - | None -> - let testSuite = NBomberContext.getTestSuite(context) - test <@ testSuite = context.TestSuite @> - -[] -let ``getTestName should return from Config, if empty then from TestContext`` - (configValue: string option) = - - match configValue with - | Some value -> - let config = { config with TestName = configValue } - let ctx = { context with NBomberConfig = Some config } - let testSuite = NBomberContext.getTestName(ctx) - test <@ testSuite = value @> - - | None -> - let testSuite = NBomberContext.getTestName(context) - test <@ testSuite = context.TestName @> - -[] -let ``getReportingInterval should return fail if interval is smaller than min value`` () = - - let okContext = { context with Reporting = { context.Reporting with ReportingInterval = seconds 5 }} - let errorContext = { context with Reporting = { context.Reporting with ReportingInterval = seconds 2 }} - - let ok = NBomberContext.getReportingInterval(okContext) - let error = NBomberContext.getReportingInterval(errorContext) - - test <@ Result.isOk ok @> - test <@ Result.isError error @> - -[] -let ``checkAvailableTarget should return fail if TargetScenarios has empty value`` () = - let scn = { baseScenario with ScenarioName = "1" } - match NBomberContext.Validation.checkAvailableTargets [scn] [" "] with - | Error (TargetScenariosNotFound _) -> () - | _ -> failwith "" - -[] -let ``checkAvailableTarget should return fail if TargetScenarios has values which doesn't exist in registered scenarios`` () = - let scn = { baseScenario with ScenarioName = "1" } - match NBomberContext.Validation.checkAvailableTargets [scn] ["3"] with - | Error (TargetScenariosNotFound _) -> () - | _ -> failwith "" - -[] -let ``checkReportName should return fail if ReportFileName is empty`` () = - match NBomberContext.Validation.checkReportName(" ") with - | Error (EmptyReportName _) -> () - | _ -> failwith "" - -[] -let ``checkReportName should return fail if ReportFileName contains invalid chars`` () = - Path.GetInvalidFileNameChars() - |> Seq.map(Array.singleton >> String) - |> Seq.iter(fun x -> - match NBomberContext.Validation.checkReportName(x) with - | Error (InvalidReportName _) -> () - | Error EmptyReportName -> () - | Ok value -> failwithf $"received OK for char: %s{value}" - | error -> error |> Result.getError |> AppError.toString |> failwith - ) - -[] -let ``checkReportFolder should return fail if ReportFolderPath is empty`` () = - match NBomberContext.Validation.checkReportFolder(" ") with - | Error (EmptyReportFolderPath _) -> () - | _ -> failwith "" - -[] -let ``checkReportFolder should return fail if ReportFolderPath contains invalid chars`` () = - Path.GetInvalidPathChars() - |> Seq.map(Array.singleton >> String) - |> Seq.iter(fun x -> - match NBomberContext.Validation.checkReportFolder(x) with - | Error (InvalidReportFolderPath _) -> () - | Error EmptyReportFolderPath -> () - | Ok value -> failwithf $"received OK for char: %s{value}" - | error -> error |> Result.getError |> AppError.toString |> failwith - ) - -[] -let ``checkReportingInterval should return fail if ReportingInterval is smaller than min value`` () = - match NBomberContext.Validation.checkReportingInterval(seconds 3) with - | Error (ReportingIntervalSmallerThanMin _) -> () - | _ -> failwith "" - -[] -let ``createSessionArgs should properly create args with default values`` () = - - let context = NBomberRunner.registerScenario baseScenario - - taskResult { - let testInfo = SessionArgs.empty.TestInfo - let! scenarios = context |> NBomberContext.createScenarios - let! sessionArgs = context |> NBomberContext.createSessionArgs testInfo scenarios - return sessionArgs - } - |> fun t -> t.Result - |> Result.getOk - |> fun sessionArgs -> - test <@ context.NBomberConfig.IsNone @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.IsSome @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.Value.ReportFileName.IsSome @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.Value.ReportFolder.IsSome @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.Value.ReportFormats.IsSome @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.Value.ReportingInterval.IsSome @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.Value.ScenariosSettings.IsSome @> - test <@ sessionArgs.NBomberConfig.GlobalSettings.Value.EnableHintsAnalyzer.IsSome @> - -[] -let ``createSessionArgs should validate empty register scenarios`` () = - NBomberRunner.registerScenarios [] - |> NBomberRunner.run - |> Result.getError - |> fun error -> - test <@ error.Contains "No scenarios were registered" @> diff --git a/tests/NBomber.IntegrationTests/NBomberRunnerTests.fs b/tests/NBomber.IntegrationTests/NBomberRunnerTests.fs deleted file mode 100644 index a82715ab..00000000 --- a/tests/NBomber.IntegrationTests/NBomberRunnerTests.fs +++ /dev/null @@ -1,43 +0,0 @@ -module Tests.NBomberRunner - -open System.Threading.Tasks -open Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.FSharp -open NBomber.Domain - -[] -let ``withTargetScenarios should run only specified scenarios`` () = - - let mutable scn1Started = false - let mutable scn2Started = false - - let scn1 = - Scenario.create("scn_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withInit(fun _ -> task { scn1Started <- true }) - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 1)] - |> Scenario.withoutWarmUp - - let scn2 = - Scenario.create("scn_2", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withInit(fun _ -> task { scn2Started <- true }) - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 1)] - |> Scenario.withoutWarmUp - - NBomberRunner.registerScenarios [scn1; scn2] - |> NBomberRunner.withTargetScenarios ["scn_2"] - |> NBomberRunner.run - |> ignore - - test <@ scn1Started = false @> - test <@ scn2Started @> diff --git a/tests/NBomber.IntegrationTests/Plugins/PluginTests.fs b/tests/NBomber.IntegrationTests/Plugins/PluginTests.fs deleted file mode 100644 index 4d65e6e1..00000000 --- a/tests/NBomber.IntegrationTests/Plugins/PluginTests.fs +++ /dev/null @@ -1,159 +0,0 @@ -module Tests.Plugin - -open System -open System.Data -open System.Threading.Tasks - -open Serilog -open Serilog.Sinks.InMemory -open Serilog.Sinks.InMemory.Assertions -open Swensen.Unquote -open Xunit - -open NBomber -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain -open NBomber.FSharp -open Tests.TestHelper - -[] -let ``WorkerPlugin Init, Start, Stop should be invoked once for Warmup and once for Bombing`` () = - - let mutable invocationOrder = List.empty - let scenarios = PluginTestHelper.createScenarios() - - let plugin = { - new IWorkerPlugin with - member _.PluginName = "TestPlugin" - - member _.Init(_, _, _) = - invocationOrder <- "init" :: invocationOrder - Task.CompletedTask - - member _.Start() = - invocationOrder <- "start" :: invocationOrder - Task.CompletedTask - - member _.GetStats(_) = - invocationOrder <- "get_stats" :: invocationOrder - Task.FromResult(new DataSet()) - - member _.GetHints() = - invocationOrder <- "get_hints" :: invocationOrder - Array.empty - - member _.Stop() = - invocationOrder <- "stop" :: invocationOrder - Task.CompletedTask - - member _.Dispose() = - invocationOrder <- "dispose" :: invocationOrder - } - - NBomberRunner.registerScenarios scenarios - |> NBomberRunner.withWorkerPlugins [plugin] - |> NBomberRunner.enableHintsAnalyzer true - |> NBomberRunner.withReportingInterval(seconds 5) - |> NBomberRunner.run - |> Result.mapError failwith - |> ignore - - test <@ List.rev invocationOrder = ["init"; "start"; "stop"; "start"; "stop"; "get_stats"; "get_hints"; "dispose"] @> - -[] -let ``Init should be invoked with infra config`` () = - - let scenarios = PluginTestHelper.createScenarios() - let mutable pluginConfig = Unchecked.defaultof<_> - - let plugin = { - new IWorkerPlugin with - member _.PluginName = "TestPlugin" - - member _.Init(logger, _, infraConfig) = - pluginConfig <- infraConfig - Task.CompletedTask - - member _.Start() = Task.CompletedTask - member _.GetHints() = Array.empty - member _.GetStats(_) = Task.FromResult(new DataSet()) - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - NBomberRunner.registerScenarios scenarios - |> NBomberRunner.loadInfraConfig "Configuration/infra_config.json" - |> NBomberRunner.withWorkerPlugins [plugin] - |> NBomberRunner.run - |> Result.mapError(fun x -> failwith x) - |> ignore - - let serilogConfig = pluginConfig.GetSection("Serilog") - - test <@ isNull serilogConfig = false @> - -[] -let ``PluginStats should return empty data set in case of execution timeout`` () = - let inMemorySink = new InMemorySink() - let loggerConfig = fun () -> LoggerConfiguration().WriteTo.Sink(inMemorySink) - - let timeoutPlugin = { - new IWorkerPlugin with - member _.PluginName = "TestPlugin" - - member _.Init(_, _, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - member _.GetStats(_) = task { - do! Task.Delay(seconds 10) // we waiting more than default timeout = 5 sec - return new DataSet() - } - member _.GetHints() = Array.empty - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - Scenario.create("1", fun ctx -> task { - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 10)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withLoggerConfig loggerConfig - |> NBomberRunner.withWorkerPlugins [timeoutPlugin] - |> NBomberRunner.runWithArgs ["disposeLogger=false"] - |> Result.getOk - |> fun nodeStats -> - test <@ Array.isEmpty nodeStats.PluginStats @> - inMemorySink.Should().HaveMessage("Getting plugin stats failed with the timeout error", "because timeout has been reached") |> ignore - -[] -let ``PluginStats should return empty data set in case of internal exception`` () = - let inMemorySink = new InMemorySink() - let loggerConfig = fun () -> LoggerConfiguration().WriteTo.Sink(inMemorySink) - - let exceptionPlugin = { - new IWorkerPlugin with - member _.PluginName = "TestPlugin" - member _.Init(_, _, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - member _.GetStats(_) = failwith "test exception" // we throw exception - member _.GetHints() = Array.empty - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - Scenario.create("1", fun ctx -> task { - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 2)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withLoggerConfig loggerConfig - |> NBomberRunner.withWorkerPlugins [exceptionPlugin] - |> NBomberRunner.runWithArgs ["disposeLogger=false"] - |> Result.getOk - |> fun nodeStats -> - test <@ Array.isEmpty nodeStats.PluginStats @> - inMemorySink.Should().HaveMessage("Getting plugin stats failed", "because exception was thrown") |> ignore diff --git a/tests/NBomber.IntegrationTests/Reporting/CSVReportingTests.fs b/tests/NBomber.IntegrationTests/Reporting/CSVReportingTests.fs deleted file mode 100644 index b6eb4151..00000000 --- a/tests/NBomber.IntegrationTests/Reporting/CSVReportingTests.fs +++ /dev/null @@ -1,78 +0,0 @@ -module Tests.Reporting.CSVReporting - -open System.IO -open System.Threading.Tasks - -open Serilog -open Serilog.Events -open Serilog.Sinks.InMemory -open Swensen.Unquote -open Xunit - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain -open NBomber.Extensions.Internal -open NBomber.FSharp - -// This test might fail if you are using a region on your computer that uses, as a decimal sign -[] -let ``CSV report should be formatted properly`` () = - - // delete all directories with all files - if Directory.Exists "./my_csv_reports" then - Directory.Delete("./my_csv_reports", recursive = true) - - let scenario = - Scenario.create("test1", fun ctx -> task { - - let! step1 = Step.run("ok step 1", ctx, fun () -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 5, during = seconds 5)] - - let scenario2 = - Scenario.create("test2", fun ctx -> task { - - let! step2 = Step.run("ok step 2", ctx, fun () -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - - let! step3 = Step.run("ok step 3", ctx, fun () -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 5, during = seconds 5)] - - NBomberRunner.registerScenarios [scenario; scenario2] - |> NBomberRunner.withReportFolder "./my_csv_reports" - |> NBomberRunner.withReportFormats [ReportFormat.Csv] - |> NBomberRunner.run - |> ignore - - let files = Directory.GetFiles("./my_csv_reports", searchPattern = "*.*", searchOption = SearchOption.TopDirectoryOnly) - - let csvRows = - files - |> Seq.map FileInfo - |> Seq.find(fun s -> [".csv"] |> Seq.contains s.Extension) - |> fun file -> file.FullName - |> File.ReadAllLines - - test <@ csvRows.Length = 6 @> - - csvRows - |> Seq.map(String.split [|","|]) - |> Seq.map Array.length - |> fun a -> test <@ Seq.max a = Seq.min a @> // compare columns count diff --git a/tests/NBomber.IntegrationTests/Reporting/ReportingConfigurationTests.fs b/tests/NBomber.IntegrationTests/Reporting/ReportingConfigurationTests.fs deleted file mode 100644 index 6d802f44..00000000 --- a/tests/NBomber.IntegrationTests/Reporting/ReportingConfigurationTests.fs +++ /dev/null @@ -1,161 +0,0 @@ -module Tests.Reporting.ReportingConfiguration - -open System.IO -open System.Threading.Tasks - -open Serilog -open Serilog.Events -open Serilog.Sinks.InMemory -open Swensen.Unquote -open Xunit - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain -open NBomber.Extensions.Internal -open NBomber.FSharp - -[] -let ``JSON config settings for ReportFileName and ReportFolder should be properly handled`` () = - - // test_config_2.json contains - // "ReportFileName": "custom_report_name", - // "ReportFolder": "./my_custom_reports", - // "ReportFormats": ["Html", "Txt"], - - // delete all directories with all files - if Directory.Exists "./my_custom_reports" then - Directory.Delete("./my_custom_reports", recursive = true) - - let scenario = - Scenario.create("test", fun ctx -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 5, during = seconds 5)] - - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.loadConfig("./Configuration/test_config_2.json") - |> NBomberRunner.run - |> ignore - - let dirExist = Directory.Exists "./my_custom_reports" - let files = Directory.GetFiles("./my_custom_reports", searchPattern = "*.*", searchOption = SearchOption.TopDirectoryOnly) - - test <@ dirExist @> - test <@ files.Length = 3 @> // here we check that only 2 report formats were generated + txt 1 log file - - files - |> Seq.map(FileInfo) - |> Seq.iter(fun file -> - test <@ file.Name.Contains "custom_report_name" || file.Name.Contains "nbomber-log" @> - test <@ [".html"; ".txt"] |> Seq.contains file.Extension @> - test <@ file.Length > 0L @> - ) - -[] -let ``withReportFileName and withReportFolder should be properly handled`` () = - - // delete all directories with all files - if Directory.Exists "./my_reports_2" then - Directory.Delete("./my_reports_2", recursive = true) - - let scenario = - Scenario.create("test", fun ctx -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 5, during = seconds 5)] - - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.withReportFileName "custom_report_name" - |> NBomberRunner.withReportFolder "./my_reports_2" - |> NBomberRunner.run - |> ignore - - let dirExist = Directory.Exists "./my_reports_2" - let files = Directory.GetFiles("./my_reports_2", searchPattern = "*.*", searchOption = SearchOption.TopDirectoryOnly) - - test <@ dirExist @> - test <@ files.Length = 5 @> // here we check that all report formats were generated - - files - |> Seq.map(FileInfo) - |> Seq.iter(fun file -> - test <@ file.Name.Contains "custom_report_name" || file.Name.Contains "nbomber-log" @> - test <@ [".html"; ".csv"; ".txt"; ".md"] |> Seq.contains file.Extension @> - test <@ file.Length > 0L @> - ) - -[] -let ``withoutReports should not print report files`` () = - - let inMemorySink = new InMemorySink() - - let createLoggerConfig = fun () -> - LoggerConfiguration() - .MinimumLevel.Is(LogEventLevel.Verbose) - .WriteTo.Sink(inMemorySink) - - let scenario = - Scenario.create("test", fun ctx -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 5, during = seconds 5)] - - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.withoutReports - |> NBomberRunner.withLoggerConfig createLoggerConfig - |> NBomberRunner.runWithArgs ["disposeLogger=false"] - |> ignore - - let logEvents = inMemorySink.LogEvents |> Seq.toList - let reportsBuilt = logEvents |> List.exists(fun x -> x.MessageTemplate.Text = "Report.build") - let txtReportPrinted = logEvents |> List.exists(fun x -> x.MessageTemplate.Text = "TxtReport.print") - let csvReportPrinted = logEvents |> List.exists(fun x -> x.MessageTemplate.Text = "CsvReport.print") - let htmlReportPrinted = logEvents |> List.exists(fun x -> x.MessageTemplate.Text = "HtmlReport.print") - let mdReportPrinted = logEvents |> List.exists(fun x -> x.MessageTemplate.Text = "MdReport.print") - let consoleReportPrinted = logEvents |> List.exists(fun x -> x.MessageTemplate.Text = "ConsoleReport.print") - - test <@ reportsBuilt = true @> - test <@ txtReportPrinted = false @> - test <@ csvReportPrinted = false @> - test <@ htmlReportPrinted = false @> - test <@ mdReportPrinted = false @> - test <@ consoleReportPrinted = true @> - -[] -let ``withoutReports should not save report files`` () = - - // delete all directories with all files - if Directory.Exists "./no-reports/1" then - Directory.Delete("./no-reports/1", recursive = true) - - let scenario = - Scenario.create("test", fun ctx -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 5, during = seconds 5)] - - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.withoutReports - |> NBomberRunner.withReportFolder "./no-reports/1" - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ stats.ReportFiles.Length = 0 @> - - let dirExist = Directory.Exists "./no-reports/1" - let files = Directory.GetFiles("./no-reports/1", searchPattern = "*.*", searchOption = SearchOption.AllDirectories) - - test <@ dirExist @> - test <@ files.Length = 1 @> // here we check that all report formats were generated - test <@ FileInfo(files[0]).Name.Contains "nbomber-log" @> - diff --git a/tests/NBomber.IntegrationTests/Reporting/ReportingSinkTests.fs b/tests/NBomber.IntegrationTests/Reporting/ReportingSinkTests.fs deleted file mode 100644 index befe5c63..00000000 --- a/tests/NBomber.IntegrationTests/Reporting/ReportingSinkTests.fs +++ /dev/null @@ -1,322 +0,0 @@ -module Tests.Reporting.ReportingSinkTests - -open System.Threading.Tasks - -open Swensen.Unquote -open Xunit - -open NBomber -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain -open NBomber.FSharp -open Tests.TestHelper - -//todo: test that multiply sink will be invoked correctly -//todo: test that stop timer stops sending metrics in case when stopping is still executing -//todo: test cluster stats - -[] -let ``SaveFinalStats should receive correct stats`` () = - - let _finalStats = ResizeArray() - - let reportingSink = { - new IReportingSink with - member _.SinkName = "TestSink" - member _.Init(_, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - member _.SaveRealtimeStats(stats) = Task.CompletedTask - - member _.SaveFinalStats(stats) = - _finalStats.Add stats - Task.CompletedTask - - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - let scenario1 = - Scenario.create("scenario_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 30)] - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.withReportingSinks [reportingSink] - |> NBomberRunner.withReportingInterval(seconds 5) - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let final = _finalStats.ToArray() - test <@ final[0] = nodeStats @> - test <@ nodeStats.Duration = seconds 30 @> - test <@ nodeStats.ScenarioStats |> Array.filter(fun x -> x.CurrentOperation = OperationType.Complete) |> Array.length = 1 @> - - test <@ nodeStats.ScenarioStats |> Array.forall(fun x -> x.Ok.Request.Count > 0) @> - test <@ nodeStats.ScenarioStats |> Array.forall(fun x -> x.Ok.Request.Count > 0) @> - test <@ nodeStats.ScenarioStats |> Array.forall(fun x -> x.Ok.Request.RPS > 0.0) @> - - test <@ nodeStats.ScenarioStats |> Array.forall(fun x -> x.Fail.Request.Count = 0) @> - test <@ nodeStats.ScenarioStats |> Array.forall(fun x -> x.Fail.Request.Count = 0) @> - test <@ nodeStats.ScenarioStats |> Array.forall(fun x -> x.Fail.Request.RPS = 0.0) @> - -[] -let ``SaveRealtimeStats should receive calculated stats by intervals`` () = - - let _realtimeStats = ResizeArray() - - let reportingSink = { - new IReportingSink with - member _.SinkName = "TestSink" - member _.Init(_, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - - member _.SaveRealtimeStats(stats) = - _realtimeStats.Add(stats) - Task.CompletedTask - - member _.SaveFinalStats(stats) = Task.CompletedTask - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - let mutable delay = milliseconds 500 - let mutable size = 1000 - - let scenario1 = - Scenario.create("scenario_1", fun ctx -> task { - do! Task.Delay delay - return Response.ok(sizeBytes = size) - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 1, during = seconds 30)] - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.withReportingSinks [reportingSink] - |> NBomberRunner.withReportingInterval(seconds 5) - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - - let first = _realtimeStats[0] - let last = _realtimeStats[_realtimeStats.Count - 1] - - let rpsEquals = _realtimeStats |> Seq.collect id |> Seq.forall(fun x -> x.Ok.Request.RPS = 1) - let countEquals = _realtimeStats |> Seq.collect id |> Seq.forall(fun x -> x.Ok.Request.Count = 5) - - test <@ _realtimeStats.Count = 6 @> - - test <@ rpsEquals @> - test <@ countEquals @> - - test <@ first[0].Ok.Latency.MaxMs < 1000 && first[0].Ok.Latency.MaxMs > 500 @> - test <@ last[0].Ok.Latency.MaxMs < 1000 @> - test <@ first[0].Ok.DataTransfer.MaxBytes = last[0].Ok.DataTransfer.MaxBytes @> - -[] -let ``SaveRealtimeStats should receive correct calculated stats for long running steps`` () = - - let _realtimeStats = ResizeArray() - - let reportingSink = { - new IReportingSink with - member _.SinkName = "TestSink" - member _.Init(_, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - - member _.SaveRealtimeStats(stats) = - _realtimeStats.Add stats - Task.CompletedTask - - member _.SaveFinalStats(stats) = Task.CompletedTask - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - let scenario1 = - Scenario.create("scenario_1", fun ctx -> task { - - let! fastStep = Step.run("fast_step", ctx, fun () -> task { - do! Task.Delay(seconds 1) - return Response.ok() - }) - - let! fastStep = Step.run("long_step", ctx, fun () -> task { - do! Task.Delay(seconds 30) - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 10, during = seconds 20)] - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.withReportingSinks [reportingSink] - |> NBomberRunner.withReportingInterval(seconds 5) - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let first = _realtimeStats[0] - - test <@ first[0].StepStats[0].Ok.Request.Count = 10 @> - test <@ first[0].StepStats[0].Ok.Request.RPS = 2 @> - -[] -let ``SaveRealtimeStats should receive correct stats`` () = - - let _realtimeStats = ResizeArray() - let mutable _finalStats = Unchecked.defaultof - - let reportingSink = { - new IReportingSink with - member _.SinkName = "TestSink" - member _.Init(_, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - - member _.SaveRealtimeStats(stats) = - _realtimeStats.AddRange(stats) - Task.CompletedTask - - member _.SaveFinalStats(stats) = Task.CompletedTask - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - let scenario1 = - Scenario.create("scenario_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 30)] - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.withReportingSinks [reportingSink] - |> NBomberRunner.withReportingInterval(seconds 5) - |> NBomberRunner.run - |> Result.getOk - |> fun finalStats -> - let realtime = _realtimeStats.ToArray() - - test <@ realtime.Length > 0 @> - test <@ realtime |> Array.forall(fun x -> x.CurrentOperation = OperationType.Bombing) @> - test <@ realtime |> Array.forall(fun x -> x.Ok.Request.Count > 0) @> - test <@ realtime |> Array.forall(fun x -> x.Ok.Request.Count > 0) @> - test <@ realtime |> Array.forall(fun x -> x.Ok.Request.RPS > 0.0) @> - test <@ realtime |> Array.forall(fun x -> x.Fail.Request.Count = 0) @> - test <@ realtime |> Array.forall(fun x -> x.Fail.Request.Count = 0) @> - test <@ realtime |> Array.forall(fun x -> x.Fail.Request.RPS = 0.0) @> - - test <@ finalStats.NodeInfo.CurrentOperation = OperationType.Complete @> - test <@ finalStats.ScenarioStats[0].Ok.Request.Count > 0 @> - test <@ finalStats.ScenarioStats[0].Ok.Request.RPS > 0.0 @> - test <@ finalStats.ScenarioStats[0].Fail.Request.Count = 0 @> - test <@ finalStats.ScenarioStats[0].Fail.Request.RPS = 0.0 @> - -[] -let ``WorkerPlugin stats should be passed to IReportingSink SaveFinalStats`` () = - - let scenarios = PluginTestHelper.createScenarios() - let mutable _nodeStats = NodeStats.empty - - let plugin = { - new IWorkerPlugin with - member _.PluginName = "TestPlugin" - member _.Init(_, _, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - member _.GetStats(_) = PluginStatisticsHelper.createPluginStats() |> Task.FromResult - member _.GetHints() = Array.empty - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - let reportingSink = { - new IReportingSink with - member _.SinkName = "TestSink" - member _.Init(_, _) = Task.CompletedTask - member _.Start() = Task.CompletedTask - - member _.SaveRealtimeStats(_) = Task.CompletedTask - - member _.SaveFinalStats(stats) = - _nodeStats <- stats - Task.CompletedTask - - member _.Stop() = Task.CompletedTask - member _.Dispose() = () - } - - NBomberRunner.registerScenarios scenarios - |> NBomberRunner.withoutReports - |> NBomberRunner.withReportingSinks [reportingSink] - |> NBomberRunner.withReportingInterval(seconds 10) - |> NBomberRunner.withWorkerPlugins [plugin] - |> NBomberRunner.run - |> Result.mapError failwith - |> ignore - - let pluginStats = _nodeStats.PluginStats[0] - let table1 = pluginStats.Tables["PluginStatistics1Table"] - let table2 = pluginStats.Tables["PluginStatistics2Table"] - - // assert on IReportingSink - test <@ table1.Columns.Count > 0 @> - test <@ table1.Rows.Count > 0 @> - test <@ table2.Columns.Count > 0 @> - test <@ table2.Rows.Count > 0 @> - -[] -let ``ReportingSink Init, Start, Stop should be invoked once for Warmup and once for Bombing`` () = - - let mutable invocationOrder = List.empty - let mutable saveRealtimeStatsCounter = 0 - let scenarios = PluginTestHelper.createScenarios() - - let reportingSink = { - new IReportingSink with - member _.SinkName = "TestSink" - - member _.Init(_, _) = - invocationOrder <- "init" :: invocationOrder - Task.CompletedTask - - member _.Start() = - invocationOrder <- "start" :: invocationOrder - Task.CompletedTask - - member _.SaveRealtimeStats(_) = - saveRealtimeStatsCounter <- saveRealtimeStatsCounter + 1 - Task.CompletedTask - - member _.SaveFinalStats(stats) = - invocationOrder <- "save_final_stats" :: invocationOrder - Task.CompletedTask - - member _.Stop() = - invocationOrder <- "stop" :: invocationOrder - Task.CompletedTask - - member _.Dispose() = - invocationOrder <- "dispose" :: invocationOrder - } - - NBomberRunner.registerScenarios scenarios - |> NBomberRunner.withReportingSinks [reportingSink] - |> NBomberRunner.enableHintsAnalyzer true - |> NBomberRunner.withReportingInterval(seconds 5) - |> NBomberRunner.run - |> Result.mapError failwith - |> ignore - - test <@ saveRealtimeStatsCounter > 0 @> - test <@ List.rev invocationOrder = ["init"; "start"; "stop"; "start"; "stop"; "save_final_stats"; "dispose"] @> - diff --git a/tests/NBomber.IntegrationTests/ScenarioStatsActorTests.fs b/tests/NBomber.IntegrationTests/ScenarioStatsActorTests.fs deleted file mode 100644 index a8776cd7..00000000 --- a/tests/NBomber.IntegrationTests/ScenarioStatsActorTests.fs +++ /dev/null @@ -1,155 +0,0 @@ -module Tests.ScenarioStatsActor - -open System -open System.Threading.Tasks - -open FsCheck.Xunit -open Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Contracts.Stats -open NBomber.Contracts.Internal -open NBomber.Extensions.Internal -open NBomber.Domain.Stats.ScenarioStatsActor -open NBomber.FSharp -open Tests.TestHelper - -let internal baseScenario = - Scenario.create("scenario", fun ctx -> task { - do! Task.Delay(seconds 0.5) - return Response.ok() - }) - |> NBomber.Domain.Scenario.createScenario - |> Result.getOk - -[] -let ``AllRealtimeStats should contain cached realtime stats`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let statsActor = new ScenarioStatsActor(env.Dep.Logger, baseScenario, reportingInterval = seconds 5) - - for i in [1..10] do - let result1 = { Name = "step_name"; ClientResponse = Response.ok() - CurrentTimeBucket = TimeSpan.Zero; Latency = seconds i } - let result2 = { Name = Constants.ScenarioGlobalInfo; ClientResponse = Response.ok() - CurrentTimeBucket = TimeSpan.Zero; Latency = seconds i } - statsActor.Publish(AddMeasurement result1) - statsActor.Publish(AddMeasurement result2) - - let tcs = TaskCompletionSource() - let loadStats = { SimulationName = ""; Value = 10 } - let duration = seconds 10 - statsActor.Publish(BuildReportingStats(tcs, loadStats, duration)) - let realtimeStats = tcs.Task.Result - - test <@ statsActor.AllRealtimeStats[duration].Ok.Request.Count = 10 @> - test <@ statsActor.AllRealtimeStats[duration].StepStats[0].Ok.Request.Count = 10 @> - test <@ statsActor.AllRealtimeStats[duration].StepStats[0].Fail.Request.Count = 0 @> - test <@ realtimeStats.Ok.Request.Count = 10 @> - -[] -let ``TempBuffer should work correctly`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let statsActor = new ScenarioStatsActor(env.Dep.Logger, baseScenario, reportingInterval = seconds 5) - - // add metrics that match the current reporting bucket - let startTime = seconds 1 - for i in [1..5] do - let result1 = { Name = "step_name"; ClientResponse = Response.ok(); CurrentTimeBucket = startTime; Latency = seconds i } - let result2 = { Name = Constants.ScenarioGlobalInfo; ClientResponse = Response.ok(); CurrentTimeBucket = startTime; Latency = seconds i } - statsActor.Publish(AddMeasurement result1) - statsActor.Publish(AddMeasurement result2) - - // add metrics that StartTime is bigger than the current reporting bucket - let startTime = seconds 6 - for i in [1..10] do - let result1 = { Name = "step_name"; ClientResponse = Response.ok(); CurrentTimeBucket = startTime; Latency = seconds i } - let result2 = { Name = Constants.ScenarioGlobalInfo; ClientResponse = Response.ok(); CurrentTimeBucket = startTime; Latency = seconds i } - statsActor.Publish(AddMeasurement result1) - statsActor.Publish(AddMeasurement result2) - - let tcs = TaskCompletionSource() - let loadStats = { SimulationName = ""; Value = 10 } - let fiveSec = seconds 5 - statsActor.Publish(BuildReportingStats(tcs, loadStats, fiveSec)) - - let tcs = TaskCompletionSource() - let loadStats = { SimulationName = ""; Value = 10 } - let tenSec = seconds 10 - statsActor.Publish(BuildReportingStats(tcs, loadStats, tenSec)) - - tcs.Task.Wait() - - test <@ statsActor.AllRealtimeStats[fiveSec].Ok.Request.Count = 5 @> - test <@ statsActor.AllRealtimeStats[tenSec].Ok.Request.Count = 10 @> - -[] -let ``BuildReportingStats should preserver Steps order at which steps arrived`` (stepNames: string list) = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let statsActor = new ScenarioStatsActor(env.Dep.Logger, baseScenario, reportingInterval = seconds 5) - - let stepNames = - stepNames - |> List.filter(String.IsNullOrEmpty >> not) - |> List.groupBy id - |> List.map fst - - for stName in stepNames do - let measurement = { Name = stName; ClientResponse = Response.ok(); CurrentTimeBucket = TimeSpan.Zero; Latency = seconds 100 } - statsActor.Publish(AddMeasurement measurement) - - let globalStep = { Name = Constants.ScenarioGlobalInfo; ClientResponse = Response.ok(); CurrentTimeBucket = TimeSpan.Zero; Latency = seconds 100 } - statsActor.Publish(AddMeasurement globalStep) - - let reply = TaskCompletionSource() - let simulation = { SimulationName = ""; Value = 9 } - statsActor.Publish(BuildReportingStats(reply, simulation, seconds 10)) - let scnStats = reply.Task.Result - - stepNames - |> List.iteri(fun i stName -> - test <@ stName = scnStats.StepStats[i].StepName @> - ) - -[] -let ``DataTransfer should be calculated properly for Global Step Info`` () = - - let env = Dependency.createWithInMemoryLogger NodeType.SingleNode - let statsActor = new ScenarioStatsActor(env.Dep.Logger, baseScenario, reportingInterval = seconds 5) - - for i in [1 .. 100] do - let stepSmall = { Name = "step_small"; ClientResponse = Response.ok(sizeBytes = 1); CurrentTimeBucket = TimeSpan.Zero; Latency = seconds 100 } - statsActor.Publish(AddMeasurement stepSmall) - - let stepBig = { Name = "step_big"; ClientResponse = Response.ok(sizeBytes = 1000); CurrentTimeBucket = TimeSpan.Zero; Latency = seconds 100 } - statsActor.Publish(AddMeasurement stepBig) - - let stepGlobal = { Name = Constants.ScenarioGlobalInfo; ClientResponse = Response.ok(sizeBytes = 5); CurrentTimeBucket = TimeSpan.Zero; Latency = seconds 100 } - statsActor.Publish(AddMeasurement stepGlobal) - - let reply = TaskCompletionSource() - let simulation = { SimulationName = ""; Value = 9 } - statsActor.Publish(BuildReportingStats(reply, simulation, seconds 10)) - let scnStats = reply.Task.Result - - // GlobalInfoDataSize stats should be cleared - let stepBig = { Name = "step_big"; ClientResponse = Response.ok(sizeBytes = 1000); CurrentTimeBucket = TimeSpan.Zero; Latency = seconds 100 } - statsActor.Publish(AddMeasurement stepBig) - - let reply = TaskCompletionSource() - statsActor.Publish(BuildReportingStats(reply, simulation, seconds 10)) - let scnStats2 = reply.Task.Result - - // 100 (step_small) + 1000 (step_big) + 5 (global_info) - test <@ scnStats.AllBytes = 1105 @> - test <@ scnStats.Ok.DataTransfer.AllBytes = 1105 @> - test <@ scnStats.Fail.DataTransfer.AllBytes = 0 @> - test <@ scnStats.Ok.DataTransfer.Percent99 = 1105 @> - test <@ scnStats.GetStepStats("step_small").Ok.DataTransfer.AllBytes = 100 @> - test <@ scnStats.GetStepStats("step_big").Ok.DataTransfer.AllBytes = 1000 @> - - test <@ scnStats2.Ok.DataTransfer.AllBytes = 0 @> - test <@ scnStats2.AllBytes = 1000 @> diff --git a/tests/NBomber.IntegrationTests/ScenarioTests/EmptyScenarioTests.fs b/tests/NBomber.IntegrationTests/ScenarioTests/EmptyScenarioTests.fs deleted file mode 100644 index 37f45c02..00000000 --- a/tests/NBomber.IntegrationTests/ScenarioTests/EmptyScenarioTests.fs +++ /dev/null @@ -1,91 +0,0 @@ -module Tests.Scenario.EmptyScenarioTests - -open System.Threading.Tasks -open Xunit -open Swensen.Unquote -open NBomber -open NBomber.Errors -open NBomber.FSharp -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain - -[] -let internal ``check that EmptyScenario should fail if it has no Init and no Clean`` () = - Scenario.empty "my_empty_scenario" - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.runWithResult [] - |> Result.getError - |> function - | Scenario error -> - match error with - | EmptyScenarioWithEmptyInitAndClean _ -> () - | _ -> failwith "invalid error type" - - | _ -> failwith "invalid error type" - -[] -let ``check that EmptyScenario should be ok if it has no Init but Clean function exist`` () = - - let mutable cleanInvoked = false - - Scenario.empty "my_empty_scenario" - |> Scenario.withClean(fun _ -> task { - cleanInvoked <- true - return () - }) - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ cleanInvoked @> - -[] -let ``check that EmptyScenario should be ok if it has no Clean but Init function exist`` () = - - let mutable initInvoked = false - - Scenario.empty "my_empty_scenario" - |> Scenario.withInit(fun _ -> task { - initInvoked <- true - return () - }) - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ initInvoked @> - -[] -let ``check that EmptyScenario is not available in FinalStats`` () = - - let mutable initInvoked = false - - let scn1 = - Scenario.create("scenario_1", fun ctx -> task { - do! Task.Delay(milliseconds 10) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 1)] - - let emptyScn = - Scenario.empty "my_empty_scenario" - |> Scenario.withInit(fun _ -> task { - initInvoked <- true - return () - }) - - NBomberRunner.registerScenarios [scn1; emptyScn] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ initInvoked @> - test <@ stats.ScenarioStats.Length = 1 @> - test <@ stats.ScenarioStats[0].ScenarioName = "scenario_1" @> - diff --git a/tests/NBomber.IntegrationTests/ScenarioTests/InitCleanStopTests.fs b/tests/NBomber.IntegrationTests/ScenarioTests/InitCleanStopTests.fs deleted file mode 100644 index 6bef8008..00000000 --- a/tests/NBomber.IntegrationTests/ScenarioTests/InitCleanStopTests.fs +++ /dev/null @@ -1,297 +0,0 @@ -module Tests.Scenario.InitCleanStopTests - -open System -open System.Threading.Tasks -open Swensen.Unquote -open Xunit -open Microsoft.Extensions.Configuration -open NBomber -open NBomber.FSharp -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Domain - -//todo: add test on TestInit and TestClean should be executed only for scenario.Enabled -//todo: test on context.StopScenario("name") and check what realtime stats it provides - -[] -type TestCustomSettings = { - TargetHost: string - MsgSizeInBytes: int - PauseMs: int -} - -[] -let ``TestClean should be invoked only once and not fail runner`` () = - - let mutable cleanInvokeCounter = 0 - - let testClean = fun _ -> task { - cleanInvokeCounter <- cleanInvokeCounter + 1 - failwith "exception was not handled" - } - - Scenario.create("withTestClean test", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withClean testClean - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(2, seconds 1)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> ignore - - test <@ 1 = cleanInvokeCounter @> - -[] -let ``TestInit should propagate CustomSettings from config.json`` () = - - let mutable scnContext: IScenarioInitContext option = None - - let testInit = fun context -> task { - scnContext <- Some context - } - - Scenario.create("test_youtube", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withInit testInit - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(2, seconds 2)] - |> NBomberRunner.registerScenario - |> NBomberRunner.loadConfig "Configuration/test_config.json" - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> ignore - - let customSettings = scnContext.Value.CustomSettings.Get() - - test <@ customSettings.TargetHost = "localhost" @> - test <@ customSettings.MsgSizeInBytes = 1000 @> - -[] -let ``should be stopped via StepContext.StopScenario`` () = - - let mutable counter = 0 - let duration = seconds 5 - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - counter <- counter + 1 - - if counter = 5 then - ctx.StopScenario("test_youtube_1", "custom reason") - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(10, duration)] - - let scenario2 = - Scenario.create("test_youtube_2", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(10, duration)] - - NBomberRunner.registerScenarios [scenario1; scenario2] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let youtube1Steps = - nodeStats.ScenarioStats - |> Seq.find(fun x -> x.ScenarioName = "test_youtube_1") - - let youtube2Steps = - nodeStats.ScenarioStats - |> Seq.find(fun x -> x.ScenarioName = "test_youtube_2") - - test <@ youtube1Steps.Duration < duration @> - test <@ youtube2Steps.Duration = duration @> - -[] -let ``Test execution should be stopped if all scenarios are stopped`` () = - let mutable counter1 = 0 - let mutable counter2 = 0 - let duration = seconds 60 - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - counter1 <- counter1 + 1 - - if counter1 = 30 then - ctx.StopScenario("test_youtube_1", "custom reason") - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, duration)] - - let scenario2 = - Scenario.create("test_youtube_2", fun ctx -> task { - do! Task.Delay(milliseconds 100) - counter2 <- counter2 + 1 - - if counter2 = 60 then - ctx.StopScenario("test_youtube_2", "custom reason") - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, duration)] - - NBomberRunner.registerScenarios [scenario1; scenario2] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let youtube1Steps = nodeStats.ScenarioStats |> Seq.find(fun x -> x.ScenarioName = "test_youtube_1") - let youtube2Steps = nodeStats.ScenarioStats |> Seq.find(fun x -> x.ScenarioName = "test_youtube_2") - test <@ youtube1Steps.Duration < duration @> - test <@ youtube2Steps.Duration < duration @> - -[] -let ``withClean should provide scenario execution duration via context.ScenarioInfo`` () = - let duration = seconds 60 - let mutable plannedDuration = TimeSpan.Zero - let mutable executionDuration = TimeSpan.Zero - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - do! Task.Delay(seconds 1) - - if ctx.InvocationNumber > 2 then - ctx.StopCurrentTest("no reason") - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withInit(fun ctx -> task { - plannedDuration <- ctx.ScenarioInfo.ScenarioDuration - }) - |> Scenario.withClean(fun ctx -> task { - executionDuration <- ctx.ScenarioInfo.ScenarioDuration - }) - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 60)] - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let executionSeconds = executionDuration.Seconds - test <@ plannedDuration = duration @> - test <@ stats.ScenarioStats[0].Duration.Seconds = executionSeconds @> - test <@ stats.ScenarioStats[0].Duration < duration @> - -[] -let ``Test execution should be stopped if too many errors`` () = - let duration = seconds 60 - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.fail() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(100, duration)] - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ stats.ScenarioStats[0].Fail.Request.Count >= Constants.ScenarioMaxFailCount @> - -[] -let ``withMaxFailCount should configure MaxFailCount`` () = - let duration = seconds 60 - let maxFailCount = 1 - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - do! Task.Delay(milliseconds 500) - return Response.fail() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(1, seconds 1, duration)] - |> Scenario.withMaxFailCount maxFailCount - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ stats.ScenarioStats[0].Fail.Request.Count <> Constants.ScenarioMaxFailCount @> - test <@ stats.ScenarioStats[0].Fail.Request.Count <= 2 @> - -[] -let ``MaxFailCount should be tracked only for scenarios failures, not steps failures`` () = - let duration = seconds 2 - let maxFailCount = 1 - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - - let! fail = Step.run("fail_step", ctx, fun () -> task { - do! Task.Delay(milliseconds 10) - return Response.fail() // we return fail but this fail should not be count as scenario FailCount - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withRestartIterationOnFail false - |> Scenario.withLoadSimulations [KeepConstant(10, duration)] - |> Scenario.withMaxFailCount maxFailCount - - NBomberRunner.registerScenarios [scenario1] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ stats.ScenarioStats[0].Fail.Request.Count = 0 @> - -[] -let ``withInit should stop the test in case of error`` () = - - Scenario.create("test_youtube", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withInit(fun ctx -> task { - failwith "my error" - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(2, seconds 2)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> function - | Error error when error.Contains "Init scenario error" -> () - | _ -> failwith "error" - -[] -let ``withClean should not stop test in case of error`` () = - - Scenario.create("test_youtube", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withClean(fun ctx -> task { - failwith "my error" - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(2, seconds 1)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.isOk diff --git a/tests/NBomber.IntegrationTests/ScenarioTests/ValidationTests.fs b/tests/NBomber.IntegrationTests/ScenarioTests/ValidationTests.fs deleted file mode 100644 index ff833227..00000000 --- a/tests/NBomber.IntegrationTests/ScenarioTests/ValidationTests.fs +++ /dev/null @@ -1,108 +0,0 @@ -module Tests.Scenario.ValidationTests - -open Xunit -open Swensen.Unquote -open NBomber -open NBomber.FSharp -open NBomber.Extensions.Internal -open NBomber.Configuration -open NBomber.Contracts -open NBomber.Domain -open NBomber.Domain.DomainTypes - -[] -let ``applyScenariosSettings() should override initial settings if the scenario name is matched`` () = - - let scnName1 = "scenario_1" - let warmUp1 = seconds 30 - let duration1 = seconds 50 - - let scnName2 = "scenario_1" - let duration2 = seconds 80 - - let settings = { - ScenarioName = scnName1 - WarmUpDuration = Some warmUp1 - LoadSimulationsSettings = Some [LoadSimulation.KeepConstant(10, duration1)] - CustomSettings = Some "some data" - MaxFailCount = Some Constants.ScenarioMaxFailCount - } - - let originalScenarios = - [Scenario.create(scnName2, fun ctx -> task { return Response.ok() }) - |> Scenario.withLoadSimulations [RampingConstant(500, duration2)] ] - |> Scenario.createScenarios - |> Result.getOk - - let updatedScenarios = Scenario.applySettings [settings] originalScenarios - - test <@ updatedScenarios[0].PlanedDuration = duration1 @> - test <@ updatedScenarios[0].WarmUpDuration.Value = warmUp1 @> - test <@ updatedScenarios[0].CustomSettings = settings.CustomSettings.Value @> - -[] -let ``applyScenariosSettings() should skip applying settings when scenario name is not match`` () = - - let scnName1 = "scenario_1" - let warmUp1 = seconds 30 - let duration1 = seconds 50 - - let scnName2 = "scenario_2" - let duration2 = seconds 5 - - let settings = { - ScenarioName = scnName1 - WarmUpDuration = Some warmUp1 - LoadSimulationsSettings = Some [LoadSimulation.RampingConstant(5, duration1)] - CustomSettings = None - MaxFailCount = Some Constants.ScenarioMaxFailCount - } - - let scenario = - Scenario.create(scnName2, fun ctx -> task { return Response.ok() }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [LoadSimulation.KeepConstant(500, duration2)] - |> List.singleton - |> Scenario.createScenarios - |> Result.getOk - - let updatedScenario = Scenario.applySettings [settings] scenario - - test <@ updatedScenario.Head.WarmUpDuration = None @> - test <@ updatedScenario.Head.PlanedDuration = duration2 @> - -[] -let ``applyScenariosSettings() with no Scenarios should return empty array`` () = - let scenarios = List.empty - let settings = List.empty - Scenario.applySettings settings scenarios - |> List.isEmpty - |> Assert.True - -[] -let ``checkEmptyName should return fail if scenario has empty name`` () = - let scn = Scenario.create(" ", fun ctx -> task { return Response.ok() }) - match Scenario.Validation.checkEmptyScenarioName scn with - | Error _ -> () - | _ -> failwith "" - -[] -let ``checkDuplicateName should return fail if scenario has duplicate name`` () = - let scn1 = Scenario.create("1", fun ctx -> task { return Response.ok() }) - let scn2 = Scenario.create("1", fun ctx -> task { return Response.ok() }) - match Scenario.Validation.checkDuplicateScenarioName([scn1; scn2]) with - | Error _ -> () - | _ -> failwith "" - -[] -let ``ScenarioSettings should be validated on duplicates `` () = - - Scenario.create("1", fun ctx -> task { return Response.ok() }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 2)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.loadConfig "Configuration/duplicate_scenarios_config.json" // duplicated scenario 1 - |> NBomberRunner.run - |> Result.getError - |> fun error -> test <@ error.Contains("Scenario names are not unique in JSON config") @> diff --git a/tests/NBomber.IntegrationTests/ScenarioTests/WarmUpTests.fs b/tests/NBomber.IntegrationTests/ScenarioTests/WarmUpTests.fs deleted file mode 100644 index 307a223c..00000000 --- a/tests/NBomber.IntegrationTests/ScenarioTests/WarmUpTests.fs +++ /dev/null @@ -1,142 +0,0 @@ -module Tests.Scenario.WarmUpTests - -open System.Threading.Tasks - -open Serilog -open Serilog.Sinks.InMemory -open Swensen.Unquote -open Xunit - -open NBomber -open NBomber.FSharp -open NBomber.Extensions.Internal -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Errors -open NBomber.Domain - -[] -let ``Warmup should have no effect on stats`` () = - - Scenario.create("warmup test", fun ctx -> task { - - let! okStep = Step.run("ok step", ctx, fun _ -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - - let! failStep = Step.run("fail step", ctx, fun _ -> task { - do! Task.Delay(milliseconds 100) - return Response.fail() - }) - - return Response.ok() - }) - |> Scenario.withWarmUpDuration(seconds 1) - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let okSt = nodeStats.ScenarioStats[0].GetStepStats("ok step") - let failSt = nodeStats.ScenarioStats[0].GetStepStats("fail step") - - test <@ okSt.Ok.Request.Count <= 10 @> - test <@ okSt.Fail.Request.Count = 0 @> - test <@ failSt.Ok.Request.Count = 0 @> - test <@ failSt.Fail.Request.Count <= 10 @> - -[] -let ``withoutWarmUp should hide the warmup info on the console`` () = - - let mutable warmupRun = false - let inMemorySink = new InMemorySink() - - Scenario.create("1", fun ctx -> task { - if ctx.ScenarioInfo.ScenarioOperation = ScenarioOperation.WarmUp then - warmupRun <- true - - do! Task.Delay(seconds 0.5) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 1)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withLoggerConfig(fun () -> LoggerConfiguration().WriteTo.Sink(inMemorySink)) - |> NBomberRunner.withoutReports - |> NBomberRunner.runWithArgs ["disposeLogger=false"] - |> ignore - - test <@ warmupRun = false @> - test <@ inMemorySink.LogEvents |> Seq.exists(fun x -> x.MessageTemplate.Text.Contains "Starting warm up...") |> not @> - test <@ inMemorySink.LogEvents |> Seq.exists(fun x -> x.MessageTemplate.Text.Contains "Starting bombing...") @> - -[] -let ``withWarmUpDuration should run warmup only for specified scenarios`` () = - - let mutable warmupStep1 = false - let mutable warmupStep2 = false - let mutable bombingStep1 = false - let mutable bombingStep2 = false - - let scn1 = - Scenario.create("1", fun ctx -> task { - if ctx.ScenarioInfo.ScenarioOperation = ScenarioOperation.WarmUp then - warmupStep1 <- true - - if ctx.ScenarioInfo.ScenarioOperation = ScenarioOperation.Bombing then - bombingStep1 <- true - - do! Task.Delay(seconds 0.5) - return Response.ok() - }) - |> Scenario.withWarmUpDuration(seconds 2) - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 2)] - - let scn2 = - Scenario.create("2", fun ctx -> task { - if ctx.ScenarioInfo.ScenarioOperation = ScenarioOperation.WarmUp then - warmupStep2 <- true - - if ctx.ScenarioInfo.ScenarioOperation = ScenarioOperation.Bombing then - bombingStep2 <- true - - do! Task.Delay(seconds 0.5) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 2)] - - NBomberRunner.registerScenarios [scn1; scn2] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> ignore - - test <@ warmupStep1 = true @> - test <@ warmupStep2 = false @> - test <@ bombingStep1 = true @> - test <@ bombingStep2 = true @> - -[] -let ``warm-up duration should be equal or smaller that scenario's duration`` () = - - let scn = - Scenario.create("1", fun ctx -> task { - do! Task.Delay(seconds 0.5) - return Response.ok() - }) - |> Scenario.withWarmUpDuration(seconds 5) // we set bigger duration than the scnDuration - |> Scenario.withLoadSimulations [KeepConstant(1, seconds 2)] - - NBomberRunner.registerScenarios [scn] - |> NBomberRunner.withoutReports - |> NBomberRunner.runWithResult [] - |> Result.getError - |> function - | Scenario error -> - match error with - | WarmUpDurationIsBiggerScnDuration _ -> () - | _ -> failwith "invalid error type" - - | _ -> failwith "invalid error type" diff --git a/tests/NBomber.IntegrationTests/StatisticsTests.fs b/tests/NBomber.IntegrationTests/StatisticsTests.fs deleted file mode 100644 index 07035eb3..00000000 --- a/tests/NBomber.IntegrationTests/StatisticsTests.fs +++ /dev/null @@ -1,654 +0,0 @@ -module Tests.Statistics - -open System -open System.IO -open System.Collections.Generic -open System.Threading.Tasks - -open FsCheck.Xunit -open HdrHistogram -open Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Contracts.Internal -open NBomber.Extensions.Internal -open NBomber.Domain -open NBomber.Domain.Stats -open NBomber.Domain.Stats.Statistics -open NBomber.Domain.Stats.RawMeasurementStats -open NBomber.FSharp -open Tests.TestHelper - -module ScenarioStatsTests = - - let internal baseRawStepStats ={ - MinMicroSec = Int32.MaxValue - MaxMicroSec = 0 - MinBytes = Int64.MaxValue - MaxBytes = 0 - RequestCount = 0 - LessOrEq800 = 0 - More800Less1200 = 0 - MoreOrEq1200 = 0 - AllBytes = 0L - LatencyHistogram = LongHistogram(highestTrackableValue = Constants.MaxTrackableStepLatency, numberOfSignificantValueDigits = 3) - DataTransferHistogram = - LongHistogram( - highestTrackableValue = Constants.MaxTrackableStepResponseSize, - numberOfSignificantValueDigits = 3 - ) - StatusCodes = Dictionary() - } - - let internal baseStepStatsRawData = RawMeasurementStats.empty("step") - - let baseLoadSimulationStats = { SimulationName = "simulation name"; Value = 1 } - - [] - let ``ScenarioStats RequestCount should sum of OkCount and FailCount from all steps`` - (okCount: int, failCount: int) = - - let okStats = { baseRawStepStats with RequestCount = okCount } - let failStats = { baseRawStepStats with RequestCount = failCount } - - let stepsData = { Name = Constants.ScenarioGlobalInfo; OkStats = okStats; FailStats = failStats } - - let scenarioStats = - ScenarioStats.create - "scenario" - [| stepsData |] - baseLoadSimulationStats - OperationType.Complete - (seconds 1) - (seconds 1) - - test <@ scenarioStats.Ok.Request.Count + scenarioStats.Fail.Request.Count = okCount + failCount @> - - [] - let ``ScenarioStats AllBytes should sum AllBytes of OkStats and FailStats from all steps`` - (okAllBytes: int64, failAllBytes: int64) = - - let okStats = { baseRawStepStats with AllBytes = okAllBytes } - let failStats = { baseRawStepStats with AllBytes = failAllBytes } - - let stepsData = { Name = Constants.ScenarioGlobalInfo; OkStats = okStats; FailStats = failStats } - - let scenarioStats = - ScenarioStats.create - "scenario" - [| stepsData |] - baseLoadSimulationStats - OperationType.Complete - (seconds 1) - (seconds 1) - - test <@ ScenarioStats.calcAllBytes scenarioStats = okAllBytes + failAllBytes @> - - [] - let ``ScenarioStats OkCount should be separated from OkCount of steps`` (okCount1: int, okCount2: int) = - - let okStats1 = { baseRawStepStats with RequestCount = okCount1 } - let okStats2 = { baseRawStepStats with RequestCount = okCount2 } - let stepsData1 = { baseStepStatsRawData with Name = Constants.ScenarioGlobalInfo; OkStats = okStats1 } - let stepsData2 = { baseStepStatsRawData with OkStats = okStats2 } - - let scenarioStats = - ScenarioStats.create - "scenario" - [| stepsData1; stepsData2 |] - baseLoadSimulationStats - OperationType.Complete - (seconds 1) - (seconds 1) - - test <@ scenarioStats.Ok.Request.Count = okCount1 @> - test <@ scenarioStats.StepStats[0].Ok.Request.Count = okCount2 @> - - [] - let ``ScenarioStats FailCount should be separated from FailCount of steps`` (failCount1: int, failCount2: int) = - - let okStats1 = { baseRawStepStats with RequestCount = failCount1 } - let okStats2 = { baseRawStepStats with RequestCount = failCount2 } - let stepsData1 = { baseStepStatsRawData with Name = Constants.ScenarioGlobalInfo; FailStats = okStats1 } - let stepsData2 = { baseStepStatsRawData with FailStats = okStats2 } - - let scenarioStats = - ScenarioStats.create - "scenario" - [| stepsData1; stepsData2 |] - baseLoadSimulationStats - OperationType.Complete - (seconds 1) - (seconds 1) - - test <@ scenarioStats.Fail.Request.Count = failCount1 @> - test <@ scenarioStats.StepStats[0].Fail.Request.Count = failCount2 @> - - - [] - let ``ScenarioStats LatencyCount should sum of LatencyCount from all steps fro Ok and Fail stats`` - (less800: int, more800Less1200: int, more1200: int) = - - let okStats = { - baseRawStepStats with - LessOrEq800 = less800 - More800Less1200 = more800Less1200 - MoreOrEq1200 = more1200 - } - - let failStats = { - baseRawStepStats with - LessOrEq800 = less800 - More800Less1200 = more800Less1200 - MoreOrEq1200 = more1200 - } - - let stepStatsRawData = - { baseStepStatsRawData with Name = Constants.ScenarioGlobalInfo; OkStats = okStats; FailStats = failStats } - - let scenarioStats = - ScenarioStats.create - "scenario" - [| stepStatsRawData |] - baseLoadSimulationStats - OperationType.Complete - (seconds 1) - (seconds 1) - - test <@ scenarioStats.Ok.Latency.LatencyCount.LessOrEq800 = less800 @> - test <@ scenarioStats.Ok.Latency.LatencyCount.More800Less1200 = more800Less1200 @> - test <@ scenarioStats.Ok.Latency.LatencyCount.MoreOrEq1200 = more1200 @> - - test <@ scenarioStats.Fail.Latency.LatencyCount.LessOrEq800 = less800 @> - test <@ scenarioStats.Fail.Latency.LatencyCount.More800Less1200 = more800Less1200 @> - test <@ scenarioStats.Fail.Latency.LatencyCount.MoreOrEq1200 = more1200 @> - -module NodeStatsTests = - - let baseNodeInfo = { - MachineName = "machine name" - NodeType = NodeType.SingleNode - CurrentOperation = OperationType.Complete - OS = Environment.OSVersion.ToString() - DotNetVersion = "6.0" - Processor = "processor" - CoresCount = 4 - NBomberVersion = "2.0" - } - - let baseTestInfo = - { SessionId = "session id"; TestSuite = "test suite"; TestName = "test name"; ClusterId = "" } - - let baseLatencyCount = { LessOrEq800 = 1; More800Less1200 = 1; MoreOrEq1200 = 1 } - - let baseLoadSimulationStats = { SimulationName = "simulation name"; Value = 1 } - - let baseScenarioStats = { - ScenarioStats.ScenarioName = "scenario name" - Ok = MeasurementStats.empty - Fail = MeasurementStats.empty - StepStats = Array.empty - LoadSimulationStats = baseLoadSimulationStats - CurrentOperation = OperationType.Complete - AllRequestCount = 0 - AllOkCount = 0 - AllFailCount = 0 - AllBytes = 0 - Duration = TimeSpan.Zero - } - - [] - let ``NodeStats RequestCount should be sum of Ok + Fail of each scenario`` - (okCount: int, failCount: int, allBytes: int64) = - - let scenario1 = { baseScenarioStats with AllRequestCount = okCount; AllOkCount = okCount; AllBytes = allBytes } - let scenario2 = { baseScenarioStats with AllRequestCount = failCount; AllFailCount = failCount; AllBytes = allBytes } - - let nodeStats = - NodeStats.create baseTestInfo baseNodeInfo [| scenario1; scenario2 |] Array.empty - - test <@ nodeStats.AllRequestCount = okCount + failCount @> - test <@ nodeStats.AllOkCount = okCount @> - test <@ nodeStats.AllFailCount = failCount @> - test <@ nodeStats.AllBytes = allBytes + allBytes @> - - [] - let ``NodeStats Duration should be duration of the longest scenario`` () = - let scenario1 = { baseScenarioStats with Duration = seconds 10 } - let scenario2 = { baseScenarioStats with Duration = seconds 20 } - - let nodeStats = - NodeStats.create baseTestInfo baseNodeInfo [| scenario1; scenario2 |] Array.empty - - test <@ nodeStats.Duration = seconds 20 @> - - [] - let ``NodeStats should be calculated during test execution`` () = - - let okScenario = - Scenario.create("ok scenario", fun ctx -> task { - do! Task.Delay(milliseconds 500) - return Response.ok(sizeBytes = 100) - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 0.5, during = seconds 10)] - - let failScenario = - Scenario.create("fail scenario", fun ctx -> task { - do! Task.Delay(milliseconds 500) - return Response.fail(statusCode = "10", sizeBytes = 10, message = "reason") - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 0.5, during = seconds 10)] - - NBomberRunner.registerScenarios [okScenario; failScenario] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let sc0 = stats.GetScenarioStats("ok scenario") - let sc1 = stats.GetScenarioStats("fail scenario") - test <@ stats.Duration = seconds 10 @> - - test <@ stats.AllRequestCount = 40 @> - - test <@ stats.AllOkCount = 20 @> - test <@ stats.AllFailCount = 20 @> - test <@ stats.AllBytes = sc0.Ok.DataTransfer.AllBytes + sc1.Fail.DataTransfer.AllBytes @> - - [] - let ``NodeStats should support int64 data sizes`` () = - - let sizeBytes = 3000000000L - let okScenario = - Scenario.create("ok scenario", fun ctx -> task { - do! Task.Delay(milliseconds 500) - return Response.ok(sizeBytes = sizeBytes) - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 0.5, during = seconds 2)] - - NBomberRunner.registerScenarios [okScenario] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let sc = stats.GetScenarioStats("ok scenario") - test <@ stats.Duration = seconds 2 @> - - test <@ stats.AllRequestCount = 4 @> - - test <@ stats.AllOkCount = 4 @> - test <@ stats.AllFailCount = 0 @> - test <@ stats.AllBytes = 4L * sizeBytes @> - test <@ sc.Ok.DataTransfer.MinBytes = sizeBytes @> - test <@ sc.Ok.DataTransfer.MaxBytes = sizeBytes @> - -module StepStatsRawData = - - [] - let ``addStepResult should take client response latency if it set`` (isClient: bool, latencyMs: uint32) = - - let emptyData = RawMeasurementStats.empty("step_name") - let clientResMs = if isClient then float latencyMs else 0.0 - let stepResMs = 42.0 - - let clientResponse = { - StatusCode = "" - IsError = false - Message = "" - SizeBytes = 10 - LatencyMs = clientResMs - Payload = None - } - - let stepResult = { - Name = "step_name" - ClientResponse = clientResponse - CurrentTimeBucket = TimeSpan.Zero - Latency = milliseconds stepResMs - } - - RawMeasurementStats.addMeasurement emptyData stepResult 10 - - let realMin = if clientResMs > 0.0 then clientResMs else stepResMs - - let min = - emptyData.OkStats.MinMicroSec - |> float - |> NBomber.Converter.fromMicroSecToMs - - test <@ min = realMin @> - - [] - let ``addStepResult should properly calc latency count`` (latencies: uint32 list) = - - let data = RawMeasurementStats.empty("step_name") - - let latencies = latencies |> List.filter(fun x -> x > 0u) - - latencies - |> List.iter(fun latency -> - let clientResponse = { - StatusCode = "" - IsError = false - Message = "" - SizeBytes = 10 - LatencyMs = float latency - Payload = None - } - - let stepResponse = { - Name = "step_name" - ClientResponse = clientResponse - CurrentTimeBucket = TimeSpan.Zero - Latency = seconds 0 - } - - RawMeasurementStats.addMeasurement data stepResponse 10 - ) - - let lessOrEq800 = latencies |> Seq.filter(fun x -> x <= 800u) |> Seq.length - let more800Less1200 = latencies |> Seq.filter(fun x -> x > 800u && x < 1200u) |> Seq.length - let moreOrEq1200 = latencies |> Seq.filter(fun x -> x >= 1200u) |> Seq.length - - test <@ data.OkStats.LessOrEq800 = lessOrEq800 @> - test <@ data.OkStats.More800Less1200 = more800Less1200 @> - test <@ data.OkStats.MoreOrEq1200 = moreOrEq1200 @> - - [] - let ``addStepResult should properly handle OkStats and FailStats`` (latencies: (bool * uint32) list) = - - let data = RawMeasurementStats.empty("step_name") - - let latencies = - latencies - |> List.filter(fun (_, latency) -> latency > 0u) - |> List.map(fun (isOk, latency) -> isOk, latency |> float) - - latencies - |> Seq.iter(fun (isOk, latency) -> - let clientResponse = { - StatusCode = "" - IsError = not isOk - Message = "" - SizeBytes = 10 - LatencyMs = 0 - Payload = None - } - - let stepResponse = { // only stepResponse latency will be included - Name = "step_name" - ClientResponse = clientResponse - CurrentTimeBucket = TimeSpan.Zero - Latency = milliseconds latency - } - - RawMeasurementStats.addMeasurement data stepResponse 10 - ) - - // calc OkStats - let okLatencies = latencies |> Seq.filter(fun (isOk, _) -> isOk) - let okCount = okLatencies |> Seq.length - let okLessOrEq800 = - okLatencies - |> Seq.filter(fun (_, latency) -> latency <= 800.0) - |> Seq.length - - let okMinStats = if okCount > 0 then okLatencies |> Seq.map snd |> Seq.min else 0.0 - let okMaxStats = if okCount > 0 then okLatencies |> Seq.map snd |> Seq.max else 0.0 - - // calc FailStats - let failLatencies = latencies |> Seq.filter(fun (isOk, _) -> isOk = false) - let failCount = failLatencies |> Seq.length - - let failLessOrEq800 = - failLatencies - |> Seq.filter(fun (_, latency) -> latency <= 800.0) - |> Seq.length - - let failMinStats = if failCount > 0 then failLatencies |> Seq.map snd |> Seq.min else 0.0 - let failMaxStats = if failCount > 0 then failLatencies |> Seq.map snd |> Seq.max else 0.0 - let okMin = if okCount > 0 then data.OkStats.MinMicroSec |> float |> NBomber.Converter.fromMicroSecToMs else 0.0 - let okMax = if okCount > 0 then data.OkStats.MaxMicroSec |> float |> NBomber.Converter.fromMicroSecToMs else 0.0 - let failMin = if failCount > 0 then data.FailStats.MinMicroSec |> float |> NBomber.Converter.fromMicroSecToMs else 0.0 - let failMax = if failCount > 0 then data.FailStats.MaxMicroSec |> float |> NBomber.Converter.fromMicroSecToMs else 0.0 - - test <@ data.OkStats.RequestCount = okCount @> - test <@ data.OkStats.LessOrEq800 = okLessOrEq800 @> - test <@ okMin = okMinStats @> - test <@ okMax = okMaxStats @> - - test <@ data.FailStats.RequestCount = failCount @> - test <@ data.FailStats.LessOrEq800 = failLessOrEq800 @> - test <@ failMin = failMinStats @> - test <@ failMax = failMaxStats @> - - [] - let ``addStepResult should properly calc response sizes`` (responseSizes: (bool * uint32) list) = - - let data = RawMeasurementStats.empty("step") - - let responseSizes = - responseSizes - |> List.filter(fun (_, resSize) -> resSize > 0u) - |> List.map(fun (isOk, resSize) -> isOk, resSize |> int) - - responseSizes - |> Seq.iter(fun (isOk, resSize) -> - let clientResponse = { - StatusCode = "" - IsError = not isOk - Message = "" - SizeBytes = resSize - LatencyMs = 1.0 - Payload = None - } - - let stepResponse = { - Name = "step" - ClientResponse = clientResponse - CurrentTimeBucket = TimeSpan.Zero - Latency = seconds 0 - } - - RawMeasurementStats.addMeasurement data stepResponse resSize - ) - - // calc OkStatsData - let okResponses = responseSizes |> Seq.filter(fun (isOk, _) -> isOk) - - let okCount = okResponses |> Seq.length - - let okMinBytes = if okCount > 0 then okResponses |> Seq.map snd |> Seq.min else 0 - let okMaxBytes = if okCount > 0 then okResponses |> Seq.map snd |> Seq.max else 0 - let okAllBytes = int64(if okCount > 0 then okResponses |> Seq.map snd |> Seq.sum else 0) - - // calc FailStatsData - let failResponses = responseSizes |> Seq.filter(fun (isOk, _) -> isOk = false) - let failCount = failResponses |> Seq.length - let failMinBytes = if failCount > 0 then failResponses |> Seq.map snd |> Seq.min else 0 - let failMaxBytes = if failCount > 0 then failResponses |> Seq.map snd |> Seq.max else 0 - let failAllBytes = int64(if failCount > 0 then failResponses |> Seq.map snd |> Seq.sum else 0) - let okMin = if okCount > 0 then data.OkStats.MinBytes else 0 - let okMax = if okCount > 0 then data.OkStats.MaxBytes else 0 - let failMin = if failCount > 0 then data.FailStats.MinBytes else 0 - let failMax = if failCount > 0 then data.FailStats.MaxBytes else 0 - - test <@ data.OkStats.RequestCount = okCount @> - test <@ okMin = okMinBytes @> - test <@ okMax = okMaxBytes @> - test <@ data.OkStats.AllBytes = okAllBytes @> - - test <@ data.FailStats.RequestCount = failCount @> - test <@ failMin = failMinBytes @> - test <@ failMax = failMaxBytes @> - test <@ data.FailStats.AllBytes = failAllBytes @> - -[] -let ``NodeStats should be calculated properly`` () = - - let scenario = - Scenario.create("realtime stats scenario", fun ctx -> task { - - let! okStep = Step.run("ok step", ctx, fun () -> task { - do! Task.Delay(milliseconds 500) - return Response.ok(sizeBytes = 100) - }) - - let! failStep = Step.run("fail step", ctx, fun () -> task { - do! Task.Delay(milliseconds 500) - return Response.fail(message = "reason 1", statusCode = "10", sizeBytes = 10) - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 1, during = seconds 5)] - - NBomberRunner.registerScenarios [ scenario ] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let scnStats = stats.ScenarioStats[0] - let okStep = scnStats.GetStepStats("ok step") - let failStep = scnStats.GetStepStats("fail step") - - test <@ okStep.Ok.Request.Count = 5 @> - test <@ okStep.Ok.Request.RPS = 1 @> - - test <@ okStep.Ok.DataTransfer.MinBytes = 100 @> - test <@ okStep.Fail.Request.Count = 0 @> - - test <@ failStep.Fail.Request.Count = 5 @> - test <@ failStep.Fail.Request.RPS = 1 @> - - test <@ failStep.Fail.DataTransfer.MinBytes = 10 @> - test <@ failStep.Ok.Request.Count = 0 @> - -[] -let ``NodeStats ReportFiles should contain report content`` () = - - let scenario = - Scenario.create("realtime stats scenario", fun ctx -> task { - - let! okStep = Step.run("ok step", ctx, fun () -> task { - do! Task.Delay(milliseconds 500) - return Response.ok(sizeBytes = 100) - }) - - let! failStep = Step.run("fail step", ctx, fun () -> task { - do! Task.Delay(milliseconds 500) - return Response.fail(message = "reason 1", statusCode = "10", sizeBytes = 10) - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 5)] - - NBomberRunner.registerScenarios [scenario] - |> NBomberRunner.withReportFolder "./reports/node_stats/1" - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let reportFile = stats.ReportFiles[0] - let fileContent = File.ReadAllText(reportFile.FilePath) - - test <@ reportFile.ReportContent = fileContent @> - -[] -let ``status codes should be calculated properly`` () = - - let scenario = - Scenario.create("realtime stats scenario", fun ctx -> task { - - let! okStep = Step.run("ok step", ctx, fun () -> task { - do! Task.Delay(milliseconds 100) - return Response.ok(statusCode = "10") - }) - - let! okStepNoStatus = Step.run("ok step no status", ctx, fun () -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - - let! failStep = Step.run("fail step", ctx, fun () -> task { - do! Task.Delay(milliseconds 100) - return Response.fail(statusCode = "-10") - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 10)] - - NBomberRunner.registerScenarios [ scenario ] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let allCodes = stats.ScenarioStats[0].Ok.StatusCodes |> Array.append(stats.ScenarioStats[0].Fail.StatusCodes) - let okStCodes = stats.ScenarioStats[0].GetStepStats("ok step").Ok.StatusCodes - let okNoStatusStCodes = stats.ScenarioStats[0].GetStepStats("ok step no status").Ok.StatusCodes - let failStCodes = stats.ScenarioStats[0].GetStepStats("fail step").Fail.StatusCodes - - test <@ allCodes - |> Seq.find(fun x -> x.StatusCode = "10" || x.StatusCode = "-10") - |> fun x -> x.Count > 10 @> - - test <@ okStCodes - |> Seq.find(fun x -> x.StatusCode = "10") - |> fun error -> error.Count > 10 @> - - test <@ failStCodes - |> Seq.find(fun x -> x.StatusCode = "-10") - |> fun error -> error.Count > 10 @> - - test <@ Array.isEmpty okNoStatusStCodes @> - -[] -let ``StatusCodeStats merge function returns sorted results`` () = - - let stats: StatusCodeStats[] = [| - { StatusCode = "50"; IsError = false; Message = String.Empty; Count = 1 } - { StatusCode = "80"; IsError = false; Message = String.Empty; Count = 1 } - { StatusCode = "10"; IsError = false; Message = String.Empty; Count = 1 } - |] - - let result = - stats - |> Statistics.StatusCodeStats.merge - |> Array.map(fun x -> x.StatusCode) - - test <@ [| "10"; "50"; "80" |] = result @> - -[] -let ``Stats should be calculated without Pause simulation`` () = - - let scenario = - Scenario.create("realtime stats scenario", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [ - Pause(during = seconds 10) - Inject(rate = 100, interval = seconds 1, during = seconds 1) - ] - - NBomberRunner.registerScenarios [ scenario ] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let ok = stats.GetScenarioStats("realtime stats scenario").Ok - let duration = stats.GetScenarioStats("realtime stats scenario").Duration - - test <@ ok.Request.RPS = 100 @> - test <@ ok.Request.Count = 100 @> - test <@ duration = seconds 11 @> // inject (1 sec) + pause (10 sec) diff --git a/tests/NBomber.IntegrationTests/StepTests/BasicStepTests.fs b/tests/NBomber.IntegrationTests/StepTests/BasicStepTests.fs deleted file mode 100644 index 808d4a54..00000000 --- a/tests/NBomber.IntegrationTests/StepTests/BasicStepTests.fs +++ /dev/null @@ -1,477 +0,0 @@ -module Tests.Step.BasicStepTests - -open System -open System.Collections.Generic -open System.Threading -open System.Threading.Tasks - -open FsCheck.Xunit -open Xunit -open Swensen.Unquote - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.FSharp -open NBomber.Extensions.Internal - -[] -let ``Response Ok and Fail should be properly count`` () = - - let mutable okCnt = 0 - let mutable failCnt = 0 - - Scenario.create("count test", fun ctx -> task { - - let! ok = Step.run("ok step", ctx, fun () -> task { - do! Task.Delay(milliseconds 100) - okCnt <- okCnt + 1 - return Response.ok() - }) - - let! fail = Step.run("fail step", ctx, fun () -> task { - do! Task.Delay(milliseconds 100) - failCnt <- failCnt + 1 - return Response.fail() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 1, during = seconds 2)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let okSt = nodeStats.ScenarioStats[0].GetStepStats("ok step") - let failSt = nodeStats.ScenarioStats[0].GetStepStats("fail step") - - test <@ okSt.Ok.Request.Count = 2 @> - test <@ okSt.Fail.Request.Count = 0 @> - test <@ failSt.Ok.Request.Count = 0 @> - test <@ failSt.Fail.Request.Count = 2 @> - - test <@ nodeStats.ScenarioStats[0].Ok.Request.Count = 0 @> - test <@ nodeStats.ScenarioStats[0].Fail.Request.Count = 2 @> - -[] -[] -let ``Min/Mean/Max/RPS/DataTransfer should be properly count`` () = - - Scenario.create("latency count test", fun ctx -> backgroundTask { - do! Task.Delay(milliseconds 100) - return Response.ok(sizeBytes = 1000) - }) - |> Scenario.withWarmUpDuration(seconds 1) - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 10)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let stats = nodeStats.ScenarioStats[0] - let ok = stats.Ok - - test <@ ok.Request.RPS >= 8 @> - test <@ ok.Request.RPS <= 10 @> - test <@ ok.Latency.MinMs <= 110 && ok.Latency.MinMs >= 99 @> - test <@ ok.Latency.MeanMs <= 112 @> - test <@ ok.Latency.MaxMs <= 117 @> - test <@ ok.Latency.Percent50 <= 113 @> - test <@ ok.Latency.Percent75 <= 114 @> - test <@ ok.Latency.Percent95 <= 115 @> - test <@ ok.Latency.Percent99 <= 116 @> - test <@ ok.DataTransfer.MinBytes = 1000 @> - test <@ ok.DataTransfer.AllBytes >= 80_000L && ok.DataTransfer.AllBytes <= 100_000L @> - -// [] -// let ``can be duplicated to introduce repeatable behaviour`` () = -// -// let mutable repeatCounter = 0 -// -// let repeatStep = Step.create("repeat_step", fun context -> task { -// do! Task.Delay(milliseconds 100) -// let number = context.GetPreviousStepResponse() -// -// if number = 1 then repeatCounter <- repeatCounter + 1 -// -// return Response.ok(number + 1) -// }) -// -// Scenario.create "latency count test" [repeatStep; repeatStep] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 3)] -// |> NBomberRunner.registerScenario -// |> NBomberRunner.withoutReports -// |> NBomberRunner.run -// |> ignore -// -// test <@ repeatCounter > 5 @> - -[] -let ``NBomber shouldn't stop execution scenario if too many failed results on a warm-up`` () = - - Scenario.create("scenario", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.fail() - }) - |> Scenario.withWarmUpDuration(seconds 5) - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 10)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.runWithResult Array.empty - |> Result.getOk - |> ignore - -[] -let ``NBomber should allow to set custom response latency and handle it properly`` () = - - Scenario.create("scenario", fun ctx -> task { - do! Task.Delay(milliseconds 100) - return Response.ok(latencyMs = 2_000.0) // set custom latency - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [Inject(rate = 1, interval = seconds 1, during = seconds 3)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - let scnStats = nodeStats.ScenarioStats[0] - - test <@ scnStats.Ok.Request.Count = 3 @> - test <@ scnStats.Ok.Request.RPS = 1.0 @> - test <@ scnStats.Ok.Latency.MinMs <= 2_001.0 @> - -[] -let ``context StopTest should stop all scenarios`` () = - - let mutable counter = 0 - let duration = seconds 42 - - let scenario1 = - Scenario.create("test_youtube_1", fun ctx -> task { - do! Task.Delay(milliseconds 100) - counter <- counter + 1 - - if counter >= 30 then - ctx.StopCurrentTest(reason = "custom reason") - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(10, duration)] - - let scenario2 = - Scenario.create("test_youtube_2", fun ctx -> task { - do! Task.Delay(milliseconds 100) - counter <- counter + 1 - - if counter >= 30 then - ctx.StopCurrentTest(reason = "custom reason") - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(10, duration)] - - NBomberRunner.registerScenarios [scenario1; scenario2] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun nodeStats -> - nodeStats.ScenarioStats - |> Seq.find(fun x -> x.ScenarioName = "test_youtube_1") - |> fun x -> test <@ x.Duration < duration @> - -[] -let ``NBomber should reset step invocation number after warm-up`` () = - - let mutable counter = 0 - - Scenario.create("scenario", fun ctx -> task { - do! Task.Delay(seconds 1) - counter <- ctx.InvocationNumber - return Response.ok() - }) - |> Scenario.withWarmUpDuration(seconds 10) - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 10)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> ignore - - test <@ counter >= 5 && counter <= 11 @> - -[] -[] -let ``NBomber should handle invocation number per step following shared-nothing approach`` () = - - let data = Dictionary() - - Scenario.create("scenario", fun ctx -> task { - do! Task.Delay(seconds 1) - - data[ctx.ScenarioInfo.ThreadNumber] <- ctx.InvocationNumber - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 10, during = seconds 10)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> ignore - - // hack to fix the issue with iterating over mutable dictionary - // it show up on slow machine - Task.Delay(seconds 10).Wait() - - let maxNumber = data.Values |> Seq.maxBy(id) - - test <@ maxNumber >= 5 && maxNumber <= 11 @> - -[] -let ``NBomber by default should reset scenario iteration on step fail`` () = - - let mutable step3Invoked = false - - Scenario.create("scenario", fun ctx -> task { - - let! step1 = Step.run("step1", ctx, fun () -> task { - return Response.ok() - }) - - let! step2 = Step.run("step2", ctx, fun () -> task { - return Response.fail() - }) - - let! step3 = Step.run("step3", ctx, fun () -> task { - step3Invoked <- true // this step should not be invoked - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ step3Invoked = false @> - test <@ stats.ScenarioStats[0].Ok.Request.Count = 0 @> - test <@ stats.ScenarioStats[0].Fail.Request.Count > 0 @> - test <@ stats.ScenarioStats[0].Fail.Request.Count = stats.ScenarioStats[0].GetStepStats("step2").Fail.Request.Count @> - test <@ stats.ScenarioStats[0].GetStepStats("step1").Ok.Request.Count > 0 @> - -[] -let ``withRestartIterationOnFail should allow to configure reset = false`` () = - - let mutable step3Invoked = false - - Scenario.create("scenario", fun ctx -> task { - - let! step1 = Step.run("step1", ctx, fun () -> task { - return Response.ok() - }) - - let! step2 = Step.run("step2", ctx, fun () -> task { - return Response.fail() - }) - - let! step3 = Step.run("step3", ctx, fun () -> task { - step3Invoked <- true // this step should be invoked - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - |> Scenario.withRestartIterationOnFail false - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - test <@ step3Invoked = true @> - test <@ stats.ScenarioStats[0].Ok.Request.Count > 0 @> - test <@ stats.ScenarioStats[0].Fail.Request.Count = 0 @> - test <@ stats.ScenarioStats[0].GetStepStats("step1").Ok.Request.Count > 0 @> - test <@ stats.ScenarioStats[0].GetStepStats("step2").Fail.Request.Count > 0 @> - test <@ stats.ScenarioStats[0].GetStepStats("step3").Ok.Request.Count > 0 @> - -[] -let ``operation timeout should be tracked properly`` () = - - let scn1 = - Scenario.create("scenario_1", fun ctx -> task { - - let! step1 = Step.run("step1", ctx, fun () -> task { - use timeout = new CancellationTokenSource() - timeout.CancelAfter 50 - - do! Task.Delay(100, timeout.Token) - - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - - let scn2 = - Scenario.create("scenario_2", fun ctx -> task { - use timeout = new CancellationTokenSource() - timeout.CancelAfter 50 - - do! Task.Delay(100, timeout.Token) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - - NBomberRunner.registerScenarios [scn1; scn2] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let scn1Stats = stats.GetScenarioStats("scenario_1") - let scn2Stats = stats.GetScenarioStats("scenario_2") - - test <@ scn1Stats.Fail.StatusCodes[0].IsError @> - test <@ scn1Stats.Fail.StatusCodes[0].StatusCode = Constants.TimeoutStatusCode @> - test <@ scn1Stats.Fail.StatusCodes[0].Count = scn1Stats.Fail.Request.Count @> - - test <@ scn2Stats.Fail.StatusCodes[0].IsError @> - test <@ scn2Stats.Fail.StatusCodes[0].StatusCode = Constants.TimeoutStatusCode @> - test <@ scn2Stats.Fail.StatusCodes[0].Count = scn2Stats.Fail.Request.Count @> - -[] -let ``unhandled exceptions should have a proper status code`` () = - - let scn1 = - Scenario.create("scenario_1", fun ctx -> task { - - let! step1 = Step.run("step1", ctx, fun () -> task { - - do! Task.Delay 100 - - failwith "my exception" - - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - - let scn2 = - Scenario.create("scenario_2", fun ctx -> task { - - do! Task.Delay 100 - - failwith "my exception" - - return Response.ok() - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - - NBomberRunner.registerScenarios [scn1; scn2] - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let scn1Stats = stats.GetScenarioStats("scenario_1") - let scn2Stats = stats.GetScenarioStats("scenario_2") - - test <@ scn1Stats.Fail.StatusCodes[0].IsError @> - test <@ scn1Stats.Fail.StatusCodes[0].StatusCode = Constants.UnhandledExceptionCode @> - test <@ scn1Stats.Fail.StatusCodes[0].Count = scn1Stats.Fail.Request.Count @> - test <@ scn1Stats.Fail.StatusCodes[0].Message = "my exception" @> - - test <@ scn2Stats.Fail.StatusCodes[0].IsError @> - test <@ scn2Stats.Fail.StatusCodes[0].StatusCode = Constants.UnhandledExceptionCode @> - test <@ scn2Stats.Fail.StatusCodes[0].Count = scn2Stats.Fail.Request.Count @> - test <@ scn1Stats.Fail.StatusCodes[0].Message = "my exception" @> - -[] -let ``Response Ok message should be presented in status codes`` () = - - Scenario.create("scenario", fun ctx -> task { - - let! step = Step.run("step", ctx, fun () -> task { - do! Task.Delay 100 - return Response.ok(statusCode = "200", message = "my message 1") - }) - - return Response.ok(statusCode = "300", message = "my message 2") - }) - |> Scenario.withoutWarmUp - |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 1)] - |> NBomberRunner.registerScenario - |> NBomberRunner.withoutReports - |> NBomberRunner.run - |> Result.getOk - |> fun stats -> - let scnStats = stats.GetScenarioStats("scenario") - - test <@ scnStats.Ok.StatusCodes[0].IsError = false @> - test <@ scnStats.Ok.StatusCodes[0].StatusCode = "200" @> - test <@ scnStats.Ok.StatusCodes[0].Count = scnStats.StepStats[0].Ok.Request.Count @> - test <@ scnStats.Ok.StatusCodes[0].Message = "my message 1" @> - - test <@ scnStats.Ok.StatusCodes[1].IsError = false @> - test <@ scnStats.Ok.StatusCodes[1].StatusCode = "300" @> - test <@ scnStats.Ok.StatusCodes[1].Count = scnStats.Ok.Request.Count @> - test <@ scnStats.Ok.StatusCodes[1].Message = "my message 2" @> - -// [] -// let ``create should check feed on null and throw NRE`` () = -// Assert.Throws( -// typeof, -// fun _ -> let nullFeed = Unchecked.defaultof<_>() -// Step.create("null_feed", feed = nullFeed, execute = fun context -> task { return Response.ok() }) -// |> ignore -// ) - -// [] -// let ``create should check clientFactory on null and throw NRE`` () = -// Assert.Throws( -// typeof, -// fun _ -> let nullFactory = Unchecked.defaultof<_>() -// Step.create("null_feed", clientFactory = nullFactory, execute = fun context -> task { return Response.ok() }) -// |> ignore -// ) - -// [] -// let ``create should allow set step timeout`` () = -// -// let step1 = Step.create("step 1", timeout = milliseconds 500, execute = fun context -> task { -// do! Task.Delay(milliseconds 100) -// return Response.ok() -// }) -// -// let step2 = Step.create("step 2", timeout = milliseconds 500, execute = fun context -> task { -// do! Task.Delay(600) -// return Response.ok() -// }) -// -// Scenario.create "timeout tests" [step1; step2] -// |> Scenario.withoutWarmUp -// |> Scenario.withLoadSimulations [KeepConstant(copies = 1, during = seconds 5)] -// |> NBomberRunner.registerScenario -// |> NBomberRunner.withoutReports -// |> NBomberRunner.run -// |> Result.getOk -// |> fun stats -> -// test <@ stats.ScenarioStats[0].GetStepStats("step 1").Fail.Request.Count = 0 @> -// test <@ stats.ScenarioStats[0].GetStepStats("step 2").Fail.Request.Count > 0 @> -// test <@ stats.ScenarioStats[0].GetStepStats("step 2").Fail.StatusCodes[0].StatusCode = Constants.TimeoutStatusCode @> diff --git a/tests/NBomber.IntegrationTests/TestHelper.fs b/tests/NBomber.IntegrationTests/TestHelper.fs deleted file mode 100644 index da19cb99..00000000 --- a/tests/NBomber.IntegrationTests/TestHelper.fs +++ /dev/null @@ -1,178 +0,0 @@ -namespace Tests.TestHelper - -open System -open System.Data -open System.Threading.Tasks - -open Serilog -open Serilog.Sinks.InMemory - -open NBomber -open NBomber.Contracts -open NBomber.Contracts.Stats -open NBomber.Infra -open NBomber.Infra.Logger -open NBomber.DomainServices -open NBomber.FSharp - -module internal Dependency = - - let createFor (nodeType: NodeType) = - - let testInfo = { - SessionId = Dependency.createSessionId() - TestSuite = Constants.DefaultTestSuite - TestName = Constants.DefaultTestName - ClusterId = "" - } - - let emptyContext = NBomberContext.empty - - let logSettings = { - Folder = "./reports" - TestInfo = testInfo - NodeType = nodeType - AgentGroup = "" - } - - let dep = Dependency.create ApplicationType.Process logSettings emptyContext - {| TestInfo = testInfo; Dep = dep |} - - let createWithInMemoryLogger (nodeType: NodeType) = - - let testInfo = { - SessionId = Dependency.createSessionId() - TestSuite = Constants.DefaultTestSuite - TestName = Constants.DefaultTestName - ClusterId = "" - } - - let inMemorySink = new InMemorySink() - let loggerConfig = fun () -> LoggerConfiguration().WriteTo.Sink(inMemorySink) - let context = { NBomberContext.empty with CreateLoggerConfig = Some loggerConfig } - - let logSettings = { - Folder = "./reports" - TestInfo = testInfo - NodeType = nodeType - AgentGroup = "" - } - - let dep = Dependency.create ApplicationType.Process logSettings context - - let dependency = { - new IGlobalDependency with - member _.ApplicationType = dep.ApplicationType - member _.NodeType = dep.NodeType - member _.NBomberConfig = dep.NBomberConfig - member _.InfraConfig = dep.InfraConfig - member _.CreateLoggerConfig = dep.CreateLoggerConfig - member _.Logger = dep.Logger - member _.ConsoleLogger = dep.ConsoleLogger - member _.ReportingSinks = dep.ReportingSinks - member _.WorkerPlugins = dep.WorkerPlugins } - - {| TestInfo = testInfo - Dep = dependency - MemorySink = inMemorySink |} - -module List = - - /// Safe variant of `List.min` - let minOrDefault defaultValue list = - if List.isEmpty list then defaultValue - else List.min list - - /// Safe variant of `List.max` - let maxOrDefault defaultValue list = - if List.isEmpty list then defaultValue - else List.max list - - /// Safe variant of `List.average` - let averageOrDefault (defaultValue: float) list = - if List.isEmpty list then defaultValue - else list |> List.average - -module internal PluginStatisticsHelper = - - let private getPluginStatisticsColumns (prefix: string) = - let colKey = new DataColumn("Key", Type.GetType("System.String")) - colKey.Caption <- $"%s{prefix}ColumnKey" - - let colValue = new DataColumn("Value", Type.GetType("System.String")) - colValue.Caption <- $"%s{prefix}ColumnValue" - - let colType = new DataColumn("Type", Type.GetType("System.String")) - colType.Caption <- $"%s{prefix}ColumnType" - - [| colKey; colValue; colType |] - - let private getPluginStatisticsRows (count: int) (prefix: string) (table: DataTable) = [| - for i in 1 .. count do - let row = table.NewRow() - row["Key"] <- $"%s{prefix}RowKey%i{i}" - row["Value"] <- $"%s{prefix}RowValue%i{i}" - row["Type"] <- $"%s{prefix}RowType%i{i}" - yield row - |] - - let private createTable (prefix: string) = - let tableName = $"%s{prefix}Table" - let table = new DataTable(tableName) - - prefix - |> getPluginStatisticsColumns - |> table.Columns.AddRange - - table - |> getPluginStatisticsRows 10 prefix - |> Array.iter(fun x -> x |> table.Rows.Add) - - table - - let createPluginStats () = - let pluginStats = new DataSet() - pluginStats.Tables.Add(createTable("PluginStatistics1")) - pluginStats.Tables.Add(createTable("PluginStatistics2")) - pluginStats - -module internal PluginTestHelper = - - let createScenarios () = - - let scenario1 = - Scenario.create("scenario 1", fun ctx -> task { - - let! step1 = Step.run("step 1", ctx, fun () -> task { - do! Task.Delay(seconds 0.1) - return Response.ok() - }) - - let! step2 = Step.run("step 2", ctx, fun () -> task { - do! Task.Delay(seconds 0.2) - return Response.ok() - }) - - let! step3 = Step.run("step 3", ctx, fun () -> task { - do! Task.Delay(seconds 0.3) - return Response.ok() - }) - - return Response.ok() - }) - |> Scenario.withWarmUpDuration(seconds 2) - |> Scenario.withLoadSimulations [ - KeepConstant(copies = 2, during = seconds 10) - ] - - let scenario2 = - Scenario.create("scenario 2", fun ctx -> task { - do! Task.Delay(seconds 0.3) - return Response.ok() - }) - |> Scenario.withWarmUpDuration(seconds 2) - |> Scenario.withLoadSimulations [ - KeepConstant(copies = 2, during = seconds 10) - ] - - [scenario1; scenario2]