-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
418 additions
and
11 deletions.
There are no files selected for viewing
66 changes: 66 additions & 0 deletions
66
Abstracta.JmeterDsl.Tests/Core/PostProcessors/DslRegexExtractorTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using WireMock.FluentAssertions; | ||
using WireMock.RequestBuilders; | ||
using WireMock.ResponseBuilders; | ||
using WireMock.Server; | ||
|
||
namespace Abstracta.JmeterDsl.Core.PostProcessors | ||
{ | ||
using static JmeterDsl; | ||
|
||
public class DslRegexExtractorTest | ||
{ | ||
private WireMockServer _wiremock; | ||
|
||
[SetUp] | ||
public void SetUp() | ||
{ | ||
_wiremock = WireMockServer.Start(); | ||
_wiremock.Given(Request.Create().WithPath("/")) | ||
.RespondWith(Response.Create() | ||
.WithStatusCode(200)); | ||
} | ||
|
||
[TearDown] | ||
public void TearDown() => | ||
_wiremock.Stop(); | ||
|
||
[Test] | ||
public void ShouldExtractVariableWhenSimpleRegexExtractorMatches() | ||
{ | ||
var user = "test"; | ||
var userParam = "user="; | ||
var userVar = "USER"; | ||
TestPlan( | ||
ThreadGroup(1, 1, | ||
DummySampler(userParam + user) | ||
.Children( | ||
RegexExtractor(userVar, userParam + "(.*)") | ||
), | ||
HttpSampler(_wiremock.Url + "/?" + userParam + "${" + userVar + "}") | ||
)).Run(); | ||
_wiremock.Should().HaveReceivedACall().AtUrl(_wiremock.Url + "/?" + userParam + user); | ||
} | ||
|
||
[Test] | ||
public void ShouldExtractVariableWhenComplexRegexExtractorMatches() | ||
{ | ||
var user = "test"; | ||
var userParam = "user="; | ||
var userVar = "USER"; | ||
TestPlan( | ||
ThreadGroup(1, 1, | ||
DummySampler("OK") | ||
.Url("http://localhost/?" + userParam + "user2&" + userParam + user) | ||
.Children( | ||
RegexExtractor(userVar, "([^&?]+)=([^&]+)") | ||
.MatchNumber(2) | ||
.Template("$2$") | ||
.FieldToCheck(DslRegexExtractor.DslTargetField.RequestUrl) | ||
.Scope(TestElements.DslScopedTestElement<DslRegexExtractor>.DslScope.AllSamples) | ||
), | ||
HttpSampler(_wiremock.Url + "/?" + userParam + "${" + userVar + "}") | ||
)).Run(); | ||
_wiremock.Should().HaveReceivedACall().AtUrl(_wiremock.Url + "/?" + userParam + user); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System; | ||
using System.Text.RegularExpressions; | ||
using YamlDotNet.Core; | ||
using YamlDotNet.Core.Events; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace Abstracta.JmeterDsl.Core.Bridge | ||
{ | ||
public class EnumConverter : IYamlTypeConverter | ||
{ | ||
public bool Accepts(Type type) | ||
=> type.IsEnum; | ||
|
||
public object ReadYaml(IParser parser, Type type) | ||
=> throw new NotImplementedException(); | ||
|
||
public void WriteYaml(IEmitter emitter, object value, Type type) | ||
=> emitter.Emit(new Scalar(ToSnakeCase(value.ToString()))); | ||
|
||
private string ToSnakeCase(string val) | ||
=> Regex.Replace(val, @"([a-z0-9])([A-Z])", "$1_$2").ToUpper(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
Abstracta.JmeterDsl/Core/PostProcessors/DslRegexExtractor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
namespace Abstracta.JmeterDsl.Core.PostProcessors | ||
{ | ||
/// <summary> | ||
/// Allows extracting part of a request or response using regular expressions to store into a | ||
/// variable. | ||
/// <br/> | ||
/// By default, the regular extractor is configured to extract from the main sample (does not include | ||
/// sub samples) response body the first capturing group (part of regular expression that is inside | ||
/// of parenthesis) of the first match of the regex. If no match is found, then the variable will not | ||
/// be created or modified. | ||
/// </summary> | ||
public class DslRegexExtractor : DslVariableExtractor<DslRegexExtractor> | ||
{ | ||
private readonly string _regex; | ||
private string _template; | ||
private DslTargetField? _fieldToCheck; | ||
|
||
public DslRegexExtractor(string varName, string regex) | ||
: base(null, varName) | ||
{ | ||
_regex = regex; | ||
} | ||
|
||
public enum DslTargetField | ||
{ | ||
/// <summary> | ||
/// Applies the regular extractor to the plain string of the response body. | ||
/// </summary> | ||
ResponseBody, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to the response body replacing all HTML escape codes. | ||
/// </summary> | ||
ResponseBodyUnescaped, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to the string representation obtained from parsing the response | ||
/// body with <a href="http://tika.apache.org/1.2/formats.html">Apache Tika</a>. | ||
/// </summary> | ||
ResponseBodyAsDocument, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to response headers. Response headers is a string with headers | ||
/// separated by new lines and names and values separated by colons. | ||
/// </summary> | ||
ResponseHeaders, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to request headers. Request headers is a string with headers | ||
/// separated by new lines and names and values separated by colons. | ||
/// </summary> | ||
RequestHeaders, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to the request URL. | ||
/// </summary> | ||
RequestUrl, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to response code. | ||
/// </summary> | ||
ResponseCode, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor to response message. | ||
/// </summary> | ||
ResponseMessage, | ||
} | ||
|
||
/// <summary> | ||
/// Sets the match number to be extracted. | ||
/// <br/> | ||
/// For example, if a response looks like this: | ||
/// <c>user=test&user=tester</c> | ||
/// and you use <c>user=([^&]+)</c> as regular expression, first match (1) would extract | ||
/// <c>test</c> and second match (2) would extract <c>tester</c>. | ||
/// <br/> | ||
/// When not specified, the first match will be used. When 0 is specified, a random match will be | ||
/// used. When negative, all the matches are extracted to variables with name | ||
/// <c><variableName>_<matchNumber></c>, the number of matches is stored in | ||
/// <c><variableName>_matchNr</c>, and default value is assigned to <c><variableName></c>. | ||
/// </summary> | ||
/// <param name="matchNumber">specifies the match number to use.</param> | ||
/// <returns>the extractor for further configuration or usage.</returns> | ||
public DslRegexExtractor MatchNumber(int matchNumber) | ||
{ | ||
_matchNumber = matchNumber; | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Specifies the final string to store in the JMeter Variable. | ||
/// <br/> | ||
/// The string may contain capturing groups (regular expression segments between parenthesis) | ||
/// references by using <c>$<groupId>$</c> expressions (eg: <c>$1$</c> for first group). Check | ||
/// <a href="https://jmeter.apache.org/usermanual/component_reference.html#Regular_Expression_Extractor">JMeter | ||
/// Regular Expression Extractor documentation</a> for more details. | ||
/// <br/> | ||
/// For example, if a response looks like this: | ||
/// <c>[email protected]</c> | ||
/// And you use <c>user=([^&]+)</c> as regular expression. Then <c>$1$-$2$</c> will result in | ||
/// storing in the specified JMeter variable the value <c>tester-abstracta</c>. | ||
/// <br/> | ||
/// When not specified <c>$1$</c> will be used. | ||
/// </summary> | ||
/// <param name="template">specifies template to use for storing in the JMeter variable.</param> | ||
/// <returns>the extractor for further configuration or usage.</returns> | ||
public DslRegexExtractor Template(string template) | ||
{ | ||
_template = template; | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Sets the default value to be stored in the JMeter variable when the regex does not match. | ||
/// <br/> | ||
/// When match number is negative then the value is always assigned to the variable name. | ||
/// </summary> | ||
/// A common pattern is to specify this value to a known value (e.g.: | ||
/// <VAR>_EXTRACTION_FAILURE) and then add some assertion on the variable to mark request as | ||
/// failure when the match doesn't work. | ||
/// <br/> | ||
/// When not specified then the variable will not be set if no match is found. | ||
/// <param name="defaultValue">specifies the default value to be used.</param> | ||
/// <returns>the extractor for further configuration or usage.</returns> | ||
public DslRegexExtractor DefaultValue(string defaultValue) | ||
{ | ||
_defaultValue = defaultValue; | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Allows specifying what part of request or response to apply the regular extractor to. | ||
/// <br/> | ||
/// When not specified then the regular extractor will be applied to the response body. | ||
/// </summary> | ||
/// <param name="fieldToCheck">field to apply the regular extractor to.</param> | ||
/// <returns>the extractor for further configuration or usage.</returns> | ||
/// <seealso cref="DslTargetField"/> | ||
public DslRegexExtractor FieldToCheck(DslTargetField fieldToCheck) | ||
{ | ||
_fieldToCheck = fieldToCheck; | ||
return this; | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
Abstracta.JmeterDsl/Core/PostProcessors/DslVariableExtractor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Abstracta.JmeterDsl.Core.TestElements; | ||
|
||
namespace Abstracta.JmeterDsl.Core.PostProcessors | ||
{ | ||
/// <summary> | ||
/// Contains common logic for post processors which extract some value into a variable. | ||
/// </summary> | ||
public abstract class DslVariableExtractor<T> : DslScopedTestElement<T> | ||
where T : DslVariableExtractor<T> | ||
{ | ||
protected readonly string _variableName; | ||
protected int? _matchNumber; | ||
protected string _defaultValue; | ||
|
||
public DslVariableExtractor(string name, string varName) | ||
: base(name) | ||
{ | ||
_variableName = varName; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
Abstracta.JmeterDsl/Core/TestElements/DslScopedTestElement.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
namespace Abstracta.JmeterDsl.Core.TestElements | ||
{ | ||
/// <summary> | ||
/// Contains common logic for test elements that only process certain samples. | ||
/// </summary> | ||
/// <typeparam name="T">is the type of the test element that extends this class (to properly inherit fluent | ||
/// API methods).</typeparam> | ||
public abstract class DslScopedTestElement<T> : BaseTestElement, IMultiLevelTestElement | ||
where T : DslScopedTestElement<T> | ||
{ | ||
protected DslScope? _scope; | ||
protected string _scopeVariable; | ||
|
||
protected DslScopedTestElement(string name) | ||
: base(name) | ||
{ | ||
} | ||
|
||
public enum DslScope | ||
{ | ||
/// <summary> | ||
/// Applies the regular extractor to all samples (main and sub samples). | ||
/// </summary> | ||
AllSamples, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor only to main sample (sub samples, like redirects, are not | ||
/// included). | ||
/// </summary> | ||
MainSample, | ||
|
||
/// <summary> | ||
/// Applies the regular extractor only to sub samples (redirects, embedded resources, etc.). | ||
/// </summary> | ||
SubSamples, | ||
} | ||
|
||
/// <summary> | ||
/// Allows specifying if the element should be applied to main sample and/or sub samples. | ||
/// <br/> | ||
/// When not specified the element will only apply to main sample. | ||
/// </summary> | ||
/// <param name="scope">specifying to what sample result apply the element to.</param> | ||
/// <returns>the DSL element for further configuration or usage.</returns> | ||
/// <seealso cref="Scope"/> | ||
public T Scope(DslScope scope) | ||
{ | ||
_scope = scope; | ||
return (T)this; | ||
} | ||
|
||
/// <summary> | ||
/// Allows specifying that the element should be applied to the contents of a given JMeter | ||
/// variable. | ||
/// <br/> | ||
/// This setting overrides any setting on scope and fieldToCheck. | ||
/// </summary> | ||
/// <param name="scopeVariable">specifies the name of the variable to apply the element to.</param> | ||
/// <returns>the DSL element for further configuration or usage.</returns> | ||
public T ScopeVariable(string scopeVariable) | ||
{ | ||
_scopeVariable = scopeVariable; | ||
return (T)this; | ||
} | ||
} | ||
} |
Oops, something went wrong.