Support deleting / resetting a single scenario (#834)

* Support deleting / resetting a single scenario

* move files
This commit is contained in:
Stef Heyenrath
2022-10-26 08:43:51 +02:00
committed by GitHub
parent b4c32dd66b
commit 31298d281d
27 changed files with 186 additions and 179 deletions

View File

@@ -1,10 +1,18 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AD/@EntryIndexedValue">AD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CONNECT/@EntryIndexedValue">CONNECT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CS/@EntryIndexedValue">CS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DELETE/@EntryIndexedValue">DELETE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EC/@EntryIndexedValue">EC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GET/@EntryIndexedValue">GET</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HEAD/@EntryIndexedValue">HEAD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OPTIONS/@EntryIndexedValue">OPTIONS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PATCH/@EntryIndexedValue">PATCH</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=POST/@EntryIndexedValue">POST</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PUT/@EntryIndexedValue">PUT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RSA/@EntryIndexedValue">RSA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SSL/@EntryIndexedValue">SSL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TE/@EntryIndexedValue">TE</s:String>

View File

@@ -1,9 +1,9 @@
namespace WireMock.Http;
namespace WireMock.Constants;
/// <summary>
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
/// </summary>
internal static class HttpRequestMethods
public static class HttpRequestMethod
{
public const string CONNECT = "CONNECT";
public const string DELETE = "DELETE";

View File

@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using JetBrains.Annotations;
using WireMock.Admin.Mappings;
using WireMock.Logging;
using WireMock.Matchers.Request;
namespace WireMock.Server
{
@@ -144,6 +142,11 @@ namespace WireMock.Server
/// </summary>
void ResetScenarios();
/// <summary>
/// Resets a specific Scenario by the name.
/// </summary>
bool ResetScenario(string name);
/// <summary>
/// Resets the LogEntries.
/// </summary>

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Execution;
using WireMock.Constants;
using WireMock.Server;
using WireMock.Types;
@@ -169,39 +170,39 @@ public class WireMockAssertions
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingConnect(string because = "", params object[] becauseArgs)
=> UsingMethod("CONNECT", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.CONNECT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingDelete(string because = "", params object[] becauseArgs)
=> UsingMethod("DELETE", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.DELETE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingGet(string because = "", params object[] becauseArgs)
=> UsingMethod("GET", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.GET, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingHead(string because = "", params object[] becauseArgs)
=> UsingMethod("HEAD", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.HEAD, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingOptions(string because = "", params object[] becauseArgs)
=> UsingMethod("OPTIONS", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.OPTIONS, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPost(string because = "", params object[] becauseArgs)
=> UsingMethod("POST", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.POST, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPatch(string because = "", params object[] becauseArgs)
=> UsingMethod("PATCH", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.PATCH, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPut(string because = "", params object[] becauseArgs)
=> UsingMethod("PUT", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.PUT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingTrace(string because = "", params object[] becauseArgs)
=> UsingMethod("TRACE", because, becauseArgs);
=> UsingMethod(HttpRequestMethod.TRACE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingAnyMethod(string because = "", params object[] becauseArgs)

View File

@@ -1,4 +1,4 @@
using RestEase;
using RestEase;
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
@@ -179,6 +179,20 @@ namespace WireMock.Client
[Post("scenarios")]
Task<StatusModel> ResetScenariosAsync();
/// <summary>
/// Delete (reset) a specific scenario
/// </summary>
[Delete("scenarios/{name}")]
[AllowAnyStatusCode]
Task<StatusModel> DeleteScenarioAsync([Path] string name);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Post("scenarios/{name}/reset")]
[AllowAnyStatusCode]
Task<StatusModel> ResetScenarioAsync([Path] string name);
/// <summary>
/// Create a new File
/// </summary>

View File

@@ -26,7 +26,7 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
public ConcurrentDictionary<Guid, IMapping> Mappings { get; } = new ConcurrentDictionary<Guid, IMapping>();
public ConcurrentDictionary<string, ScenarioState> Scenarios { get; } = new();
public ConcurrentDictionary<string, ScenarioState> Scenarios { get; } = new(StringComparer.OrdinalIgnoreCase);
public ConcurrentObservableCollection<LogEntry> LogEntries { get; } = new();

View File

@@ -1,3 +1,4 @@
#pragma warning disable CS1591
namespace WireMock.Pact.Models.V2;
public class Interaction

View File

@@ -1,25 +1,25 @@
namespace WireMock.Pact.Models.V2
#pragma warning disable CS1591
namespace WireMock.Pact.Models.V2;
public class MatchingRule
{
public class MatchingRule
{
/// <summary>
/// type or regex
/// </summary>
public string Match { get; set; } = "type";
/// <summary>
/// type or regex
/// </summary>
public string Match { get; set; } = "type";
/// <summary>
/// Used for Match = "type"
/// </summary>
public string Min { get; set; }
/// <summary>
/// Used for Match = "type"
/// </summary>
public string Min { get; set; }
/// <summary>
/// Used for Match = "type"
/// </summary>
public string Max { get; set; }
/// <summary>
/// Used for Match = "type"
/// </summary>
public string Max { get; set; }
/// <summary>
/// Used for Match = "regex"
/// </summary>
public string Regex { get; set; }
}
/// <summary>
/// Used for Match = "regex"
/// </summary>
public string Regex { get; set; }
}

View File

@@ -1,9 +1,9 @@
namespace WireMock.Pact.Models.V2
{
public class Metadata
{
public string PactSpecificationVersion { get; set; }
#pragma warning disable CS1591
namespace WireMock.Pact.Models.V2;
public PactSpecification PactSpecification { get; set; } = new PactSpecification();
}
public class Metadata
{
public string PactSpecificationVersion { get; set; }
public PactSpecification PactSpecification { get; set; } = new PactSpecification();
}

View File

@@ -1,15 +1,15 @@
#pragma warning disable CS1591
using System.Collections.Generic;
namespace WireMock.Pact.Models.V2
namespace WireMock.Pact.Models.V2;
public class Pact
{
public class Pact
{
public Pacticipant Consumer { get; set; }
public Pacticipant Consumer { get; set; }
public List<Interaction> Interactions { get; set; } = new List<Interaction>();
public List<Interaction> Interactions { get; set; } = new List<Interaction>();
public Metadata Metadata { get; set; }
public Metadata Metadata { get; set; }
public Pacticipant Provider { get; set; }
}
public Pacticipant Provider { get; set; }
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
using System.Collections.Generic;
using WireMock.Constants;
namespace WireMock.Pact.Models.V2;
@@ -6,7 +8,7 @@ public class PactRequest
{
public IDictionary<string, string>? Headers { get; set; }
public string Method { get; set; } = "GET";
public string Method { get; set; } = HttpRequestMethod.GET;
public string? Path { get; set; } = "/";

View File

@@ -1,3 +1,4 @@
#pragma warning disable CS1591
using System.Collections.Generic;
namespace WireMock.Pact.Models.V2;

View File

@@ -1,11 +1,11 @@
namespace WireMock.Pact.Models.V2
#pragma warning disable CS1591
namespace WireMock.Pact.Models.V2;
public class PactRust
{
public class PactRust
{
public string Ffi { get; set; }
public string Ffi { get; set; }
public string Mockserver { get; set; }
public string Mockserver { get; set; }
public string Models { get; set; }
}
public string Models { get; set; }
}

View File

@@ -1,7 +1,7 @@
namespace WireMock.Pact.Models.V2
#pragma warning disable CS1591
namespace WireMock.Pact.Models.V2;
public class PactSpecification
{
public class PactSpecification
{
public string Version { get; set; } = "2.0";
}
public string Version { get; set; } = "2.0";
}

View File

@@ -1,7 +1,7 @@
namespace WireMock.Pact.Models.V2
#pragma warning disable CS1591
namespace WireMock.Pact.Models.V2;
public class Pacticipant
{
public class Pacticipant
{
public string Name { get; set; }
}
public string Name { get; set; }
}

View File

@@ -1,11 +1,11 @@
#pragma warning disable CS1591
using System.Collections.Generic;
namespace WireMock.Pact.Models.V2
{
public class ProviderState
{
public string Name { get; set; }
namespace WireMock.Pact.Models.V2;
public IDictionary<string, string> Params { get; set; }
}
public class ProviderState
{
public string Name { get; set; }
public IDictionary<string, string> Params { get; set; }
}

View File

@@ -1,17 +1,10 @@
using Stef.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using WireMock.Constants;
using Stef.Validation;
using WireMock.Http;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Serialization;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Proxy;
@@ -62,69 +55,4 @@ internal class ProxyHelper
return (responseMessage, newMapping);
}
private IMapping ToMapping(ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage)
{
var excludedHeaders = proxyAndRecordSettings.ExcludedHeaders ?? new string[] { };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };
var request = Request.Create();
request.WithPath(requestMessage.Path);
request.UsingMethod(requestMessage.Method);
requestMessage.Query?.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies?.Loop((key, value) =>
{
if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithCookie(key, value);
}
});
var allExcludedHeaders = new List<string>(excludedHeaders) { "Cookie" };
requestMessage.Headers?.Loop((key, value) =>
{
if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithHeader(key, value.ToArray());
}
});
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson!, true, throwExceptionWhenMatcherFails));
break;
case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString));
break;
case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}
var response = Response.Create(responseMessage);
return new Mapping
(
guid: Guid.NewGuid(),
title: $"Proxy Mapping for {requestMessage.Method} {requestMessage.Path}",
description: string.Empty,
path: null,
settings: _settings,
request,
response,
priority: WireMockConstants.ProxyPriority, // This was 0
scenario: null,
executionConditionState: null,
nextState: null,
stateTimes: null,
webhooks: null,
useWebhooksFireAndForget: null,
timeSettings: null
);
}
}

View File

@@ -1,10 +1,10 @@
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
using System.Linq;
using WireMock.Http;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using Stef.Validation;
namespace WireMock.RequestBuilders;
@@ -13,63 +13,63 @@ public partial class Request
/// <inheritdoc />
public IRequestBuilder UsingConnect(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.CONNECT));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.CONNECT));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingDelete(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.DELETE));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.DELETE));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingGet(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.GET));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.GET));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingHead(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.HEAD));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.HEAD));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingOptions(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.OPTIONS));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.OPTIONS));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingPost(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.POST));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.POST));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingPatch(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.PATCH));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.PATCH));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingPut(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.PUT));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.PUT));
return this;
}
/// <inheritdoc />
public IRequestBuilder UsingTrace(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethods.TRACE));
_requestMatchers.Add(new RequestMessageMethodMatcher(matchBehaviour, MatchOperator.Or, HttpRequestMethod.TRACE));
return this;
}

View File

@@ -8,7 +8,7 @@ public class ScenarioState
/// <summary>
/// Gets or sets the Name (from the Scenario).
/// </summary>
public string? Name { get; set; }
public string Name { get; set; } = null!;
/// <summary>
/// Gets or sets the NextState.

View File

@@ -46,6 +46,8 @@ public partial class WireMockServer
private static readonly RegexMatcher AdminRequestContentTypeJson = new ContentTypeMatcher(WireMockConstants.ContentTypeJson, true);
private static readonly RegexMatcher AdminMappingsGuidPathMatcher = new(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
private static readonly RegexMatcher AdminRequestsGuidPathMatcher = new(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
private static readonly RegexMatcher AdminScenariosNameMatcher = new(@"^\/__admin\/scenarios\/.+$");
private static readonly RegexMatcher AdminScenariosNameWithResetMatcher = new(@"^\/__admin\/scenarios\/.+\/reset$");
private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher;
@@ -93,9 +95,11 @@ public partial class WireMockServer
// __admin/scenarios
Given(Request.Create().WithPath(AdminScenarios).UsingGet()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosGet));
Given(Request.Create().WithPath(AdminScenarios).UsingDelete()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
Given(Request.Create().WithPath(AdminScenariosNameMatcher).UsingDelete()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenarioReset));
// __admin/scenarios/reset
Given(Request.Create().WithPath(AdminScenarios + "/reset").UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
Given(Request.Create().WithPath(AdminScenariosNameWithResetMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenarioReset));
// __admin/files/{filename}
Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePost));
@@ -610,6 +614,17 @@ public partial class WireMockServer
return ResponseMessageBuilder.Create("Scenarios reset");
}
private IResponseMessage ScenarioReset(IRequestMessage requestMessage)
{
var name = string.Equals(HttpRequestMethod.DELETE, requestMessage.Method, StringComparison.OrdinalIgnoreCase) ?
requestMessage.Path.Substring(AdminScenarios.Length + 1) :
requestMessage.Path.Split('/').Reverse().Skip(1).First();
return ResetScenario(name) ?
ResponseMessageBuilder.Create("Scenario reset") :
ResponseMessageBuilder.Create($"No scenario found by name '{name}'.", 404);
}
#endregion
#region Pact

View File

@@ -477,6 +477,13 @@ public partial class WireMockServer : IWireMockServer
_options.Scenarios.Clear();
}
/// <inheritdoc />
[PublicAPI]
public bool ResetScenario(string name)
{
return _options.Scenarios.ContainsKey(name) && _options.Scenarios.TryRemove(name, out _);
}
/// <inheritdoc cref="IWireMockServer.WithMapping(MappingModel[])" />
[PublicAPI]
public IWireMockServer WithMapping(params MappingModel[] mappings)

View File

@@ -10,7 +10,7 @@ interface ITransformer
IBodyData? TransformBody(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IBodyData? bodyData, ReplaceNodeOptions options);
IDictionary<string, WireMockList<string>>? TransformHeaders(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IDictionary<string, WireMockList<string>>? headers);
IDictionary<string, WireMockList<string>> TransformHeaders(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IDictionary<string, WireMockList<string>>? headers);
string TransformString(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, string? value);
}

View File

@@ -36,7 +36,7 @@ internal class Transformer : ITransformer
return newBodyData;
}
public IDictionary<string, WireMockList<string>>? TransformHeaders(
public IDictionary<string, WireMockList<string>> TransformHeaders(
IMapping mapping,
IRequestMessage originalRequestMessage,
IResponseMessage originalResponseMessage,
@@ -239,6 +239,7 @@ internal class Transformer : ITransformer
}
}
// ReSharper disable once UnusedParameter.Local
private static void ReplaceNodeValue(ReplaceNodeOptions options, JToken node, string transformedString)
{
StringUtils.TryParseQuotedString(transformedString, out var result, out _);
@@ -270,13 +271,13 @@ internal class Transformer : ITransformer
Encoding = original.Encoding,
DetectedBodyType = original.DetectedBodyType,
DetectedBodyTypeFromContentType = original.DetectedBodyTypeFromContentType,
BodyAsString = handlebarsContext.ParseAndRender(original.BodyAsString, model)
BodyAsString = handlebarsContext.ParseAndRender(original.BodyAsString!, model)
};
}
private static IBodyData TransformBodyAsFile(ITransformerContext handlebarsContext, object model, IBodyData original, bool useTransformerForBodyAsFile)
{
string transformedBodyAsFilename = handlebarsContext.ParseAndRender(original.BodyAsFile, model);
string transformedBodyAsFilename = handlebarsContext.ParseAndRender(original.BodyAsFile!, model);
if (!useTransformerForBodyAsFile)
{

View File

@@ -5,7 +5,7 @@ using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Stef.Validation;
using WireMock.Http;
using WireMock.Constants;
using WireMock.Matchers;
using WireMock.Types;
@@ -29,15 +29,15 @@ internal static class BodyParser
*/
private static readonly IDictionary<string, bool> BodyAllowedForMethods = new Dictionary<string, bool>
{
{ HttpRequestMethods.HEAD, false },
{ HttpRequestMethods.GET, false },
{ HttpRequestMethods.PUT, true },
{ HttpRequestMethods.POST, true },
{ HttpRequestMethods.DELETE, true },
{ HttpRequestMethods.TRACE, false },
{ HttpRequestMethods.OPTIONS, true },
{ HttpRequestMethods.CONNECT, false },
{ HttpRequestMethods.PATCH, true }
{ HttpRequestMethod.HEAD, false },
{ HttpRequestMethod.GET, false },
{ HttpRequestMethod.PUT, true },
{ HttpRequestMethod.POST, true },
{ HttpRequestMethod.DELETE, true },
{ HttpRequestMethod.TRACE, false },
{ HttpRequestMethod.OPTIONS, true },
{ HttpRequestMethod.CONNECT, false },
{ HttpRequestMethod.PATCH, true }
};
private static readonly IStringMatcher[] MultipartContentTypesMatchers = {
@@ -122,7 +122,7 @@ internal static class BodyParser
// In case of MultiPart: check if the BodyAsBytes is a valid UTF8 or ASCII string, in that case read as String else keep as-is
if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart)
{
if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out Encoding encoding) &&
if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out var encoding) &&
SupportedBodyAsStringEncodingForMultipart.Select(x => x.Equals(encoding)).Any())
{
data.BodyAsString = encoding.GetString(data.BodyAsBytes);

View File

@@ -603,5 +603,31 @@ public class WireMockAdminApiTests
server.Stop();
}
[Fact]
public async Task IWireMockAdminApi_DeleteScenarioUsingDeleteAsync()
{
// Arrange
var name = "x";
var server = WireMockServer.StartWithAdminInterface();
var api = RestClient.For<IWireMockAdminApi>(server.Urls[0]);
// Act
var status = await api.DeleteScenarioAsync(name).ConfigureAwait(false);
status.Status.Should().Be("No scenario found by name 'x'.");
}
[Fact]
public async Task IWireMockAdminApi_DeleteScenarioUsingPostAsync()
{
// Arrange
var name = "x";
var server = WireMockServer.StartWithAdminInterface();
var api = RestClient.For<IWireMockAdminApi>(server.Urls[0]);
// Act
var status = await api.ResetScenarioAsync(name).ConfigureAwait(false);
status.Status.Should().Be("No scenario found by name 'x'.");
}
}
#endif

View File

@@ -117,7 +117,7 @@ public class WireMockServerProxyTests
}
// Assert
server.Mappings.Should().HaveCount(28);
server.Mappings.Should().HaveCount(30);
}
[Fact]

View File

@@ -81,7 +81,7 @@ namespace WireMock.Net.Tests
// Assert
server.Mappings.Should().NotBeNull();
server.Mappings.Should().HaveCount(26);
server.Mappings.Should().HaveCount(28);
server.Mappings.All(m => m.Priority == WireMockConstants.AdminPriority).Should().BeTrue();
}
@@ -100,9 +100,9 @@ namespace WireMock.Net.Tests
// Assert
server.Mappings.Should().NotBeNull();
server.Mappings.Should().HaveCount(27);
server.Mappings.Should().HaveCount(29);
server.Mappings.Count(m => m.Priority == WireMockConstants.AdminPriority).Should().Be(26);
server.Mappings.Count(m => m.Priority == WireMockConstants.AdminPriority).Should().Be(28);
server.Mappings.Count(m => m.Priority == WireMockConstants.ProxyPriority).Should().Be(1);
}