From 8199cdc3828dd30eba8ffa9b8b85dbd392192a82 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 7 Oct 2017 18:10:17 +0200 Subject: [PATCH] scenario and state (added admin interface for GET and DELETE) --- src/WireMock.Net/Owin/WireMockMiddleware.cs | 55 ++++++-------- .../Owin/WireMockMiddlewareOptions.cs | 13 ++-- .../Server/FluentMockServer.Admin.cs | 30 ++++++++ .../Server/FluentMockServer.LogEntries.cs | 76 ++++++------------- src/WireMock.Net/Server/FluentMockServer.cs | 58 +++++++------- .../WireMockMiddlewareTests.cs | 2 +- 6 files changed, 110 insertions(+), 124 deletions(-) diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index 4724c58b..309b47a6 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -1,8 +1,4 @@ using System; -using System.Collections; -using System.Collections.ObjectModel; -using System.Collections.Concurrent; -using System.Collections.Generic; using System.Threading.Tasks; using WireMock.Logging; using WireMock.Matchers.Request; @@ -28,8 +24,6 @@ namespace WireMock.Owin private readonly OwinRequestMapper _requestMapper = new OwinRequestMapper(); private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper(); - private readonly IDictionary _states = new ConcurrentDictionary(); - #if !NETSTANDARD public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next) { @@ -59,9 +53,9 @@ namespace WireMock.Owin foreach (var mapping in _options.Mappings.Where(m => m.Scenario != null)) { // Set start - if (!_states.ContainsKey(mapping.Scenario) && mapping.IsStartState) + if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState) { - _states.Add(mapping.Scenario, null); + _options.Scenarios.Add(mapping.Scenario, null); } } @@ -69,7 +63,7 @@ namespace WireMock.Owin .Select(m => new { Mapping = m, - MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _states.ContainsKey(m.Scenario) ? _states[m.Scenario] : null) + MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _options.Scenarios.ContainsKey(m.Scenario) ? _options.Scenarios[m.Scenario] : null) }) .ToList(); @@ -107,7 +101,7 @@ namespace WireMock.Owin if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null) { - bool present = request.Headers.TryGetValue("Authorization", out var authorization); + bool present = request.Headers.TryGetValue("Authorization", out string authorization); if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < MatchScores.Perfect) { response = new ResponseMessage { StatusCode = 401 }; @@ -124,7 +118,7 @@ namespace WireMock.Owin if (targetMapping.Scenario != null) { - _states[targetMapping.Scenario] = targetMapping.NextState; + _options.Scenarios[targetMapping.Scenario] = targetMapping.NextState; } } catch (Exception ex) @@ -153,33 +147,30 @@ namespace WireMock.Owin private void LogRequest(LogEntry entry, bool addRequest) { - lock (((ICollection)_options.LogEntries).SyncRoot) + if (addRequest) { - if (addRequest) + _options.LogEntries.Add(entry); + } + + if (_options.MaxRequestLogCount != null) + { + var amount = _options.LogEntries.Count - _options.MaxRequestLogCount.Value; + for (int i = 0; i < amount; i++) { - _options.LogEntries.Add(entry); + _options.LogEntries.RemoveAt(0); } + } - if (_options.MaxRequestLogCount != null) + if (_options.RequestLogExpirationDuration != null) + { + var checkTime = DateTime.Now.AddHours(-_options.RequestLogExpirationDuration.Value); + + for (var i = _options.LogEntries.Count - 1; i >= 0; i--) { - var amount = _options.LogEntries.Count - _options.MaxRequestLogCount.Value; - for (int i = 0; i < amount; i++) + var le = _options.LogEntries[i]; + if (le.RequestMessage.DateTime <= checkTime) { - _options.LogEntries.RemoveAt(0); - } - } - - if (_options.RequestLogExpirationDuration != null) - { - var checkTime = DateTime.Now.AddHours(-_options.RequestLogExpirationDuration.Value); - - for (var i = _options.LogEntries.Count - 1; i >= 0; i--) - { - var le = _options.LogEntries[i]; - if (le.RequestMessage.DateTime <= checkTime) - { - _options.LogEntries.RemoveAt(i); - } + _options.LogEntries.RemoveAt(i); } } } diff --git a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs index 33bea177..3737527e 100644 --- a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs +++ b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using WireMock.Logging; @@ -14,18 +15,14 @@ namespace WireMock.Owin public bool AllowPartialMapping { get; set; } - public IList Mappings { get; set; } + public IList Mappings { get; set; } = new List(); + + public ObservableCollection LogEntries { get; } = new ObservableCollection(); - public ObservableCollection LogEntries { get; } - public int? RequestLogExpirationDuration { get; set; } public int? MaxRequestLogCount { get; set; } - public WireMockMiddlewareOptions() - { - Mappings = new List(); - LogEntries = new ObservableCollection(); - } + public IDictionary Scenarios { get; } = new ConcurrentDictionary(); } } \ No newline at end of file diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index bb39aa46..291dae88 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -31,6 +31,7 @@ namespace WireMock.Server private const string AdminMappings = "/__admin/mappings"; private const string AdminRequests = "/__admin/requests"; private const string AdminSettings = "/__admin/settings"; + private const string AdminScenarios = "/__admin/scenarios"; private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/(\{{0,1}([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}\}{0,1})$"); private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/requests\/(\{{0,1}([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}\}{0,1})$"); @@ -117,6 +118,15 @@ namespace WireMock.Server // __admin/requests/find Given(Request.Create().WithPath(AdminRequests + "/find").UsingPost()).RespondWith(new DynamicResponseProvider(RequestsFind)); + + + // __admin/scenarios + // __admin/scenarios + Given(Request.Create().WithPath(AdminScenarios).UsingGet()).RespondWith(new DynamicResponseProvider(ScenariosGet)); + Given(Request.Create().WithPath(AdminScenarios).UsingDelete()).RespondWith(new DynamicResponseProvider(ScenariosReset)); + + // __admin/scenarios/reset + Given(Request.Create().WithPath(AdminScenarios + "/reset").UsingPost()).RespondWith(new DynamicResponseProvider(ScenariosReset)); } #region Proxy and Record @@ -459,6 +469,26 @@ namespace WireMock.Server } #endregion Requests/find + #region Scenarios + private ResponseMessage ScenariosGet(RequestMessage requestMessage) + { + var scenarios = Scenarios.Select(s => new + { + Name = s.Key, + Started = s.Value != null, + NextState = s.Value + }); + return ToJson(scenarios); + } + + private ResponseMessage ScenariosReset(RequestMessage requestMessage) + { + ResetScenarios(); + + return new ResponseMessage { Body = "Scenarios reset" }; + } + #endregion + private IRequestBuilder InitRequestBuilder(RequestModel requestModel) { IRequestBuilder requestBuilder = Request.Create(); diff --git a/src/WireMock.Net/Server/FluentMockServer.LogEntries.cs b/src/WireMock.Net/Server/FluentMockServer.LogEntries.cs index 1cb8f595..6423ef4f 100644 --- a/src/WireMock.Net/Server/FluentMockServer.LogEntries.cs +++ b/src/WireMock.Net/Server/FluentMockServer.LogEntries.cs @@ -19,36 +19,15 @@ namespace WireMock.Server [PublicAPI] public event NotifyCollectionChangedEventHandler LogEntriesChanged { - add - { - lock (((ICollection)_options.LogEntries).SyncRoot) - { - _options.LogEntries.CollectionChanged += value; - } - } - remove - { - lock (((ICollection)_options.LogEntries).SyncRoot) - { - _options.LogEntries.CollectionChanged -= value; - } - } + add => _options.LogEntries.CollectionChanged += value; + remove => _options.LogEntries.CollectionChanged -= value; } /// /// Gets the request logs. /// [PublicAPI] - public IEnumerable LogEntries - { - get - { - lock (((ICollection)_options.LogEntries).SyncRoot) - { - return new ReadOnlyCollection(_options.LogEntries); - } - } - } + public IEnumerable LogEntries => new ReadOnlyCollection(_options.LogEntries); /// /// The search log-entries based on matchers. @@ -58,26 +37,23 @@ namespace WireMock.Server [PublicAPI] public IEnumerable FindLogEntries([NotNull] params IRequestMatcher[] matchers) { - lock (((ICollection)_options.LogEntries).SyncRoot) + var results = new Dictionary(); + + foreach (var log in _options.LogEntries) { - var results = new Dictionary(); - - foreach (var log in _options.LogEntries) + var requestMatchResult = new RequestMatchResult(); + foreach (var matcher in matchers) { - var requestMatchResult = new RequestMatchResult(); - foreach (var matcher in matchers) - { - matcher.GetMatchingScore(log.RequestMessage, requestMatchResult); - } - - if (requestMatchResult.AverageTotalScore > MatchScores.AlmostPerfect) - { - results.Add(log, requestMatchResult); - } + matcher.GetMatchingScore(log.RequestMessage, requestMatchResult); } - return new ReadOnlyCollection(results.OrderBy(x => x.Value).Select(x => x.Key).ToList()); + if (requestMatchResult.AverageTotalScore > MatchScores.AlmostPerfect) + { + results.Add(log, requestMatchResult); + } } + + return new ReadOnlyCollection(results.OrderBy(x => x.Value).Select(x => x.Key).ToList()); } /// @@ -86,10 +62,7 @@ namespace WireMock.Server [PublicAPI] public void ResetLogEntries() { - lock (((ICollection)_options.LogEntries).SyncRoot) - { - _options.LogEntries.Clear(); - } + _options.LogEntries.Clear(); } /// @@ -99,18 +72,15 @@ namespace WireMock.Server [PublicAPI] public bool DeleteLogEntry(Guid guid) { - lock (((ICollection)_options.LogEntries).SyncRoot) + // Check a logentry exists with the same GUID, if so, remove it. + var existing = _options.LogEntries.FirstOrDefault(m => m.Guid == guid); + if (existing != null) { - // Check a logentry exists with the same GUID, if so, remove it. - var existing = _options.LogEntries.FirstOrDefault(m => m.Guid == guid); - if (existing != null) - { - _options.LogEntries.Remove(existing); - return true; - } - - return false; + _options.LogEntries.Remove(existing); + return true; } + + return false; } } } diff --git a/src/WireMock.Net/Server/FluentMockServer.cs b/src/WireMock.Net/Server/FluentMockServer.cs index b4d4a139..b68a6320 100644 --- a/src/WireMock.Net/Server/FluentMockServer.cs +++ b/src/WireMock.Net/Server/FluentMockServer.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -44,16 +45,13 @@ namespace WireMock.Server /// Gets the mappings. /// [PublicAPI] - public IEnumerable Mappings - { - get - { - lock (((ICollection)_options.Mappings).SyncRoot) - { - return new ReadOnlyCollection(_options.Mappings); - } - } - } + public IEnumerable Mappings => new ReadOnlyCollection(_options.Mappings); + + /// + /// Gets the scenarios. + /// + [PublicAPI] + public IDictionary Scenarios => new ConcurrentDictionary(_options.Scenarios); #region Start/Stop /// @@ -258,10 +256,7 @@ namespace WireMock.Server [PublicAPI] public void ResetMappings() { - lock (((ICollection)_options.Mappings).SyncRoot) - { - _options.Mappings = _options.Mappings.Where(m => m.IsAdminInterface).ToList(); - } + _options.Mappings = _options.Mappings.Where(m => m.IsAdminInterface).ToList(); } /// @@ -271,18 +266,15 @@ namespace WireMock.Server [PublicAPI] public bool DeleteMapping(Guid guid) { - lock (((ICollection)_options.Mappings).SyncRoot) + // Check a mapping exists with the same GUID, if so, remove it. + var existingMapping = _options.Mappings.FirstOrDefault(m => m.Guid == guid); + if (existingMapping != null) { - // Check a mapping exists with the same GUID, if so, remove it. - var existingMapping = _options.Mappings.FirstOrDefault(m => m.Guid == guid); - if (existingMapping != null) - { - _options.Mappings.Remove(existingMapping); - return true; - } - - return false; + _options.Mappings.Remove(existingMapping); + return true; } + + return false; } /// @@ -349,6 +341,15 @@ namespace WireMock.Server _options.RequestLogExpirationDuration = requestLogExpirationDuration; } + /// + /// Resets the Scenarios. + /// + [PublicAPI] + public void ResetScenarios() + { + _options.Scenarios.Clear(); + } + /// /// The given. /// @@ -368,13 +369,10 @@ namespace WireMock.Server /// private void RegisterMapping(Mapping mapping) { - lock (((ICollection)_options.Mappings).SyncRoot) - { - // Check a mapping exists with the same GUID, if so, remove it first. - DeleteMapping(mapping.Guid); + // Check a mapping exists with the same GUID, if so, remove it first. + DeleteMapping(mapping.Guid); - _options.Mappings.Add(mapping); - } + _options.Mappings.Add(mapping); } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs index a7c5f2d7..4c38bae6 100644 --- a/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs +++ b/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs @@ -19,7 +19,7 @@ // var sut = _objectMother.Create(); // // then -// Check.That(sut.States).IsNull(); +// Check.That(sut.Scenarios).IsNull(); // } // private class ObjectMother