diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs index bebff0e1..94315092 100644 --- a/src/WireMock.Net/Mapping.cs +++ b/src/WireMock.Net/Mapping.cs @@ -34,6 +34,17 @@ namespace WireMock /// public int Priority { get; } + /// + /// Execution state condition for the current mapping. + /// + 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. + /// + public object NextState { get; } + /// /// The Request matcher. /// @@ -53,8 +64,25 @@ namespace WireMock /// The provider. /// The priority for this mapping. public Mapping(Guid guid, [CanBeNull] string title, IRequestMatcher requestMatcher, IResponseProvider provider, int priority) + : this(guid, title, requestMatcher, provider, priority, null, 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. + /// State in which the current mapping can occur. Happens if not null + /// The next state which will occur after the current mapping execution. Happens if not null + public Mapping(Guid guid, [CanBeNull] string title, IRequestMatcher requestMatcher, IResponseProvider provider, int priority, object executionConditionState, object nextState) { Priority = priority; + ExecutionConditionState = executionConditionState; + NextState = nextState; Guid = guid; Title = title; RequestMatcher = requestMatcher; diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index 529082d6..ab3c13d3 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -24,15 +24,19 @@ namespace WireMock.Owin private readonly OwinRequestMapper _requestMapper = new OwinRequestMapper(); private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper(); + public object State { get; private set; } + #if !NETSTANDARD public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next) { _options = options; + State = null; } #else public WireMockMiddleware(RequestDelegate next, WireMockMiddlewareOptions options) { _options = options; + State = null; } #endif @@ -51,6 +55,7 @@ namespace WireMock.Owin try { var mappings = _options.Mappings + .Where(m => object.Equals(m.ExecutionConditionState, State)) .Select(m => new { Mapping = m, @@ -107,6 +112,7 @@ namespace WireMock.Owin } response = await targetMapping.ResponseToAsync(request); + State = 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/Server/IRespondWithAProvider.cs b/src/WireMock.Net/Server/IRespondWithAProvider.cs index 33a31579..93fe0e5b 100644 --- a/src/WireMock.Net/Server/IRespondWithAProvider.cs +++ b/src/WireMock.Net/Server/IRespondWithAProvider.cs @@ -40,5 +40,19 @@ namespace WireMock.Server /// /// The provider. void RespondWith(IResponseProvider provider); + + /// + /// 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..afde9558 100644 --- a/src/WireMock.Net/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net/Server/RespondWithAProvider.cs @@ -12,6 +12,9 @@ namespace WireMock.Server private Guid? _guid; private string _title; + private object _executionConditionState = null; + private object _nextState = null; + /// /// The _registration callback. /// @@ -42,7 +45,19 @@ 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, _executionConditionState, _nextState)); + } + + public IRespondWithAProvider WhenStateIs(object state) + { + _executionConditionState = state; + return this; + } + + public IRespondWithAProvider WillSetStateTo(object state) + { + _nextState = state; + return this; } /// 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..db24aeeb --- /dev/null +++ b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs @@ -0,0 +1,77 @@ +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()) + .WhenStateIs("Test state") + .RespondWith(Response.Create() + .WithStatusCode(200) + .WithBody(@"{ msg: ""Hello world!""}")); + + // 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() + { + // given + _server = FluentMockServer.Start(); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .WillSetStateTo("Test state") + .RespondWith(Response.Create() + .WithStatusCode(200) + .WithBody(@"No state msg")); + + _server + .Given(Request.Create() + .WithPath("/foo") + .UsingGet()) + .WhenStateIs("Test state") + .RespondWith(Response.Create() + .WithStatusCode(200) + .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"); + } + + public void Dispose() + { + _server?.Dispose(); + } + } +} diff --git a/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs new file mode 100644 index 00000000..13abf057 --- /dev/null +++ b/test/WireMock.Net.Tests/WireMockMiddlewareTests.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +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.State).IsNull(); + } + + internal class ObjectMother + { + public Mock OwinMiddleware { get; set; } + public Mock OwinContext { get; set; } + public WireMockMiddlewareOptions WireMockMiddlewareOptions { get; set; } + + public ObjectMother() + { + OwinContext = new Mock(); + OwinMiddleware = new Mock(null); + WireMockMiddlewareOptions = new WireMockMiddlewareOptions(); + } + + public WireMockMiddleware Create() + { + return new WireMockMiddleware(OwinMiddleware.Object, WireMockMiddlewareOptions); + } + } + } +}