From 4d583796613eba2273b634bf5847a88254af1e4c Mon Sep 17 00:00:00 2001 From: rabelenda Date: Mon, 5 Feb 2024 16:36:33 -0300 Subject: [PATCH] Add jsr223PreProcessor to allow generating dynamic info per request --- .../DslJsr223PreProcessorTest.cs | 20 +++++++++++ .../PreProcessors/DslJsr223PreProcessor.cs | 23 ++++++++++++ .../Core/TestElements/DslJsr223TestElement.cs | 24 +++++++++++++ Abstracta.JmeterDsl/JmeterDsl.cs | 25 +++++++++++++ docs/guide/request-generation/index.md | 1 + .../jsr223-pre-processor.md | 36 +++++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 Abstracta.JmeterDsl.Tests/Core/PreProcessors/DslJsr223PreProcessorTest.cs create mode 100644 Abstracta.JmeterDsl/Core/PreProcessors/DslJsr223PreProcessor.cs create mode 100644 Abstracta.JmeterDsl/Core/TestElements/DslJsr223TestElement.cs create mode 100644 docs/guide/request-generation/jsr223-pre-processor.md diff --git a/Abstracta.JmeterDsl.Tests/Core/PreProcessors/DslJsr223PreProcessorTest.cs b/Abstracta.JmeterDsl.Tests/Core/PreProcessors/DslJsr223PreProcessorTest.cs new file mode 100644 index 0000000..00440ea --- /dev/null +++ b/Abstracta.JmeterDsl.Tests/Core/PreProcessors/DslJsr223PreProcessorTest.cs @@ -0,0 +1,20 @@ +namespace Abstracta.JmeterDsl.Core.PreProcessors +{ + using static JmeterDsl; + + public class DslJsr223PreProcessorTest + { + [Test] + public void ShouldUseDefinedLabelWhenPreProcessorSettingLabelInTestPlan() + { + var stats = TestPlan( + ThreadGroup(1, 1, + DummySampler("ok") + .Children( + Jsr223PreProcessor("sampler.name = 'test'") + ) + )).Run(); + Assert.That(stats.Labels["test"].SamplesCount, Is.EqualTo(1)); + } + } +} diff --git a/Abstracta.JmeterDsl/Core/PreProcessors/DslJsr223PreProcessor.cs b/Abstracta.JmeterDsl/Core/PreProcessors/DslJsr223PreProcessor.cs new file mode 100644 index 0000000..f4b81e3 --- /dev/null +++ b/Abstracta.JmeterDsl/Core/PreProcessors/DslJsr223PreProcessor.cs @@ -0,0 +1,23 @@ +using Abstracta.JmeterDsl.Core.TestElements; + +namespace Abstracta.JmeterDsl.Core.PreProcessors +{ + /// + /// Allows running custom logic before executing a sampler. + ///
+ /// This is a very powerful and flexible component that allows you to modify variables, sampler, + /// context, etc., before running a sampler (for example to generate dynamic requests + /// programmatically). + ///
+ /// By default, provided script will be interpreted as groovy script, which is the default setting + /// for JMeter. If you need, you can use any of JMeter provided scripting languages (beanshell, + /// javascript, jexl, etc.) by setting the property. + ///
+ public class DslJsr223PreProcessor : DslJsr223TestElement, IMultiLevelTestElement + { + public DslJsr223PreProcessor(string name, string script) + : base(name, script) + { + } + } +} \ No newline at end of file diff --git a/Abstracta.JmeterDsl/Core/TestElements/DslJsr223TestElement.cs b/Abstracta.JmeterDsl/Core/TestElements/DslJsr223TestElement.cs new file mode 100644 index 0000000..f7dd13d --- /dev/null +++ b/Abstracta.JmeterDsl/Core/TestElements/DslJsr223TestElement.cs @@ -0,0 +1,24 @@ +namespace Abstracta.JmeterDsl.Core.TestElements +{ + /// + /// Abstracts common logic used by JSR223 test elements. + /// + public abstract class DslJsr223TestElement : BaseTestElement + where T : DslJsr223TestElement + { + protected readonly string _script; + protected string _language; + + public DslJsr223TestElement(string name, string script) + : base(name) + { + _script = script; + } + + public T Language(string language) + { + _language = language; + return (T)this; + } + } +} \ No newline at end of file diff --git a/Abstracta.JmeterDsl/JmeterDsl.cs b/Abstracta.JmeterDsl/JmeterDsl.cs index cc2c8ab..981cb40 100644 --- a/Abstracta.JmeterDsl/JmeterDsl.cs +++ b/Abstracta.JmeterDsl/JmeterDsl.cs @@ -4,6 +4,7 @@ using Abstracta.JmeterDsl.Core.Controllers; using Abstracta.JmeterDsl.Core.Listeners; using Abstracta.JmeterDsl.Core.PostProcessors; +using Abstracta.JmeterDsl.Core.PreProcessors; using Abstracta.JmeterDsl.Core.Samplers; using Abstracta.JmeterDsl.Core.ThreadGroups; using Abstracta.JmeterDsl.Http; @@ -246,6 +247,30 @@ public static DslDummySampler DummySampler(string responseBody) public static DslDummySampler DummySampler(string name, string responseBody) => new DslDummySampler(name, responseBody); + /// + /// Builds a JSR223 Pre Processor which allows including custom logic to modify requests. + ///
+ /// This preprocessor is very powerful, and lets you alter request parameters, jmeter context and + /// implement any kind of custom logic that you may think. + ///
+ /// contains the script to be executed by the preprocessor. By default, this will be + /// a groovy script, but you can change it by setting the language property in the + /// returned post processor. + /// the JSR223 Pre Processor instance + /// + public static DslJsr223PreProcessor Jsr223PreProcessor(string script) => + Jsr223PreProcessor(null, script); + + /// + /// Same as but allowing to set a name on the preprocessor. + ///
+ /// The name is used as logger name which allows configuring log level, appender, etc., for the + /// preprocessor. + ///
+ /// + public static DslJsr223PreProcessor Jsr223PreProcessor(string name, string script) => + new DslJsr223PreProcessor(name, script); + /// /// Builds a Regex Extractor which allows using regular expressions to extract different parts of a /// sample result (request or response). diff --git a/docs/guide/request-generation/index.md b/docs/guide/request-generation/index.md index 03ad6dc..cfb0c88 100644 --- a/docs/guide/request-generation/index.md +++ b/docs/guide/request-generation/index.md @@ -2,3 +2,4 @@ + diff --git a/docs/guide/request-generation/jsr223-pre-processor.md b/docs/guide/request-generation/jsr223-pre-processor.md new file mode 100644 index 0000000..f5899a8 --- /dev/null +++ b/docs/guide/request-generation/jsr223-pre-processor.md @@ -0,0 +1,36 @@ +### Provide request parameters programmatically per request + +So far we have seen a how to generate requests with information extracted from CSV, but this is not enough for some scenarios. When you need more flexibility and power you can use `jsr223preProcessor` to specify your own logic to build each request. + +Here is an example: + +```cs +using System; +using System.Net.Http.Headers; +using System.Net.Mime; +using static Abstracta.JmeterDsl.JmeterDsl; + +public class PerformanceTest +{ + [Test] + public void LoadTest() + { + var stats = TestPlan( + ThreadGroup(5, 10, + HttpSampler("http://my.service") + .Post("${REQUEST_BODY}", new MediaTypeHeaderValue(MediaTypeNames.Text.Plain)) + .Children(Jsr223PreProcessor("vars.put('REQUEST_BODY', '{\"time\": \"' + Instant.now() + '\"}')")) + ) + ).Run(); + Assert.That(stats.Overall.SampleTimePercentile99, Is.LessThan(TimeSpan.FromSeconds(5))); + } +} +``` + +::: tip +For the time being only JSR223 scripts can be used. By default `Groovy` is used, but you can change to others by using the provided `Language()` method. + +We plan in the future to look for alternatives as to be able to use .Net code as pre processor. If you are interested in this you can let us know in [this issue](https://github.com/abstracta/jmeter-dotnet-dsl/issues/3) posting your use case. +::: + +Check [DslJsr223PreProcessor](/Abstracta.JmeterDsl/Core/PreProcessors/DslJsr223PreProcessor.cs) for more details and additional options.