diff --git a/CHANGELOG.md b/CHANGELOG.md index 5761a8d1..dee677c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 2.6.0 (11 May 2026) +- [#1455](https://github.com/wiremock/WireMock.Net/pull/1455) - Fix request storing when RequestLogExpirationDuration is set [bug] [bug] contributed by [pbenko-xitaso](https://github.com/pbenko-xitaso) +- [#1454](https://github.com/wiremock/WireMock.Net/issues/1454) - No requests stored in Standalone when RequestLogExpirationDuration is set [bug] + # 2.5.0 (04 May 2026) - [#1451](https://github.com/wiremock/WireMock.Net/pull/1451) - Feature/early mismatch [feature] contributed by [Stepami](https://github.com/Stepami) - [#1452](https://github.com/wiremock/WireMock.Net/pull/1452) - Bump log4net from 2.0.15 to 3.3.0 in example console app [dependencies, .NET] contributed by [dependabot[bot]](https://github.com/apps/dependabot) diff --git a/Directory.Build.props b/Directory.Build.props index 1a0b0b9f..c7aa4b47 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 2.5.0 + 2.6.0 WireMock.Net-Logo.png https://github.com/wiremock/WireMock.Net Apache-2.0 diff --git a/Generate-ReleaseNotes.cmd b/Generate-ReleaseNotes.cmd index 71f0d674..dfda97ef 100644 --- a/Generate-ReleaseNotes.cmd +++ b/Generate-ReleaseNotes.cmd @@ -1,6 +1,6 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=2.5.0 +SET version=2.6.0 GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels wontfix test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN% diff --git a/PackageReleaseNotes.txt b/PackageReleaseNotes.txt index ef2254e0..8b963ea2 100644 --- a/PackageReleaseNotes.txt +++ b/PackageReleaseNotes.txt @@ -1,7 +1,5 @@ -# 2.5.0 (04 May 2026) -- #1451 Feature/early mismatch [feature] -- #1452 Bump log4net from 2.0.15 to 3.3.0 in example console app [dependencies, .NET] -- #1453 Fix CVE-2026-40021: upgrade log4net to 3.3.0 in examples/WireMock.Net.Service/packages.config [dependencies] -- #1442 Bug: [grpc] WithBodyAsProtoBuf exception on match [bug] +# 2.6.0 (11 May 2026) +- #1455 Fix request storing when RequestLogExpirationDuration is set [bug] [bug] +- #1454 No requests stored in Standalone when RequestLogExpirationDuration is set [bug] The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/IResponseMessageBuilder.cs b/src/WireMock.Net.Minimal/IResponseMessageBuilder.cs new file mode 100644 index 00000000..5eccaa9f --- /dev/null +++ b/src/WireMock.Net.Minimal/IResponseMessageBuilder.cs @@ -0,0 +1,16 @@ +// Copyright © WireMock.Net + +using System.Net; + +namespace WireMock; + +internal interface IResponseMessageBuilder +{ + ResponseMessage Create(HttpStatusCode statusCode, string? status, Guid? guid = null); + + ResponseMessage Create(int statusCode, string? status, Guid? guid = null); + + ResponseMessage Create(int statusCode, string? status, string? error, Guid? guid = null); + + ResponseMessage Create(HttpStatusCode statusCode); +} \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/MappingBuilder.cs b/src/WireMock.Net.Minimal/MappingBuilder.cs index 18a1800c..7d15177b 100644 --- a/src/WireMock.Net.Minimal/MappingBuilder.cs +++ b/src/WireMock.Net.Minimal/MappingBuilder.cs @@ -27,6 +27,7 @@ public class MappingBuilder : IMappingBuilder private readonly MappingToFileSaver _mappingToFileSaver; private readonly IGuidUtils _guidUtils; private readonly IDateTimeUtils _dateTimeUtils; + private readonly IResponseMessageBuilder _responseMessageBuilder; /// /// Create a MappingBuilder @@ -43,6 +44,7 @@ public class MappingBuilder : IMappingBuilder _guidUtils = new GuidUtils(); _dateTimeUtils = new DateTimeUtils(); + _responseMessageBuilder = new ResponseMessageBuilder(_dateTimeUtils); } internal MappingBuilder( @@ -51,7 +53,8 @@ public class MappingBuilder : IMappingBuilder MappingConverter mappingConverter, MappingToFileSaver mappingToFileSaver, IGuidUtils guidUtils, - IDateTimeUtils dateTimeUtils + IDateTimeUtils dateTimeUtils, + IResponseMessageBuilder responseMessageBuilder ) { _settings = Guard.NotNull(settings); @@ -60,12 +63,13 @@ public class MappingBuilder : IMappingBuilder _mappingToFileSaver = Guard.NotNull(mappingToFileSaver); _guidUtils = Guard.NotNull(guidUtils); _dateTimeUtils = Guard.NotNull(dateTimeUtils); + _responseMessageBuilder = Guard.NotNull(responseMessageBuilder); } /// public IRespondWithAProvider Given(IRequestMatcher requestMatcher, bool saveToFile = false) { - return new RespondWithAProvider(RegisterMapping, Guard.NotNull(requestMatcher), _settings, _guidUtils, _dateTimeUtils, saveToFile); + return new RespondWithAProvider(RegisterMapping, Guard.NotNull(requestMatcher), _settings, _guidUtils, _dateTimeUtils, _responseMessageBuilder, saveToFile); } /// diff --git a/src/WireMock.Net.Minimal/Owin/AspNetCoreSelfHost.cs b/src/WireMock.Net.Minimal/Owin/AspNetCoreSelfHost.cs index 1e8dd259..35c183dc 100644 --- a/src/WireMock.Net.Minimal/Owin/AspNetCoreSelfHost.cs +++ b/src/WireMock.Net.Minimal/Owin/AspNetCoreSelfHost.cs @@ -72,6 +72,7 @@ internal partial class AspNetCoreSelfHost services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/WireMock.Net.Minimal/Owin/GlobalExceptionMiddleware.cs b/src/WireMock.Net.Minimal/Owin/GlobalExceptionMiddleware.cs index a33c9592..83da3e5b 100644 --- a/src/WireMock.Net.Minimal/Owin/GlobalExceptionMiddleware.cs +++ b/src/WireMock.Net.Minimal/Owin/GlobalExceptionMiddleware.cs @@ -11,12 +11,14 @@ internal class GlobalExceptionMiddleware { private readonly IWireMockMiddlewareOptions _options; private readonly IOwinResponseMapper _responseMapper; + private readonly IResponseMessageBuilder _responseMessageBuilder; - public GlobalExceptionMiddleware(RequestDelegate next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper) + public GlobalExceptionMiddleware(RequestDelegate next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper, IResponseMessageBuilder responseMessageBuilder) { Next = next; _options = Guard.NotNull(options); _responseMapper = Guard.NotNull(responseMapper); + _responseMessageBuilder = Guard.NotNull(responseMessageBuilder); } public RequestDelegate Next { get; } @@ -35,7 +37,7 @@ internal class GlobalExceptionMiddleware catch (Exception ex) { _options.Logger.Error("HttpStatusCode set to 500 {0}", ex); - await _responseMapper.MapAsync(ResponseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false); + await _responseMapper.MapAsync(_responseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/Owin/WireMockMiddleware.cs b/src/WireMock.Net.Minimal/Owin/WireMockMiddleware.cs index 5be58a4f..9cfa3e4e 100644 --- a/src/WireMock.Net.Minimal/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net.Minimal/Owin/WireMockMiddleware.cs @@ -26,7 +26,8 @@ internal class WireMockMiddleware( IMappingMatcher mappingMatcher, IWireMockMiddlewareLogger logger, IGuidUtils guidUtils, - IDateTimeUtils dateTimeUtils + IDateTimeUtils dateTimeUtils, + IResponseMessageBuilder responseMessageBuilder ) { private readonly object _lock = new(); @@ -97,7 +98,7 @@ internal class WireMockMiddleware( { logRequest = true; options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found"); - response = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound); + response = responseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound); return; } @@ -109,7 +110,7 @@ internal class WireMockMiddleware( if (!authorizationHeaderPresent) { options.Logger.Error("HttpStatusCode set to 401, authorization header is missing."); - response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null); + response = responseMessageBuilder.Create(HttpStatusCode.Unauthorized, null); return; } @@ -117,7 +118,7 @@ internal class WireMockMiddleware( if (!MatchScores.IsPerfect(authorizationHeaderMatchResult.Score)) { options.Logger.Error("HttpStatusCode set to 401, authentication failed.", authorizationHeaderMatchResult.Exception ?? throw new WireMockException("Authentication failed")); - response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null); + response = responseMessageBuilder.Create(HttpStatusCode.Unauthorized, null); return; } } @@ -165,7 +166,7 @@ internal class WireMockMiddleware( options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}"); WireMockActivitySource.RecordException(activity, ex); - response = ResponseMessageBuilder.Create(500, ex.Message); + response = responseMessageBuilder.Create(500, ex.Message); } finally { @@ -179,7 +180,7 @@ internal class WireMockMiddleware( { options.Logger.Error("HttpStatusCode set to 404 : No matching mapping found", ex); - var notFoundResponse = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound); + var notFoundResponse = responseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound); await responseMapper.MapAsync(notFoundResponse, ctx.Response).ConfigureAwait(false); } } diff --git a/src/WireMock.Net.Minimal/ResponseMessageBuilder.cs b/src/WireMock.Net.Minimal/ResponseMessageBuilder.cs index 318b0796..46765f6f 100644 --- a/src/WireMock.Net.Minimal/ResponseMessageBuilder.cs +++ b/src/WireMock.Net.Minimal/ResponseMessageBuilder.cs @@ -9,29 +9,30 @@ using WireMock.Util; namespace WireMock; -internal static class ResponseMessageBuilder +internal class ResponseMessageBuilder(IDateTimeUtils dateTimeUtils) : IResponseMessageBuilder { private static readonly IDictionary> ContentTypeJsonHeaders = new Dictionary> { { HttpKnownHeaderNames.ContentType, new WireMockList { WireMockConstants.ContentTypeJson } } }; - internal static ResponseMessage Create(HttpStatusCode statusCode, string? status, Guid? guid = null) + public ResponseMessage Create(HttpStatusCode statusCode, string? status, Guid? guid = null) { - return Create((int)statusCode, status, guid); + return Create((int)statusCode, status, null, guid); } - internal static ResponseMessage Create(int statusCode, string? status, Guid? guid = null) + public ResponseMessage Create(int statusCode, string? status, Guid? guid = null) { return Create(statusCode, status, null, guid); } - internal static ResponseMessage Create(int statusCode, string? status, string? error, Guid? guid = null) + public ResponseMessage Create(int statusCode, string? status, string? error, Guid? guid = null) { var response = new ResponseMessage { StatusCode = statusCode, - Headers = ContentTypeJsonHeaders + Headers = ContentTypeJsonHeaders, + DateTime = dateTimeUtils.UtcNow }; if (status != null || error != null) @@ -51,7 +52,7 @@ internal static class ResponseMessageBuilder return response; } - internal static ResponseMessage Create(HttpStatusCode statusCode) + public ResponseMessage Create(HttpStatusCode statusCode) { return new ResponseMessage { diff --git a/src/WireMock.Net.Minimal/ResponseProviders/WebSocketResponseProvider.cs b/src/WireMock.Net.Minimal/ResponseProviders/WebSocketResponseProvider.cs index a73a0cf9..64460954 100644 --- a/src/WireMock.Net.Minimal/ResponseProviders/WebSocketResponseProvider.cs +++ b/src/WireMock.Net.Minimal/ResponseProviders/WebSocketResponseProvider.cs @@ -16,7 +16,7 @@ using WireMock.WebSockets; namespace WireMock.ResponseProviders; -internal class WebSocketResponseProvider(WebSocketBuilder builder, IGuidUtils guidUtils, IDateTimeUtils dateTimeUtils) : IResponseProvider +internal class WebSocketResponseProvider(WebSocketBuilder builder, IGuidUtils guidUtils, IDateTimeUtils dateTimeUtils, IResponseMessageBuilder responseMessageBuilder) : IResponseProvider { public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync( IMapping mapping, @@ -27,7 +27,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder, IGuidUtils gu // Check if this is a WebSocket upgrade request if (!context.WebSockets.IsWebSocketRequest) { - return (ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Bad Request: Not a WebSocket upgrade request"), null); + return (responseMessageBuilder.Create(HttpStatusCode.BadRequest, "Bad Request: Not a WebSocket upgrade request"), null); } if (!context.Items.TryGetValue(nameof(IWireMockMiddlewareOptions), out var options)) @@ -110,7 +110,7 @@ internal class WebSocketResponseProvider(WebSocketBuilder builder, IGuidUtils gu // If we haven't upgraded yet, we can return HTTP error if (!context.Response.HasStarted) { - return (ResponseMessageBuilder.Create(HttpStatusCode.InternalServerError, $"WebSocket error: {ex.Message}"), null); + return (responseMessageBuilder.Create(HttpStatusCode.InternalServerError, $"WebSocket error: {ex.Message}"), null); } // Already upgraded - return marker diff --git a/src/WireMock.Net.Minimal/Server/RespondWithAProvider.cs b/src/WireMock.Net.Minimal/Server/RespondWithAProvider.cs index 499caf66..1b6ebe40 100644 --- a/src/WireMock.Net.Minimal/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net.Minimal/Server/RespondWithAProvider.cs @@ -24,6 +24,7 @@ internal class RespondWithAProvider : IRespondWithAProvider private readonly WireMockServerSettings _settings; private readonly IDateTimeUtils _dateTimeUtils; private readonly IGuidUtils _guidUtils; + private readonly IResponseMessageBuilder _responseMessageBuilder; private readonly bool _saveToFile; @@ -56,6 +57,7 @@ internal class RespondWithAProvider : IRespondWithAProvider WireMockServerSettings settings, IGuidUtils guidUtils, IDateTimeUtils dateTimeUtils, + IResponseMessageBuilder responseMessageBuilder, bool saveToFile = false ) { @@ -64,6 +66,7 @@ internal class RespondWithAProvider : IRespondWithAProvider _settings = Guard.NotNull(settings); _dateTimeUtils = Guard.NotNull(dateTimeUtils); _guidUtils = Guard.NotNull(guidUtils); + _responseMessageBuilder = Guard.NotNull(responseMessageBuilder); _saveToFile = saveToFile; @@ -79,7 +82,8 @@ internal class RespondWithAProvider : IRespondWithAProvider provider = new WebSocketResponseProvider( response.WebSocketBuilder, _guidUtils, - _dateTimeUtils + _dateTimeUtils, + _responseMessageBuilder ); } diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs index ed92e458..2a2e4e7d 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs @@ -350,7 +350,7 @@ public partial class WireMockServer o.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate; }); - return ResponseMessageBuilder.Create(200, "Settings updated"); + return _responseMessageBuilder.Create(200, "Settings updated"); } #endregion Settings @@ -361,7 +361,7 @@ public partial class WireMockServer if (mapping == null) { _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); } var model = _mappingConverter.ToMappingModel(mapping); @@ -377,14 +377,14 @@ public partial class WireMockServer if (code is null) { _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); } return ToResponseMessage(code); } _settings.Logger.Warn("HttpStatusCode set to 400"); - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "GUID is missing"); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest, "GUID is missing"); } private static TEnum GetEnumFromQuery(IRequestMessage requestMessage, TEnum defaultValue) @@ -411,22 +411,22 @@ public partial class WireMockServer var mappingModel = DeserializeObject(requestMessage); var guidFromPut = ConvertMappingAndRegisterAsRespondProvider(mappingModel, guid); - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "Mapping added or updated", guidFromPut); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "Mapping added or updated", guidFromPut); } _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); } private IResponseMessage MappingDelete(HttpContext _, IRequestMessage requestMessage) { if (TryParseGuidFromRequestMessage(requestMessage, out var guid) && DeleteMapping(guid)) { - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "Mapping removed", guid); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "Mapping removed", guid); } _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); } private static bool TryParseGuidFromRequestMessage(IRequestMessage requestMessage, out Guid guid) @@ -452,12 +452,12 @@ public partial class WireMockServer if (mapping != null) { mapping.IsDisabled = false; - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "Mapping enabled", guid); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "Mapping enabled", guid); } } _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); } private IResponseMessage MappingDisable(HttpContext _, IRequestMessage requestMessage) @@ -468,12 +468,12 @@ public partial class WireMockServer if (mapping != null) { mapping.IsDisabled = true; - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "Mapping disabled", guid); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "Mapping disabled", guid); } } _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found"); } #endregion Mapping/{guid} @@ -496,7 +496,7 @@ public partial class WireMockServer { SaveStaticMappings(); - return ResponseMessageBuilder.Create(200, "Mappings saved to disk"); + return _responseMessageBuilder.Create(200, "Mappings saved to disk"); } private MappingModel[] ToMappingModels() @@ -526,22 +526,22 @@ public partial class WireMockServer if (mappingModels.Length == 1) { var guid = ConvertMappingAndRegisterAsRespondProvider(mappingModels[0]); - return ResponseMessageBuilder.Create(201, "Mapping added", guid); + return _responseMessageBuilder.Create(201, "Mapping added", guid); } ConvertMappingsAndRegisterAsRespondProvider(mappingModels); - return ResponseMessageBuilder.Create(201, "Mappings added"); + return _responseMessageBuilder.Create(201, "Mappings added"); } catch (ArgumentException a) { _settings.Logger.Error("HttpStatusCode set to 400 {0}", a); - return ResponseMessageBuilder.Create(400, a.Message); + return _responseMessageBuilder.Create(400, a.Message); } catch (Exception e) { _settings.Logger.Error("HttpStatusCode set to 500 {0}", e); - return ResponseMessageBuilder.Create(500, e.ToString()); + return _responseMessageBuilder.Create(500, e.ToString()); } } @@ -552,18 +552,18 @@ public partial class WireMockServer var deletedGuids = MappingsDeleteMappingFromBody(requestMessage); if (deletedGuids != null) { - return ResponseMessageBuilder.Create(200, $"Mappings deleted. Affected GUIDs: [{string.Join(", ", deletedGuids.ToArray())}]"); + return _responseMessageBuilder.Create(200, $"Mappings deleted. Affected GUIDs: [{string.Join(", ", deletedGuids.ToArray())}]"); } // return bad request - return ResponseMessageBuilder.Create(400, "Poorly formed mapping JSON."); + return _responseMessageBuilder.Create(400, "Poorly formed mapping JSON."); } ResetMappings(); ResetScenarios(); - return ResponseMessageBuilder.Create(200, "Mappings deleted"); + return _responseMessageBuilder.Create(200, "Mappings deleted"); } private IEnumerable? MappingsDeleteMappingFromBody(IRequestMessage requestMessage) @@ -615,14 +615,14 @@ public partial class WireMockServer message += " and static mappings reloaded"; } - return ResponseMessageBuilder.Create(200, message); + return _responseMessageBuilder.Create(200, message); } private IResponseMessage ReloadStaticMappings(HttpContext _, IRequestMessage __) { ReadStaticMappings(); - return ResponseMessageBuilder.Create(200, "Static Mappings reloaded"); + return _responseMessageBuilder.Create(200, "Static Mappings reloaded"); } #endregion Mappings @@ -640,18 +640,18 @@ public partial class WireMockServer } _settings.Logger.Warn("HttpStatusCode set to 404 : Request not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Request not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Request not found"); } private IResponseMessage RequestDelete(HttpContext _, IRequestMessage requestMessage) { if (TryParseGuidFromRequestMessage(requestMessage, out var guid) && DeleteLogEntry(guid)) { - return ResponseMessageBuilder.Create(200, "Request removed"); + return _responseMessageBuilder.Create(200, "Request removed"); } _settings.Logger.Warn("HttpStatusCode set to 404 : Request not found"); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Request not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "Request not found"); } #endregion Request/{guid} @@ -670,7 +670,7 @@ public partial class WireMockServer { ResetLogEntries(); - return ResponseMessageBuilder.Create(200, "Requests deleted"); + return _responseMessageBuilder.Create(200, "Requests deleted"); } #endregion Requests @@ -710,7 +710,7 @@ public partial class WireMockServer return ToJson(result); } - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest); } #endregion Requests/find @@ -733,7 +733,7 @@ public partial class WireMockServer { ResetScenarios(); - return ResponseMessageBuilder.Create(200, "Scenarios reset"); + return _responseMessageBuilder.Create(200, "Scenarios reset"); } private IResponseMessage ScenarioReset(HttpContext _, IRequestMessage requestMessage) @@ -743,8 +743,8 @@ public partial class WireMockServer Enumerable.Reverse(requestMessage.Path.Split('/')).Skip(1).First(); return ResetScenario(name) ? - ResponseMessageBuilder.Create(200, "Scenario reset") : - ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); + _responseMessageBuilder.Create(200, "Scenario reset") : + _responseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); } private IResponseMessage ScenariosSetState(HttpContext _, IRequestMessage requestMessage) @@ -752,14 +752,14 @@ public partial class WireMockServer var name = Enumerable.Reverse(requestMessage.Path.Split('/')).Skip(1).First(); if (!_options.ScenarioStateStore.ContainsKey(name)) { - ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); + _responseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); } var update = DeserializeObject(requestMessage); return SetScenarioState(name, update.State) ? - ResponseMessageBuilder.Create(200, $"Scenario state set to '{update.State}'") : - ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); + _responseMessageBuilder.Create(200, $"Scenario state set to '{update.State}'") : + _responseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); } #endregion diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.AdminFiles.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.AdminFiles.cs index 8b490131..3f33569f 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.AdminFiles.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.AdminFiles.cs @@ -18,14 +18,14 @@ public partial class WireMockServer { if (requestMessage.Body is null) { - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Body is null"); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest, "Body is null"); } var id = requestMessage.Path.Split('/').Last(); AddProtoDefinition(id, requestMessage.Body); - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "ProtoDefinition added"); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "ProtoDefinition added"); } #endregion @@ -34,7 +34,7 @@ public partial class WireMockServer { if (requestMessage.BodyAsBytes is null) { - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Body is null"); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest, "Body is null"); } var filename = GetFileNameFromRequestMessage(requestMessage); @@ -47,14 +47,14 @@ public partial class WireMockServer _settings.FileSystemHandler.WriteFile(filename, requestMessage.BodyAsBytes); - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "File created"); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "File created"); } private IResponseMessage FilePut(HttpContext _, IRequestMessage requestMessage) { if (requestMessage.BodyAsBytes is null) { - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Body is null"); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest, "Body is null"); } var filename = GetFileNameFromRequestMessage(requestMessage); @@ -62,12 +62,12 @@ public partial class WireMockServer if (!_settings.FileSystemHandler.FileExists(filename)) { _settings.Logger.Info("The file '{0}' does not exist, updating file will be skipped.", filename); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "File is not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "File is not found"); } _settings.FileSystemHandler.WriteFile(filename, requestMessage.BodyAsBytes); - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "File updated"); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "File updated"); } private IResponseMessage FileGet(HttpContext _, IRequestMessage requestMessage) @@ -77,7 +77,7 @@ public partial class WireMockServer if (!_settings.FileSystemHandler.FileExists(filename)) { _settings.Logger.Info("The file '{0}' does not exist.", filename); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "File is not found"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "File is not found"); } var bytes = _settings.FileSystemHandler.ReadFile(filename); @@ -112,10 +112,10 @@ public partial class WireMockServer if (!_settings.FileSystemHandler.FileExists(filename)) { _settings.Logger.Info("The file '{0}' does not exist.", filename); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound); } - return ResponseMessageBuilder.Create(HttpStatusCode.NoContent); + return _responseMessageBuilder.Create(HttpStatusCode.NoContent); } private IResponseMessage FileDelete(HttpContext _, IRequestMessage requestMessage) @@ -125,11 +125,11 @@ public partial class WireMockServer if (!_settings.FileSystemHandler.FileExists(filename)) { _settings.Logger.Info("The file '{0}' does not exist.", filename); - return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "File is not deleted"); + return _responseMessageBuilder.Create(HttpStatusCode.NotFound, "File is not deleted"); } _settings.FileSystemHandler.DeleteFile(filename); - return ResponseMessageBuilder.Create(HttpStatusCode.OK, "File deleted."); + return _responseMessageBuilder.Create(HttpStatusCode.OK, "File deleted."); } private string GetFileNameFromRequestMessage(IRequestMessage requestMessage) diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.ImportWireMockOrg.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.ImportWireMockOrg.cs index e6516e5a..7b83cecc 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.ImportWireMockOrg.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.ImportWireMockOrg.cs @@ -52,7 +52,7 @@ public partial class WireMockServer if (mappingModels.Length == 1) { var guid = ConvertWireMockOrgMappingAndRegisterAsRespondProvider(mappingModels[0]); - return ResponseMessageBuilder.Create(201, "Mapping added", guid); + return _responseMessageBuilder.Create(201, "Mapping added", guid); } foreach (var mappingModel in mappingModels) @@ -60,17 +60,17 @@ public partial class WireMockServer ConvertWireMockOrgMappingAndRegisterAsRespondProvider(mappingModel); } - return ResponseMessageBuilder.Create(201, "Mappings added"); + return _responseMessageBuilder.Create(201, "Mappings added"); } catch (ArgumentException a) { _settings.Logger.Error("HttpStatusCode set to 400 {0}", a); - return ResponseMessageBuilder.Create(400, a.Message); + return _responseMessageBuilder.Create(400, a.Message); } catch (Exception e) { _settings.Logger.Error("HttpStatusCode set to 500 {0}", e); - return ResponseMessageBuilder.Create(500, e.ToString()); + return _responseMessageBuilder.Create(500, e.ToString()); } } diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.OpenApiParser.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.OpenApiParser.cs index e2ad4ac9..4074e843 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.OpenApiParser.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.OpenApiParser.cs @@ -19,7 +19,7 @@ public partial class WireMockServer catch (Exception e) { _settings.Logger.Error("HttpStatusCode set to {0} {1}", HttpStatusCode.BadRequest, e); - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message); } } @@ -35,12 +35,12 @@ public partial class WireMockServer ConvertMappingsAndRegisterAsRespondProvider(mappingModels); - return ResponseMessageBuilder.Create(HttpStatusCode.Created, "OpenApi document converted to Mappings"); + return _responseMessageBuilder.Create(HttpStatusCode.Created, "OpenApi document converted to Mappings"); } catch (Exception e) { _settings.Logger.Error("HttpStatusCode set to {0} {1}", HttpStatusCode.BadRequest, e); - return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message); + return _responseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message); } } } \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.cs index da2dd624..dd355c0a 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.cs @@ -42,6 +42,7 @@ public partial class WireMockServer : IWireMockServer private readonly MappingBuilder _mappingBuilder; private readonly IGuidUtils _guidUtils = new GuidUtils(); private readonly IDateTimeUtils _dateTimeUtils = new DateTimeUtils(); + private readonly IResponseMessageBuilder _responseMessageBuilder; private readonly MappingSerializer _mappingSerializer; /// @@ -354,6 +355,8 @@ public partial class WireMockServer : IWireMockServer { _settings = Guard.NotNull(settings); + _responseMessageBuilder = new ResponseMessageBuilder(_dateTimeUtils); + _mappingSerializer = new MappingSerializer(settings.DefaultJsonSerializer ?? new NewtonsoftJsonConverter()); // Set default values if not provided @@ -407,7 +410,8 @@ public partial class WireMockServer : IWireMockServer _mappingConverter, _mappingToFileSaver, _guidUtils, - _dateTimeUtils + _dateTimeUtils, + _responseMessageBuilder ); _options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration; @@ -471,7 +475,7 @@ public partial class WireMockServer : IWireMockServer Given(Request.Create().WithPath("/*").UsingAnyMethod()) .WithGuid(Guid.Parse("90008000-0000-4444-a17e-669cd84f1f05")) .AtPriority(1000) - .RespondWith(new DynamicResponseProvider((_, _) => ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound))); + .RespondWith(new DynamicResponseProvider((_, _) => _responseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound))); } /// diff --git a/test/WireMock.Net.Tests/MappingBuilderTests.cs b/test/WireMock.Net.Tests/MappingBuilderTests.cs index 17e77b09..682eaea1 100644 --- a/test/WireMock.Net.Tests/MappingBuilderTests.cs +++ b/test/WireMock.Net.Tests/MappingBuilderTests.cs @@ -59,7 +59,8 @@ public class MappingBuilderTests mappingConverter, mappingToFileSaver, guidUtilsMock.Object, - dateTimeUtilsMock.Object + dateTimeUtilsMock.Object, + new ResponseMessageBuilder(dateTimeUtilsMock.Object) ); _sut.Given(Request.Create() diff --git a/test/WireMock.Net.Tests/Owin/GlobalExceptionMiddlewareTests.cs b/test/WireMock.Net.Tests/Owin/GlobalExceptionMiddlewareTests.cs index 868fafa0..eb49380d 100644 --- a/test/WireMock.Net.Tests/Owin/GlobalExceptionMiddlewareTests.cs +++ b/test/WireMock.Net.Tests/Owin/GlobalExceptionMiddlewareTests.cs @@ -5,6 +5,7 @@ using Moq; using WireMock.Logging; using WireMock.Owin; using WireMock.Owin.Mappers; +using WireMock.Util; namespace WireMock.Net.Tests.Owin; @@ -12,6 +13,7 @@ public class GlobalExceptionMiddlewareTests { private readonly Mock _optionsMock; private readonly Mock _responseMapperMock; + private readonly IResponseMessageBuilder _responseMessageBuilder; private readonly GlobalExceptionMiddleware _sut; @@ -23,7 +25,9 @@ public class GlobalExceptionMiddlewareTests _responseMapperMock = new Mock(); _responseMapperMock.Setup(m => m.MapAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true)); - _sut = new GlobalExceptionMiddleware(_ => Task.CompletedTask, _optionsMock.Object, _responseMapperMock.Object); + _responseMessageBuilder = new ResponseMessageBuilder(new DateTimeUtils()); + + _sut = new GlobalExceptionMiddleware(_ => Task.CompletedTask, _optionsMock.Object, _responseMapperMock.Object, _responseMessageBuilder); } [Fact] @@ -37,7 +41,7 @@ public class GlobalExceptionMiddlewareTests public void GlobalExceptionMiddleware_Invoke_InvalidNext_ShouldCallResponseMapperWith500() { // Arrange - var sut = new GlobalExceptionMiddleware(_ => throw new ArgumentException(), _optionsMock.Object, _responseMapperMock.Object); + var sut = new GlobalExceptionMiddleware(_ => throw new ArgumentException(), _optionsMock.Object, _responseMapperMock.Object, _responseMessageBuilder); // Act sut.Invoke(Mock.Of()); diff --git a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs index 8cd1b2bc..67032881 100644 --- a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs +++ b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.Linq.Expressions; +using System.Net; using Microsoft.AspNetCore.Http; using Moq; using WireMock.Admin.Mappings; @@ -38,6 +39,7 @@ public class WireMockMiddlewareTests private readonly Mock _contextMock; private readonly Mock _guidUtilsMock; private readonly Mock _dateTimeUtilsMock; + private readonly IResponseMessageBuilder _responseMessageBuilderMock; private readonly WireMockMiddleware _sut; @@ -51,6 +53,8 @@ public class WireMockMiddlewareTests _dateTimeUtilsMock = new Mock(); _dateTimeUtilsMock.Setup(d => d.UtcNow).Returns(UtcNow); + _responseMessageBuilderMock = new ResponseMessageBuilder(_dateTimeUtilsMock.Object); + _optionsMock = new Mock(); _optionsMock.SetupAllProperties(); _optionsMock.Setup(o => o.Mappings).Returns(_mappings); @@ -90,7 +94,8 @@ public class WireMockMiddlewareTests _matcherMock.Object, wireMockMiddlewareLoggerMock.Object, _guidUtilsMock.Object, - _dateTimeUtilsMock.Object + _dateTimeUtilsMock.Object, + _responseMessageBuilderMock ); } @@ -103,7 +108,10 @@ public class WireMockMiddlewareTests // Assert and Verify _optionsMock.Verify(o => o.Logger.Warn(It.IsAny(), It.IsAny()), Times.Once); - Expression> match = r => (int)r.StatusCode! == 404 && ((StatusModel)r.BodyData!.BodyAsJson!).Status == "No matching mapping found"; + Expression> match = r => + (int)r.StatusCode! == 404 && + ((StatusModel)r.BodyData!.BodyAsJson!).Status == "No matching mapping found" && + r.DateTime == UtcNow; _responseMapperMock.Verify(m => m.MapAsync(It.Is(match), It.IsAny()), Times.Once); }