diff --git a/examples/WireMock.Net.ConsoleApplication/MainApp.cs b/examples/WireMock.Net.ConsoleApplication/MainApp.cs index 4d4c7d97..6e889a6a 100644 --- a/examples/WireMock.Net.ConsoleApplication/MainApp.cs +++ b/examples/WireMock.Net.ConsoleApplication/MainApp.cs @@ -27,7 +27,7 @@ namespace WireMock.Net.ConsoleApplication server.SetBasicAuthentication("a", "b"); - server.AllowPartialMapping(); + // server.AllowPartialMapping(); server .Given(Request.Create().WithPath("/oauth2/access").UsingPost().WithBody("grant_type=password;username=u;password=p")) @@ -95,19 +95,55 @@ namespace WireMock.Net.ConsoleApplication .Given(Request.Create().WithPath("/partial").UsingPost().WithBody(new SimMetricsMatcher(new[] { "cat", "dog" }))) .RespondWith(Response.Create().WithStatusCode(200).WithBody("partial = 200")); - http://localhost:8080/any/any?start=1000&stop=1&stop=2 + // http://localhost:8080/any/any?start=1000&stop=1&stop=2 + //server + // .Given(Request.Create().WithPath("/*").UsingGet()) + // .WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05") + // .AtPriority(server.Mappings.Count() + 1) + // .RespondWith(Response.Create() + // .WithStatusCode(200) + // .WithHeader("Content-Type", "application/json") + // .WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}") + // .WithBody(@"{""msg"": ""Hello world CATCH-ALL on /*, {{request.path}}, bykey={{request.query.start}}, bykey={{request.query.stop}}, byidx0={{request.query.stop.[0]}}, byidx1={{request.query.stop.[1]}}"" }") + // .WithTransformer() + // .WithDelay(TimeSpan.FromMilliseconds(100)) + // ); + server - .Given(Request.Create().WithPath("/*").UsingGet()) - .WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05") - .AtPriority(server.Mappings.Count() + 1) + .Given(Request.Create() + .WithPath("/state1") + .UsingGet()) + .InScenario("s1") + .WillSetStateTo("Test state 1") .RespondWith(Response.Create() - .WithStatusCode(200) - .WithHeader("Content-Type", "application/json") - .WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}") - .WithBody(@"{""msg"": ""Hello world CATCH-ALL on /*, {{request.path}}, bykey={{request.query.start}}, bykey={{request.query.stop}}, byidx0={{request.query.stop.[0]}}, byidx1={{request.query.stop.[1]}}"" }") - .WithTransformer() - .WithDelay(TimeSpan.FromMilliseconds(100)) - ); + .WithBody("No state msg 1")); + + server + .Given(Request.Create() + .WithPath("/foostate1") + .UsingGet()) + .InScenario("s1") + .WhenStateIs("Test state 1") + .RespondWith(Response.Create() + .WithBody("Test state msg 1")); + + server + .Given(Request.Create() + .WithPath("/state2") + .UsingGet()) + .InScenario("s2") + .WillSetStateTo("Test state 2") + .RespondWith(Response.Create() + .WithBody("No state msg 2")); + + server + .Given(Request.Create() + .WithPath("/foostate2") + .UsingGet()) + .InScenario("s2") + .WhenStateIs("Test state 2") + .RespondWith(Response.Create() + .WithBody("Test state msg 2")); System.Console.WriteLine("Press any key to stop the server"); System.Console.ReadKey(); @@ -121,4 +157,4 @@ namespace WireMock.Net.ConsoleApplication System.Console.ReadKey(); } } -} +} \ No newline at end of file diff --git a/src/WireMock.Net/Admin/Mappings/MappingModel.cs b/src/WireMock.Net/Admin/Mappings/MappingModel.cs index b21c371e..62ddd6d8 100644 --- a/src/WireMock.Net/Admin/Mappings/MappingModel.cs +++ b/src/WireMock.Net/Admin/Mappings/MappingModel.cs @@ -31,6 +31,22 @@ namespace WireMock.Admin.Mappings /// public int? Priority { get; set; } + /// + /// Scenario. + /// + public string Scenario { get; set; } + + /// + /// Execution state condition for the current mapping. + /// + public object WhenStateIs { get; set; } + + /// + /// The next state which will be signaled after the current mapping execution. + /// In case the value is null state will not be changed. + /// + public object SetStateTo { get; set; } + /// /// Gets or sets the request. /// diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs index bebff0e1..1fd3c8f6 100644 --- a/src/WireMock.Net/Mapping.cs +++ b/src/WireMock.Net/Mapping.cs @@ -1,96 +1,141 @@ -using System; -using System.Threading.Tasks; -using JetBrains.Annotations; -using WireMock.Matchers.Request; - -namespace WireMock -{ - /// - /// The Mapping. - /// - public class Mapping - { - /// - /// Gets the unique identifier. - /// - /// - /// The unique identifier. - /// - public Guid Guid { get; } - - /// - /// Gets the unique title. - /// - /// - /// The unique title. - /// - public string Title { get; } - - /// - /// Gets the priority. - /// - /// - /// The priority. - /// - public int Priority { get; } - - /// - /// The Request matcher. - /// - public IRequestMatcher RequestMatcher { get; } - - /// - /// The Provider. - /// - public IResponseProvider Provider { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The unique identifier. - /// The unique title (can be null_. - /// The request matcher. - /// The provider. - /// The priority for this mapping. - public Mapping(Guid guid, [CanBeNull] string title, IRequestMatcher requestMatcher, IResponseProvider provider, int priority) - { - Priority = priority; - Guid = guid; - Title = title; - RequestMatcher = requestMatcher; - Provider = provider; - } - - /// - /// The response to. - /// - /// The request message. - /// The . - public async Task ResponseToAsync(RequestMessage requestMessage) - { - return await Provider.ProvideResponseAsync(requestMessage); - } - - /// - /// Determines whether the RequestMessage is handled. - /// - /// The request message. - /// The . - public RequestMatchResult IsRequestHandled(RequestMessage requestMessage) - { - var result = new RequestMatchResult(); - - RequestMatcher.GetMatchingScore(requestMessage, result); - - return result; - } - - /// - /// Gets a value indicating whether this mapping is an Admin Interface. - /// - /// - /// true if this mapping is an Admin Interface; otherwise, false. - /// - public bool IsAdminInterface => Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider || Provider is ProxyAsyncResponseProvider; - } +using System; +using System.Threading.Tasks; +using JetBrains.Annotations; +using WireMock.Matchers.Request; + +namespace WireMock +{ + /// + /// The Mapping. + /// + public class Mapping + { + /// + /// Gets the unique identifier. + /// + /// + /// The unique identifier. + /// + public Guid Guid { get; } + + /// + /// Gets the unique title. + /// + /// + /// The unique title. + /// + public string Title { get; } + + /// + /// Gets the priority. + /// + /// + /// The priority. + /// + public int Priority { get; } + + /// + /// Scenario. + /// + [CanBeNull] + public string Scenario { get; } + + /// + /// Execution state condition for the current mapping. + /// + [CanBeNull] + public object ExecutionConditionState { get; } + + /// + /// The next state which will be signaled after the current mapping execution. + /// In case the value is null state will not be changed. + /// + [CanBeNull] + public object NextState { get; } + + /// + /// The Request matcher. + /// + public IRequestMatcher RequestMatcher { get; } + + /// + /// The Provider. + /// + public IResponseProvider Provider { get; } + + /// + /// Is State started ? + /// + public bool IsStartState => Scenario == null || Scenario != null && NextState != null && ExecutionConditionState == null; + + /// + /// Initializes a new instance of the class. + /// + /// The unique identifier. + /// The unique title (can be null_. + /// The request matcher. + /// The provider. + /// The priority for this mapping. + /// The scenario. [Optional] + /// State in which the current mapping can occur. [Optional] + /// The next state which will occur after the current mapping execution. [Optional] + public Mapping(Guid guid, [CanBeNull] string title, IRequestMatcher requestMatcher, IResponseProvider provider, int priority, [CanBeNull] string scenario, [CanBeNull] object executionConditionState, [CanBeNull] object nextState) + { + Guid = guid; + Title = title; + RequestMatcher = requestMatcher; + Provider = provider; + Priority = priority; + Scenario = scenario; + ExecutionConditionState = executionConditionState; + NextState = nextState; + } + + /// + /// The response to. + /// + /// The request message. + /// The . + public async Task ResponseToAsync(RequestMessage requestMessage) + { + return await Provider.ProvideResponseAsync(requestMessage); + } + + /// + /// Gets the RequestMatchResult based on the RequestMessage. + /// + /// The request message. + /// The Next State. + /// The . + public RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, [CanBeNull] object nextState) + { + var result = new RequestMatchResult(); + + RequestMatcher.GetMatchingScore(requestMessage, result); + + // Only check state if Scenario is defined + if (Scenario != null) + { + var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState); + matcher.GetMatchingScore(requestMessage, result); + //// If ExecutionConditionState is null, this means that request is the start from a scenario. So just return. + //if (ExecutionConditionState != null) + //{ + // // ExecutionConditionState is not null, so get score for matching with the nextState. + // var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState); + // matcher.GetMatchingScore(requestMessage, result); + //} + } + + return result; + } + + /// + /// Gets a value indicating whether this mapping is an Admin Interface. + /// + /// + /// true if this mapping is an Admin Interface; otherwise, false. + /// + public bool IsAdminInterface => Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider || Provider is ProxyAsyncResponseProvider; + } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs b/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs index 08fc6dd3..c6a5e26f 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs @@ -43,7 +43,7 @@ namespace WireMock.Matchers.Request /// /// Gets the match details. /// - public IList> MatchDetails { get; private set; } + public IList> MatchDetails { get; } /// /// Initializes a new instance of the class. @@ -72,7 +72,6 @@ namespace WireMock.Matchers.Request /// /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. /// - /// public int CompareTo(object obj) { var compareObj = (RequestMatchResult)obj; diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs new file mode 100644 index 00000000..a51dc1ec --- /dev/null +++ b/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs @@ -0,0 +1,51 @@ +using JetBrains.Annotations; + +namespace WireMock.Matchers.Request +{ + /// + /// The scenario and state matcher. + /// + internal class RequestMessageScenarioAndStateMatcher : IRequestMatcher + { + ///// + ///// Scenario. + ///// + //[CanBeNull] private string _scenario; + + /// + /// Execution state condition for the current mapping. + /// + [CanBeNull] + private readonly object _executionConditionState; + + /// + /// The next state which will be signaled after the current mapping execution. + /// In case the value is null state will not be changed. + /// + [CanBeNull] + private readonly object _nextState; + + /// + /// Initializes a new instance of the class. + /// + /// The next state. + /// Execution state condition for the current mapping. + public RequestMessageScenarioAndStateMatcher([CanBeNull] object nextState, [CanBeNull] object executionConditionState) + { + _nextState = nextState; + _executionConditionState = executionConditionState; + } + + /// + public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) + { + double score = IsMatch(); + return requestMatchResult.AddScore(GetType(), score); + } + + private double IsMatch() + { + return Equals(_executionConditionState, _nextState) ? MatchScores.Perfect : MatchScores.Mismatch; + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Owin/IOwinSelfHost.cs b/src/WireMock.Net/Owin/IOwinSelfHost.cs index 2a378b2f..9cf9f598 100644 --- a/src/WireMock.Net/Owin/IOwinSelfHost.cs +++ b/src/WireMock.Net/Owin/IOwinSelfHost.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace WireMock.Owin diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index 529082d6..02048fd3 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -1,9 +1,12 @@ using System; using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Threading.Tasks; using WireMock.Logging; using WireMock.Matchers.Request; using System.Linq; +using WireMock.Matchers; #if !NETSTANDARD using Microsoft.Owin; #else @@ -24,6 +27,8 @@ 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) { @@ -50,11 +55,20 @@ namespace WireMock.Owin RequestMatchResult requestMatchResult = null; try { + foreach (var mapping in _options.Mappings.Where(m => m.Scenario != null)) + { + // Set start + if (!_states.ContainsKey(mapping.Scenario) && mapping.IsStartState) + { + _states.Add(mapping.Scenario, null); + } + } + var mappings = _options.Mappings .Select(m => new { Mapping = m, - MatchResult = m.IsRequestHandled(request) + MatchResult = m.GetRequestMatchResult(request, m.Scenario != null && _states.ContainsKey(m.Scenario) ? _states[m.Scenario] : null) }) .ToList(); @@ -87,14 +101,13 @@ namespace WireMock.Owin response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" }; return; } - + logRequest = !targetMapping.IsAdminInterface; if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null) { - string authorization; - bool present = request.Headers.TryGetValue("Authorization", out authorization); - if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < 1.0) + bool present = request.Headers.TryGetValue("Authorization", out var authorization); + if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < MatchScores.Perfect) { response = new ResponseMessage { StatusCode = 401 }; return; @@ -107,6 +120,11 @@ namespace WireMock.Owin } response = await targetMapping.ResponseToAsync(request); + + if (targetMapping.Scenario != null) + { + _states[targetMapping.Scenario] = targetMapping.NextState; + } } catch (Exception ex) { diff --git a/src/WireMock.Net/Properties/AssemblyInfo.cs b/src/WireMock.Net/Properties/AssemblyInfo.cs index 60a444e7..e6452c0f 100644 --- a/src/WireMock.Net/Properties/AssemblyInfo.cs +++ b/src/WireMock.Net/Properties/AssemblyInfo.cs @@ -1,3 +1,4 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("WireMock.Net.StandAlone")] \ No newline at end of file +[assembly: InternalsVisibleTo("WireMock.Net.StandAlone")] +[assembly: InternalsVisibleTo("WireMock.Net.Tests")] \ No newline at end of file diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index a06e8da8..48c3e567 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -32,6 +32,9 @@ namespace WireMock.Serialization Guid = mapping.Guid, Title = mapping.Title, Priority = mapping.Priority, + Scenario = mapping.Scenario, + WhenStateIs = mapping.ExecutionConditionState, + SetStateTo = mapping.NextState, Request = new RequestModel { ClientIP = clientIPMatchers != null && clientIPMatchers.Any() ? new ClientIPModel diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index 6d25e661..aef64b9e 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -69,9 +69,8 @@ namespace WireMock.Server Check.NotNull(filename, nameof(filename)); string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); - Guid guidFromFilename; - if (Guid.TryParse(filenameWithoutExtension, out guidFromFilename)) + if (Guid.TryParse(filenameWithoutExtension, out var guidFromFilename)) { DeserializeAndAddMapping(File.ReadAllText(filename), guidFromFilename); } @@ -151,7 +150,7 @@ namespace WireMock.Server var response = (Response)Response.Create(responseMessage); - return new Mapping(Guid.NewGuid(), string.Empty, request, response, 0); + return new Mapping(Guid.NewGuid(), string.Empty, request, response, 0, null, null, null); } #endregion @@ -323,6 +322,13 @@ namespace WireMock.Server if (mappingModel.Priority != null) respondProvider = respondProvider.AtPriority(mappingModel.Priority.Value); + if (mappingModel.Scenario != null) + { + respondProvider = respondProvider.InScenario(mappingModel.Scenario); + respondProvider = respondProvider.WhenStateIs(mappingModel.WhenStateIs); + respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo); + } + respondProvider.RespondWith(responseBuilder); } diff --git a/src/WireMock.Net/Server/IRespondWithAProvider.cs b/src/WireMock.Net/Server/IRespondWithAProvider.cs index 33a31579..72486ac9 100644 --- a/src/WireMock.Net/Server/IRespondWithAProvider.cs +++ b/src/WireMock.Net/Server/IRespondWithAProvider.cs @@ -1,44 +1,65 @@ -using System; - -namespace WireMock.Server -{ - /// - /// IRespondWithAProvider - /// - public interface IRespondWithAProvider - { - /// - /// Define a unique identifier for this mapping. - /// - /// The unique identifier. - /// The . - IRespondWithAProvider WithGuid(Guid guid); - - /// - /// Define a unique title for this mapping. - /// - /// The unique title. - /// The . - IRespondWithAProvider WithTitle(string title); - - /// - /// Define a unique identifier for this mapping. - /// - /// The unique identifier. - /// The . - IRespondWithAProvider WithGuid(string guid); - - /// - /// Define the priority for this mapping. - /// - /// The priority. - /// The . - IRespondWithAProvider AtPriority(int priority); - - /// - /// The respond with. - /// - /// The provider. - void RespondWith(IResponseProvider provider); - } +using System; + +namespace WireMock.Server +{ + /// + /// IRespondWithAProvider + /// + public interface IRespondWithAProvider + { + /// + /// Define a unique identifier for this mapping. + /// + /// The unique identifier. + /// The . + IRespondWithAProvider WithGuid(Guid guid); + + /// + /// Define a unique title for this mapping. + /// + /// The unique title. + /// The . + IRespondWithAProvider WithTitle(string title); + + /// + /// Define a unique identifier for this mapping. + /// + /// The unique identifier. + /// The . + IRespondWithAProvider WithGuid(string guid); + + /// + /// Define the priority for this mapping. + /// + /// The priority. + /// The . + IRespondWithAProvider AtPriority(int priority); + + /// + /// The respond with. + /// + /// The provider. + void RespondWith(IResponseProvider provider); + + /// + /// Sets the the scenario. + /// + /// The scenario. + /// The . + IRespondWithAProvider InScenario(string scenario); + + /// + /// Execute this respond only in case the current state is equal to specified one. + /// + /// Any object which identifies the current state + /// The . + IRespondWithAProvider WhenStateIs(object state); + + /// + /// Once this mapping is executed the state will be changed to specified one. + /// + /// Any object which identifies the new state + /// The . + IRespondWithAProvider WillSetStateTo(object state); + } } \ No newline at end of file diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs index 843a5448..77546c68 100644 --- a/src/WireMock.Net/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net/Server/RespondWithAProvider.cs @@ -11,6 +11,9 @@ namespace WireMock.Server private int _priority; private Guid? _guid; private string _title; + private object _executionConditionState; + private object _nextState; + private string _scenario; /// /// The _registration callback. @@ -42,7 +45,7 @@ namespace WireMock.Server public void RespondWith(IResponseProvider provider) { var mappingGuid = _guid ?? Guid.NewGuid(); - _registrationCallback(new Mapping(mappingGuid, _title, _requestMatcher, provider, _priority)); + _registrationCallback(new Mapping(mappingGuid, _title, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState)); } /// @@ -90,5 +93,41 @@ namespace WireMock.Server return this; } + + public IRespondWithAProvider InScenario(string scenario) + { + _scenario = scenario; + + return this; + } + + public IRespondWithAProvider WhenStateIs(object state) + { + if (string.IsNullOrEmpty(_scenario)) + { + throw new NotSupportedException("Unable to set state condition when no scenario is defined."); + } + + //if (_nextState != null) + //{ + // throw new NotSupportedException("Unable to set state condition when next state is defined."); + //} + + _executionConditionState = state; + + return this; + } + + public IRespondWithAProvider WillSetStateTo(object state) + { + if (string.IsNullOrEmpty(_scenario)) + { + throw new NotSupportedException("Unable to set next state when no scenario is defined."); + } + + _nextState = state; + + return this; + } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/FluentMockServerTests.cs b/test/WireMock.Net.Tests/FluentMockServerTests.cs index a8875a87..a220f8ab 100644 --- a/test/WireMock.Net.Tests/FluentMockServerTests.cs +++ b/test/WireMock.Net.Tests/FluentMockServerTests.cs @@ -407,7 +407,7 @@ namespace WireMock.Net.Tests var requestLoggedB = _server.LogEntries.Last(); Check.That(requestLoggedB.RequestMessage.Path).EndsWith("/foo3"); - } + } public void Dispose() { diff --git a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs new file mode 100644 index 00000000..7993bae2 --- /dev/null +++ b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using NFluent; +using WireMock.RequestBuilders; +using WireMock.ResponseBuilders; +using WireMock.Server; +using Xunit; + +namespace WireMock.Net.Tests +{ + public class StatefulBehaviorTests : IDisposable + { + private FluentMockServer _server; + + [Fact] + public async Task Should_skip_non_relevant_states() + { + // given + _server = FluentMockServer.Start(); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .InScenario("s") + .WhenStateIs("Test state") + .RespondWith(Response.Create()); + + // when + var response = await new HttpClient().GetAsync("http://localhost:" + _server.Ports[0] + "/foo"); + + // then + Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound); + } + + [Fact] + public async Task Should_process_request_if_equals_state_and_single_state_defined() + { + // given + _server = FluentMockServer.Start(); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .InScenario("s") + .WillSetStateTo("Test state") + .RespondWith(Response.Create() + .WithBody("No state msg")); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .InScenario("s") + .WhenStateIs("Test state") + .RespondWith(Response.Create() + .WithBody("Test state msg")); + + // when + var responseNoState = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo"); + var responseWithState = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/foo"); + + // then + Check.That(responseNoState).Equals("No state msg"); + Check.That(responseWithState).Equals("Test state msg"); + } + + [Fact] + public async Task Should_process_request_if_equals_state_and_multiple_state_defined() + { + // given + _server = FluentMockServer.Start(); + + _server + .Given(Request.Create() + .WithPath("/state1") + .UsingGet()) + .InScenario("s1") + .WillSetStateTo("Test state 1") + .RespondWith(Response.Create() + .WithBody("No state msg 1")); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .InScenario("s1") + .WhenStateIs("Test state 1") + .RespondWith(Response.Create() + .WithBody("Test state msg 1")); + + _server + .Given(Request.Create() + .WithPath("/state2") + .UsingGet()) + .InScenario("s2") + .WillSetStateTo("Test state 2") + .RespondWith(Response.Create() + .WithBody("No state msg 2")); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .InScenario("s2") + .WhenStateIs("Test state 2") + .RespondWith(Response.Create() + .WithBody("Test state msg 2")); + + // when + string url = "http://localhost:" + _server.Ports[0]; + var responseNoState1 = await new HttpClient().GetStringAsync(url + "/state1"); + var responseNoState2 = await new HttpClient().GetStringAsync(url + "/state2"); + + var responseWithState1 = await new HttpClient().GetStringAsync(url + "/foo"); + var responseWithState2 = await new HttpClient().GetStringAsync(url + "/foo"); + + // then + Check.That(responseNoState1).Equals("No state msg 1"); + Check.That(responseWithState1).Equals("Test state msg 1"); + Check.That(responseNoState2).Equals("No state msg 2"); + Check.That(responseWithState2).Equals("Test state msg 2"); + } + + public void Dispose() + { + _server?.Dispose(); + } + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs new file mode 100644 index 00000000..a7c5f2d7 --- /dev/null +++ b/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs @@ -0,0 +1,44 @@ +//using Microsoft.Owin; +//using Moq; +//using NFluent; +//using WireMock.Owin; +//using Xunit; + +//namespace WireMock.Net.Tests +//{ +// public class WireMockMiddlewareTests +// { +// private readonly ObjectMother _objectMother = new ObjectMother(); + +// [Fact] +// public void Should_have_default_state_as_null() +// { +// // given + +// // when +// var sut = _objectMother.Create(); + +// // then +// Check.That(sut.States).IsNull(); +// } + +// private class ObjectMother +// { +// private Mock OwinMiddleware { get; } +// private Mock OwinContext { get; } +// private WireMockMiddlewareOptions WireMockMiddlewareOptions { get; } + +// public ObjectMother() +// { +// OwinContext = new Mock(); +// OwinMiddleware = new Mock(null); +// WireMockMiddlewareOptions = new WireMockMiddlewareOptions(); +// } + +// public WireMockMiddleware Create() +// { +// return new WireMockMiddleware(OwinMiddleware.Object, WireMockMiddlewareOptions); +// } +// } +// } +//} \ No newline at end of file