Add Scenario set State method (#1322)

* Add SetScenarioState

* add tests

* summary

* .

* 1.8.13-preview-01

* fix

* fix name
This commit is contained in:
Stef Heyenrath
2025-06-23 08:03:11 +02:00
committed by GitHub
parent 43cff52b69
commit f80925c1fb
11 changed files with 512 additions and 274 deletions

View File

@@ -4,7 +4,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<VersionPrefix>1.8.12</VersionPrefix> <VersionPrefix>1.8.13-preview-02</VersionPrefix>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon> <PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/wiremock/WireMock.Net</PackageProjectUrl> <PackageProjectUrl>https://github.com/wiremock/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>

View File

@@ -11,6 +11,10 @@
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" /> <ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Update="SonarAnalyzer.CSharp" Version="10.12.0.118525" />
</ItemGroup>
<!--<ItemGroup> <!--<ItemGroup>
<PackageReference Include="WireMock.Net" Version="1.8.11" /> <PackageReference Include="WireMock.Net" Version="1.8.11" />
</ItemGroup>--> </ItemGroup>-->

View File

@@ -0,0 +1,15 @@
// Copyright © WireMock.Net
namespace WireMock.Admin.Scenarios;
/// <summary>
/// ScenarioStateModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class ScenarioStateUpdateModel
{
/// <summary>
/// Gets or sets the NextState.
/// </summary>
public string? State { get; set; }
}

View File

@@ -161,6 +161,11 @@ public interface IWireMockServer : IDisposable
/// </summary> /// </summary>
bool ResetScenario(string name); bool ResetScenario(string name);
/// <summary>
/// Sets a scenario to a state.
/// </summary>
bool SetScenarioState(string name, string? state);
/// <summary> /// <summary>
/// Resets the LogEntries. /// Resets the LogEntries.
/// </summary> /// </summary>

View File

@@ -86,7 +86,7 @@ public interface IMapping
WireMockServerSettings Settings { get; } WireMockServerSettings Settings { get; }
/// <summary> /// <summary>
/// Is State started ? /// Indicates if the state is started or manually set to a value.
/// </summary> /// </summary>
bool IsStartState { get; } bool IsStartState { get; }

View File

@@ -66,6 +66,7 @@ public partial class WireMockServer
public RegexMatcher MappingsCodeGuidPathMatcher => new($"^{_prefixEscaped}\\/mappings\\/code\\/([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}})$"); public RegexMatcher MappingsCodeGuidPathMatcher => new($"^{_prefixEscaped}\\/mappings\\/code\\/([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}})$");
public RegexMatcher RequestsGuidPathMatcher => new($"^{_prefixEscaped}\\/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}})$"); public RegexMatcher RequestsGuidPathMatcher => new($"^{_prefixEscaped}\\/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}})$");
public RegexMatcher ScenariosNameMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+$"); public RegexMatcher ScenariosNameMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+$");
public RegexMatcher ScenariosNameWithStateMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/state$");
public RegexMatcher ScenariosNameWithResetMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/reset$"); public RegexMatcher ScenariosNameWithResetMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/reset$");
public RegexMatcher FilesFilenamePathMatcher => new($"^{_prefixEscaped}\\/files\\/.+$"); public RegexMatcher FilesFilenamePathMatcher => new($"^{_prefixEscaped}\\/files\\/.+$");
public RegexMatcher ProtoDefinitionsIdPathMatcher => new($"^{_prefixEscaped}\\/protodefinitions\\/.+$"); public RegexMatcher ProtoDefinitionsIdPathMatcher => new($"^{_prefixEscaped}\\/protodefinitions\\/.+$");
@@ -138,6 +139,9 @@ public partial class WireMockServer
Given(Request.Create().WithPath(_adminPaths.Scenarios + "/reset").UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset)); Given(Request.Create().WithPath(_adminPaths.Scenarios + "/reset").UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
Given(Request.Create().WithPath(_adminPaths.ScenariosNameWithResetMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenarioReset)); Given(Request.Create().WithPath(_adminPaths.ScenariosNameWithResetMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenarioReset));
// __admin/scenarios/{scenario}/state
Given(Request.Create().WithPath(_adminPaths.ScenariosNameWithStateMatcher).UsingPut()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosSetState));
// __admin/files/{filename} // __admin/files/{filename}
Given(Request.Create().WithPath(_adminPaths.FilesFilenamePathMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePost)); Given(Request.Create().WithPath(_adminPaths.FilesFilenamePathMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePost));
Given(Request.Create().WithPath(_adminPaths.FilesFilenamePathMatcher).UsingPut()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePut)); Given(Request.Create().WithPath(_adminPaths.FilesFilenamePathMatcher).UsingPut()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePut));
@@ -705,6 +709,21 @@ public partial class WireMockServer
ResponseMessageBuilder.Create(200, "Scenario reset") : ResponseMessageBuilder.Create(200, "Scenario reset") :
ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'."); ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'.");
} }
private IResponseMessage ScenariosSetState(IRequestMessage requestMessage)
{
var name = requestMessage.Path.Split('/').Reverse().Skip(1).First();
if (!_options.Scenarios.ContainsKey(name))
{
ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'.");
}
var update = DeserializeObject<ScenarioStateUpdateModel>(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}'.");
}
#endregion #endregion
#region Pact #region Pact

View File

@@ -567,6 +567,32 @@ public partial class WireMockServer : IWireMockServer
return _options.Scenarios.ContainsKey(name) && _options.Scenarios.TryRemove(name, out _); return _options.Scenarios.ContainsKey(name) && _options.Scenarios.TryRemove(name, out _);
} }
/// <inheritdoc />
[PublicAPI]
public bool SetScenarioState(string name, string? state)
{
if (state == null)
{
return ResetScenario(name);
}
_options.Scenarios.AddOrUpdate(
name,
_ => new ScenarioState
{
Name = name,
NextState = state
},
(_, current) =>
{
current.NextState = state;
return current;
}
);
return true;
}
/// <inheritdoc cref="IWireMockServer.WithMapping(MappingModel[])" /> /// <inheritdoc cref="IWireMockServer.WithMapping(MappingModel[])" />
[PublicAPI] [PublicAPI]
public IWireMockServer WithMapping(params MappingModel[] mappings) public IWireMockServer WithMapping(params MappingModel[] mappings)

View File

@@ -256,7 +256,7 @@ public interface IWireMockAdminApi
/// Delete (reset) all scenarios /// Delete (reset) all scenarios
/// </summary> /// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param> /// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("scenarios")] [Post("scenarios/reset")]
Task<StatusModel> ResetScenariosAsync(CancellationToken cancellationToken = default); Task<StatusModel> ResetScenariosAsync(CancellationToken cancellationToken = default);
/// <summary> /// <summary>
@@ -269,7 +269,7 @@ public interface IWireMockAdminApi
Task<StatusModel> DeleteScenarioAsync([Path] string name, CancellationToken cancellationToken = default); Task<StatusModel> DeleteScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Delete (reset) all scenarios /// Delete (reset) a specific scenario
/// </summary> /// </summary>
/// <param name="name">Scenario name.</param> /// <param name="name">Scenario name.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param> /// <param name="cancellationToken">The optional cancellationToken.</param>
@@ -277,6 +277,16 @@ public interface IWireMockAdminApi
[AllowAnyStatusCode] [AllowAnyStatusCode]
Task<StatusModel> ResetScenarioAsync([Path] string name, CancellationToken cancellationToken = default); Task<StatusModel> ResetScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
/// <summary>
/// Update the state for a scenario.
/// </summary>
/// <param name="name">Scenario name.</param>
/// <param name="updateModel">Scenario state update model.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Put("scenarios/{name}/state")]
[AllowAnyStatusCode]
Task<StatusModel> PutScenarioStateAsync([Path] string name, [Body] ScenarioStateUpdateModel updateModel, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Create a new File /// Create a new File
/// </summary> /// </summary>

View File

@@ -17,6 +17,7 @@ using RestEase;
using VerifyTests; using VerifyTests;
using VerifyXunit; using VerifyXunit;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Admin.Scenarios;
using WireMock.Admin.Settings; using WireMock.Admin.Settings;
using WireMock.Client; using WireMock.Client;
using WireMock.Client.Extensions; using WireMock.Client.Extensions;
@@ -743,6 +744,57 @@ public partial class WireMockAdminApiTests
status.Status.Should().Be("No scenario found by name 'x'."); status.Status.Should().Be("No scenario found by name 'x'.");
} }
[Fact]
public async Task IWireMockAdminApi_UpdateNonExistingScenarioState()
{
// Arrange
using var server = WireMockServer.StartWithAdminInterface();
var api = RestClient.For<IWireMockAdminApi>(server.Urls[0]);
// Act
var update = new ScenarioStateUpdateModel
{
State = null
};
var status = await api.PutScenarioStateAsync("x", update).ConfigureAwait(false);
status.Status.Should().Be("No scenario found by name 'x'.");
}
[Fact]
public async Task IWireMockAdminApi_UpdateScenarioState()
{
// Arrange
using var server = WireMockServer.StartWithAdminInterface();
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("/foostate1")
.UsingGet())
.InScenario("s1")
.WhenStateIs("Test state 1")
.RespondWith(Response.Create()
.WithBody("Test state msg 1"));
var api = RestClient.For<IWireMockAdminApi>(server.Urls[0]);
// Act
var update = new ScenarioStateUpdateModel
{
State = null
};
var status = await api.PutScenarioStateAsync("s1", update).ConfigureAwait(false);
status.Status.Should().Be("Scenario state set to ''");
}
[Fact] [Fact]
public async Task IWireMockAdminApi_GetMappingByGuidAsync() public async Task IWireMockAdminApi_GetMappingByGuidAsync()
{ {

View File

@@ -6,5 +6,5 @@ internal static class Constants
{ {
internal const int NumStaticMappings = 10; internal const int NumStaticMappings = 10;
internal const int NumAdminMappings = 36; internal const int NumAdminMappings = 37;
} }

View File

@@ -12,340 +12,447 @@ using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
using Xunit; using Xunit;
namespace WireMock.Net.Tests namespace WireMock.Net.Tests;
public class StatefulBehaviorTests
{ {
public class StatefulBehaviorTests [Fact]
public async Task Scenarios_Should_skip_non_relevant_states()
{ {
[Fact] // given
public async Task Scenarios_Should_skip_non_relevant_states() string path = $"/foo_{Guid.NewGuid()}";
{ var server = WireMockServer.Start();
// given
string path = $"/foo_{Guid.NewGuid()}";
var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("s") .InScenario("s")
.WhenStateIs("Test state") .WhenStateIs("Test state")
.RespondWith(Response.Create()); .RespondWith(Response.Create());
// when // when
var response = await new HttpClient().GetAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var response = await new HttpClient().GetAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
// then // then
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound); Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
server.Stop(); server.Stop();
} }
[Fact] [Fact]
public async Task Scenarios_Should_process_request_if_equals_state_and_single_state_defined() public async Task Scenarios_Should_process_request_if_equals_state_and_single_state_defined()
{ {
// given // Arrange
string path = $"/foo_{Guid.NewGuid()}"; var path = $"/foo_{Guid.NewGuid()}";
var server = WireMockServer.Start(); using var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("s") .InScenario("s")
.WillSetStateTo("Test state") .WillSetStateTo("Test state")
.RespondWith(Response.Create().WithBody("No state msg")); .RespondWith(Response.Create().WithBody("No state msg"));
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("s") .InScenario("s")
.WhenStateIs("Test state") .WhenStateIs("Test state")
.RespondWith(Response.Create().WithBody("Test state msg")); .RespondWith(Response.Create().WithBody("Test state msg"));
// when // Act
var responseNoState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var responseNoState = await new HttpClient().GetStringAsync(server.Url + path).ConfigureAwait(false);
var responseWithState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var responseWithState = await new HttpClient().GetStringAsync(server.Url + path).ConfigureAwait(false);
// then // Assert
Check.That(responseNoState).Equals("No state msg"); Check.That(responseNoState).Equals("No state msg");
Check.That(responseWithState).Equals("Test state msg"); Check.That(responseWithState).Equals("Test state msg");
}
server.Stop(); [Theory]
} [InlineData(null, "step 1", "step 2")]
[InlineData("step 2", "step 2", "step 3")]
public async Task Scenarios_Should_ContinueOnCorrectState_WhenStateIsUpdated(string? state, string expected1, string expected2)
{
// Arrange
var path = $"/foo_{Guid.NewGuid()}";
var scenario = "s";
using var server = WireMockServer.Start();
[Fact] server
public async Task Scenarios_With_Same_Path_Should_Use_Times_When_Moving_To_Next_State() .Given(Request.Create().WithPath(path).UsingGet())
{ .InScenario(scenario)
// given .WillSetStateTo("step 2")
const int times = 2; .RespondWith(Response.Create().WithBody("step 1"));
string path = $"/foo_{Guid.NewGuid()}";
string body1 = "Scenario S1, No State, Setting State T2";
string body2 = "Scenario S1, State T2, End";
var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario(1) .InScenario(scenario)
.WillSetStateTo(2, times) .WhenStateIs("step 2")
.RespondWith(Response.Create().WithBody(body1)); .WillSetStateTo("step 3")
.RespondWith(Response.Create().WithBody("step 2"));
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario(1) .InScenario(scenario)
.WhenStateIs(2) .WhenStateIs("step 3")
.RespondWith(Response.Create().WithBody(body2)); .RespondWith(Response.Create().WithBody("step 3"));
// when // Act
var client = new HttpClient(); var client = server.CreateClient();
var responseScenario1 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var response1 = await client.GetStringAsync(server.Url + path);
var responseScenario2 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var response2 = await client.GetStringAsync(server.Url + path);
var responseWithState = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var response3 = await client.GetStringAsync(server.Url + path);
// then server.SetScenarioState(scenario, state);
responseScenario1.Should().Be(body1); var responseA = await client.GetStringAsync(server.Url + path);
responseScenario2.Should().Be(body1); var responseB = await client.GetStringAsync(server.Url + path);
responseWithState.Should().Be(body2);
server.Stop(); // Assert
} Check.That(response1).Equals("step 1");
Check.That(response2).Equals("step 2");
Check.That(response3).Equals("step 3");
Check.That(responseA).Equals(expected1);
Check.That(responseB).Equals(expected2);
}
[Fact] [Fact]
public async Task Scenarios_With_Different_Paths_Should_Use_Times_When_Moving_To_Next_State() public async Task Scenarios_With_Same_Path_Should_Use_Times_When_Moving_To_Next_State()
{ {
// given // given
const int times = 2; const int times = 2;
string path1 = $"/a_{Guid.NewGuid()}"; string path = $"/foo_{Guid.NewGuid()}";
string path2 = $"/b_{Guid.NewGuid()}"; string body1 = "Scenario S1, No State, Setting State T2";
string path3 = $"/c_{Guid.NewGuid()}"; string body2 = "Scenario S1, State T2, End";
string body1 = "Scenario S1, No State, Setting State T2"; var server = WireMockServer.Start();
string body2 = "Scenario S1, State T2, Setting State T3";
string body3 = "Scenario S1, State T3, End";
var server = WireMockServer.Start(); server
.Given(Request.Create().WithPath(path).UsingGet())
.InScenario(1)
.WillSetStateTo(2, times)
.RespondWith(Response.Create().WithBody(body1));
server server
.Given(Request.Create().WithPath(path1).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("S1") .InScenario(1)
.WillSetStateTo("T2", times) .WhenStateIs(2)
.RespondWith(Response.Create().WithBody(body1)); .RespondWith(Response.Create().WithBody(body2));
server // when
.Given(Request.Create().WithPath(path2).UsingGet()) var client = new HttpClient();
.InScenario("S1") var responseScenario1 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
.WhenStateIs("T2") var responseScenario2 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
.WillSetStateTo("T3", times) var responseWithState = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
.RespondWith(Response.Create().WithBody(body2));
server // then
.Given(Request.Create().WithPath(path3).UsingGet()) responseScenario1.Should().Be(body1);
.InScenario("S1") responseScenario2.Should().Be(body1);
.WhenStateIs("T3") responseWithState.Should().Be(body2);
.RespondWith(Response.Create().WithBody(body3));
// when server.Stop();
var client = new HttpClient(); }
var t1a = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path1).ConfigureAwait(false);
var t1b = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path1).ConfigureAwait(false);
var t2a = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path2).ConfigureAwait(false);
var t2b = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path2).ConfigureAwait(false);
var t3 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path3).ConfigureAwait(false);
// then [Fact]
t1a.Should().Be(body1); public async Task Scenarios_With_Different_Paths_Should_Use_Times_When_Moving_To_Next_State()
t1b.Should().Be(body1); {
t2a.Should().Be(body2); // given
t2b.Should().Be(body2); const int times = 2;
t3.Should().Be(body3); string path1 = $"/a_{Guid.NewGuid()}";
string path2 = $"/b_{Guid.NewGuid()}";
string path3 = $"/c_{Guid.NewGuid()}";
string body1 = "Scenario S1, No State, Setting State T2";
string body2 = "Scenario S1, State T2, Setting State T3";
string body3 = "Scenario S1, State T3, End";
server.Stop(); var server = WireMockServer.Start();
}
[Fact] server
public async Task Scenarios_Should_Respect_Int_Valued_Scenarios_and_States() .Given(Request.Create().WithPath(path1).UsingGet())
{ .InScenario("S1")
// given .WillSetStateTo("T2", times)
string path = $"/foo_{Guid.NewGuid()}"; .RespondWith(Response.Create().WithBody(body1));
var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path2).UsingGet())
.InScenario(1) .InScenario("S1")
.WillSetStateTo(2) .WhenStateIs("T2")
.RespondWith(Response.Create().WithBody("Scenario 1, Setting State 2")); .WillSetStateTo("T3", times)
.RespondWith(Response.Create().WithBody(body2));
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path3).UsingGet())
.InScenario(1) .InScenario("S1")
.WhenStateIs(2) .WhenStateIs("T3")
.RespondWith(Response.Create().WithBody("Scenario 1, State 2")); .RespondWith(Response.Create().WithBody(body3));
// when // when
var responseIntScenario = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var client = new HttpClient();
var responseWithIntState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var t1a = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path1).ConfigureAwait(false);
var t1b = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path1).ConfigureAwait(false);
var t2a = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path2).ConfigureAwait(false);
var t2b = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path2).ConfigureAwait(false);
var t3 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path3).ConfigureAwait(false);
// then // then
Check.That(responseIntScenario).Equals("Scenario 1, Setting State 2"); t1a.Should().Be(body1);
Check.That(responseWithIntState).Equals("Scenario 1, State 2"); t1b.Should().Be(body1);
t2a.Should().Be(body2);
t2b.Should().Be(body2);
t3.Should().Be(body3);
server.Stop(); server.Stop();
} }
[Fact] [Fact]
public async Task Scenarios_Should_Respect_Mixed_String_Scenario_and_Int_State() public async Task Scenarios_Should_Respect_Int_Valued_Scenarios_and_States()
{ {
// given // given
string path = $"/foo_{Guid.NewGuid()}"; string path = $"/foo_{Guid.NewGuid()}";
var server = WireMockServer.Start(); var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("state string") .InScenario(1)
.WillSetStateTo(1) .WillSetStateTo(2)
.RespondWith(Response.Create().WithBody("string state, Setting State 2")); .RespondWith(Response.Create().WithBody("Scenario 1, Setting State 2"));
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("state string") .InScenario(1)
.WhenStateIs(1) .WhenStateIs(2)
.RespondWith(Response.Create().WithBody("string state, State 2")); .RespondWith(Response.Create().WithBody("Scenario 1, State 2"));
// when // when
var responseIntScenario = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var responseIntScenario = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
var responseWithIntState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var responseWithIntState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
// then // then
Check.That(responseIntScenario).Equals("string state, Setting State 2"); Check.That(responseIntScenario).Equals("Scenario 1, Setting State 2");
Check.That(responseWithIntState).Equals("string state, State 2"); Check.That(responseWithIntState).Equals("Scenario 1, State 2");
server.Stop(); server.Stop();
} }
[Fact] [Fact]
public async Task Scenarios_Should_Respect_Mixed_Int_Scenario_and_String_Scenario_and_String_State() public async Task Scenarios_Should_Respect_Mixed_String_Scenario_and_Int_State()
{ {
// given // given
string path = $"/foo_{Guid.NewGuid()}"; string path = $"/foo_{Guid.NewGuid()}";
var server = WireMockServer.Start(); var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario(1) .InScenario("state string")
.WillSetStateTo("Next State") .WillSetStateTo(1)
.RespondWith(Response.Create().WithBody("int state, Setting State 2")); .RespondWith(Response.Create().WithBody("string state, Setting State 2"));
server server
.Given(Request.Create().WithPath(path).UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("1") .InScenario("state string")
.WhenStateIs("Next State") .WhenStateIs(1)
.RespondWith(Response.Create().WithBody("string state, State 2")); .RespondWith(Response.Create().WithBody("string state, State 2"));
// when // when
var responseIntScenario = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var responseIntScenario = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
var responseWithIntState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false); var responseWithIntState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
// then // then
Check.That(responseIntScenario).Equals("int state, Setting State 2"); Check.That(responseIntScenario).Equals("string state, Setting State 2");
Check.That(responseWithIntState).Equals("string state, State 2"); Check.That(responseWithIntState).Equals("string state, State 2");
server.Stop(); server.Stop();
} }
[Fact] [Fact]
public async Task Scenarios_TodoList_Example() public async Task Scenarios_Should_Respect_Mixed_Int_Scenario_and_String_Scenario_and_String_State()
{ {
// Assign // given
var server = WireMockServer.Start(); string path = $"/foo_{Guid.NewGuid()}";
var server = WireMockServer.Start();
server server
.Given(Request.Create().WithPath("/todo/items").UsingGet()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("To do list") .InScenario(1)
.WillSetStateTo("TodoList State Started") .WillSetStateTo("Next State")
.RespondWith(Response.Create().WithBody("Buy milk")); .RespondWith(Response.Create().WithBody("int state, Setting State 2"));
server server
.Given(Request.Create().WithPath("/todo/items").UsingPost()) .Given(Request.Create().WithPath(path).UsingGet())
.InScenario("To do list") .InScenario("1")
.WhenStateIs("TodoList State Started") .WhenStateIs("Next State")
.WillSetStateTo("Cancel newspaper item added") .RespondWith(Response.Create().WithBody("string state, State 2"));
.RespondWith(Response.Create().WithStatusCode(201));
server // when
.Given(Request.Create().WithPath("/todo/items").UsingGet()) var responseIntScenario = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
.InScenario("To do list") var responseWithIntState = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + path).ConfigureAwait(false);
.WhenStateIs("Cancel newspaper item added")
.RespondWith(Response.Create().WithBody("Buy milk;Cancel newspaper subscription"));
Check.That(server.Scenarios.Any()).IsFalse(); // then
Check.That(responseIntScenario).Equals("int state, Setting State 2");
Check.That(responseWithIntState).Equals("string state, State 2");
// Act and Assert server.Stop();
string url = "http://localhost:" + server.Ports[0]; }
string getResponse1 = new HttpClient().GetStringAsync(url + "/todo/items").Result;
Check.That(getResponse1).Equals("Buy milk");
Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list"); [Fact]
Check.That(server.Scenarios["To do list"].NextState).IsEqualTo("TodoList State Started"); public async Task Scenarios_TodoList_Example()
Check.That(server.Scenarios["To do list"].Started).IsTrue(); {
Check.That(server.Scenarios["To do list"].Finished).IsFalse(); // Arrange
var server = WireMockServer.Start();
var client = server.CreateClient();
var postResponse = await new HttpClient().PostAsync(url + "/todo/items", new StringContent("Cancel newspaper subscription")).ConfigureAwait(false); server
Check.That(postResponse.StatusCode).Equals(HttpStatusCode.Created); .Given(Request.Create().WithPath("/todo/items").UsingGet())
.InScenario("To do list")
.WillSetStateTo("TodoList State Started")
.RespondWith(Response.Create().WithBody("Buy milk"));
Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list"); server
Check.That(server.Scenarios["To do list"].NextState).IsEqualTo("Cancel newspaper item added"); .Given(Request.Create().WithPath("/todo/items").UsingPost())
Check.That(server.Scenarios["To do list"].Started).IsTrue(); .InScenario("To do list")
Check.That(server.Scenarios["To do list"].Finished).IsFalse(); .WhenStateIs("TodoList State Started")
.WillSetStateTo("Cancel newspaper item added")
.RespondWith(Response.Create().WithStatusCode(201));
string getResponse2 = await new HttpClient().GetStringAsync(url + "/todo/items").ConfigureAwait(false); server
Check.That(getResponse2).Equals("Buy milk;Cancel newspaper subscription"); .Given(Request.Create().WithPath("/todo/items").UsingGet())
.InScenario("To do list")
.WhenStateIs("Cancel newspaper item added")
.RespondWith(Response.Create().WithBody("Buy milk;Cancel newspaper subscription"));
Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list"); Check.That(server.Scenarios.Any()).IsFalse();
Check.That(server.Scenarios["To do list"].NextState).IsNull();
Check.That(server.Scenarios["To do list"].Started).IsTrue();
Check.That(server.Scenarios["To do list"].Finished).IsTrue();
server.Stop(); // Act and Assert
} var getResponse1 = await client.GetStringAsync("/todo/items").ConfigureAwait(false);
Check.That(getResponse1).Equals("Buy milk");
[Fact] Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list");
public async Task Scenarios_Should_process_request_if_equals_state_and_multiple_state_defined() Check.That(server.Scenarios["To do list"].NextState).IsEqualTo("TodoList State Started");
{ Check.That(server.Scenarios["To do list"].Started).IsTrue();
// Assign Check.That(server.Scenarios["To do list"].Finished).IsFalse();
var server = WireMockServer.Start();
server var postResponse = await client.PostAsync("/todo/items", new StringContent("Cancel newspaper subscription")).ConfigureAwait(false);
.Given(Request.Create().WithPath("/state1").UsingGet()) Check.That(postResponse.StatusCode).Equals(HttpStatusCode.Created);
.InScenario("s1")
.WillSetStateTo("Test state 1")
.RespondWith(Response.Create().WithBody("No state msg 1"));
server Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list");
.Given(Request.Create().WithPath("/foo1X").UsingGet()) Check.That(server.Scenarios["To do list"].NextState).IsEqualTo("Cancel newspaper item added");
.InScenario("s1") Check.That(server.Scenarios["To do list"].Started).IsTrue();
.WhenStateIs("Test state 1") Check.That(server.Scenarios["To do list"].Finished).IsFalse();
.RespondWith(Response.Create().WithBody("Test state msg 1"));
server string getResponse2 = await client.GetStringAsync("/todo/items").ConfigureAwait(false);
.Given(Request.Create().WithPath("/state2").UsingGet()) Check.That(getResponse2).Equals("Buy milk;Cancel newspaper subscription");
.InScenario("s2")
.WillSetStateTo("Test state 2")
.RespondWith(Response.Create().WithBody("No state msg 2"));
server Check.That(server.Scenarios["To do list"].Name).IsEqualTo("To do list");
.Given(Request.Create().WithPath("/foo2X").UsingGet()) Check.That(server.Scenarios["To do list"].NextState).IsNull();
.InScenario("s2") Check.That(server.Scenarios["To do list"].Started).IsTrue();
.WhenStateIs("Test state 2") Check.That(server.Scenarios["To do list"].Finished).IsTrue();
.RespondWith(Response.Create().WithBody("Test state msg 2"));
// Act and Assert server.Stop();
string url = "http://localhost:" + server.Ports[0]; }
var responseNoState1 = await new HttpClient().GetStringAsync(url + "/state1").ConfigureAwait(false);
Check.That(responseNoState1).Equals("No state msg 1");
var responseNoState2 = await new HttpClient().GetStringAsync(url + "/state2").ConfigureAwait(false); [Fact]
Check.That(responseNoState2).Equals("No state msg 2"); public async Task Scenarios_TodoList_WithSetState()
{
// Arrange
var scenario = "To do list";
using var server = WireMockServer.Start();
var client = server.CreateClient();
var responseWithState1 = await new HttpClient().GetStringAsync(url + "/foo1X").ConfigureAwait(false); server
Check.That(responseWithState1).Equals("Test state msg 1"); .Given(Request.Create().WithPath("/todo/items").UsingGet())
.InScenario(scenario)
.WhenStateIs("Buy milk")
.RespondWith(Response.Create().WithBody("Buy milk"));
var responseWithState2 = await new HttpClient().GetStringAsync(url + "/foo2X").ConfigureAwait(false); server
Check.That(responseWithState2).Equals("Test state msg 2"); .Given(Request.Create().WithPath("/todo/items").UsingGet())
.InScenario(scenario)
.WhenStateIs("Cancel newspaper")
.RespondWith(Response.Create().WithBody("Buy milk;Cancel newspaper subscription"));
server.Stop(); // Act and Assert
} server.SetScenarioState(scenario, "Buy milk");
server.Scenarios[scenario].Should().BeEquivalentTo(new { Name = scenario, NextState = "Buy milk" });
var getResponse1 = await client.GetStringAsync("/todo/items").ConfigureAwait(false);
getResponse1.Should().Be("Buy milk");
server.SetScenarioState(scenario, "Cancel newspaper");
server.Scenarios[scenario].Name.Should().Be(scenario);
server.Scenarios[scenario].Should().BeEquivalentTo(new { Name = scenario, NextState = "Cancel newspaper" });
var getResponse2 = await client.GetStringAsync("/todo/items").ConfigureAwait(false);
getResponse2.Should().Be("Buy milk;Cancel newspaper subscription");
}
[Fact]
public void Scenarios_TodoList_WithSetStateToNull_ShouldThrowException()
{
// Arrange
var scenario = "To do list";
using var server = WireMockServer.Start();
var client = server.CreateClient();
server
.Given(Request.Create().WithPath("/todo/items").UsingGet())
.InScenario(scenario)
.WhenStateIs("Buy milk")
.RespondWith(Response.Create().WithBody("Buy milk"));
server
.Given(Request.Create().WithPath("/todo/items").UsingGet())
.InScenario(scenario)
.WhenStateIs("Cancel newspaper")
.RespondWith(Response.Create().WithBody("Buy milk;Cancel newspaper subscription"));
// Act
server.SetScenarioState(scenario, null);
var action = async () => await client.GetStringAsync("/todo/items");
// Assert
action.Should().ThrowAsync<HttpRequestException>();
}
[Fact]
public async Task Scenarios_Should_process_request_if_equals_state_and_multiple_state_defined()
{
// Assign
var server = WireMockServer.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("/foo1X").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("/foo2X").UsingGet())
.InScenario("s2")
.WhenStateIs("Test state 2")
.RespondWith(Response.Create().WithBody("Test state msg 2"));
// Act and Assert
string url = "http://localhost:" + server.Ports[0];
var responseNoState1 = await new HttpClient().GetStringAsync(url + "/state1").ConfigureAwait(false);
Check.That(responseNoState1).Equals("No state msg 1");
var responseNoState2 = await new HttpClient().GetStringAsync(url + "/state2").ConfigureAwait(false);
Check.That(responseNoState2).Equals("No state msg 2");
var responseWithState1 = await new HttpClient().GetStringAsync(url + "/foo1X").ConfigureAwait(false);
Check.That(responseWithState1).Equals("Test state msg 1");
var responseWithState2 = await new HttpClient().GetStringAsync(url + "/foo2X").ConfigureAwait(false);
Check.That(responseWithState2).Equals("Test state msg 2");
server.Stop();
} }
} }