Skip to content

Commit f80925c

Browse files
authored
Add Scenario set State method (#1322)
* Add SetScenarioState * add tests * summary * . * 1.8.13-preview-01 * fix * fix name
1 parent 43cff52 commit f80925c

File tree

11 files changed

+576
-338
lines changed

11 files changed

+576
-338
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
</PropertyGroup>
55

66
<PropertyGroup>
7-
<VersionPrefix>1.8.12</VersionPrefix>
7+
<VersionPrefix>1.8.13-preview-02</VersionPrefix>
88
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
99
<PackageProjectUrl>https://github.com/wiremock/WireMock.Net</PackageProjectUrl>
1010
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>

examples/WireMock.Net.ConsoleApp.UsingNuGet/WireMock.Net.ConsoleApp.UsingNuGet.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
1212
</ItemGroup>
1313

14+
<ItemGroup>
15+
<PackageReference Update="SonarAnalyzer.CSharp" Version="10.12.0.118525" />
16+
</ItemGroup>
17+
1418
<!--<ItemGroup>
1519
<PackageReference Include="WireMock.Net" Version="1.8.11" />
1620
</ItemGroup>-->
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright © WireMock.Net
2+
3+
namespace WireMock.Admin.Scenarios;
4+
5+
/// <summary>
6+
/// ScenarioStateModel
7+
/// </summary>
8+
[FluentBuilder.AutoGenerateBuilder]
9+
public class ScenarioStateUpdateModel
10+
{
11+
/// <summary>
12+
/// Gets or sets the NextState.
13+
/// </summary>
14+
public string? State { get; set; }
15+
}

src/WireMock.Net.Abstractions/Server/IWireMockServer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ public interface IWireMockServer : IDisposable
161161
/// </summary>
162162
bool ResetScenario(string name);
163163

164+
/// <summary>
165+
/// Sets a scenario to a state.
166+
/// </summary>
167+
bool SetScenarioState(string name, string? state);
168+
164169
/// <summary>
165170
/// Resets the LogEntries.
166171
/// </summary>

src/WireMock.Net.Minimal/IMapping.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public interface IMapping
8686
WireMockServerSettings Settings { get; }
8787

8888
/// <summary>
89-
/// Is State started ?
89+
/// Indicates if the state is started or manually set to a value.
9090
/// </summary>
9191
bool IsStartState { get; }
9292

src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public AdminPaths(WireMockServerSettings settings)
6666
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}})$");
6767
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}})$");
6868
public RegexMatcher ScenariosNameMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+$");
69+
public RegexMatcher ScenariosNameWithStateMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/state$");
6970
public RegexMatcher ScenariosNameWithResetMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/reset$");
7071
public RegexMatcher FilesFilenamePathMatcher => new($"^{_prefixEscaped}\\/files\\/.+$");
7172
public RegexMatcher ProtoDefinitionsIdPathMatcher => new($"^{_prefixEscaped}\\/protodefinitions\\/.+$");
@@ -138,6 +139,9 @@ private void InitAdmin()
138139
Given(Request.Create().WithPath(_adminPaths.Scenarios + "/reset").UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
139140
Given(Request.Create().WithPath(_adminPaths.ScenariosNameWithResetMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenarioReset));
140141

142+
// __admin/scenarios/{scenario}/state
143+
Given(Request.Create().WithPath(_adminPaths.ScenariosNameWithStateMatcher).UsingPut()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosSetState));
144+
141145
// __admin/files/{filename}
142146
Given(Request.Create().WithPath(_adminPaths.FilesFilenamePathMatcher).UsingPost()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePost));
143147
Given(Request.Create().WithPath(_adminPaths.FilesFilenamePathMatcher).UsingPut()).AtPriority(WireMockConstants.AdminPriority).RespondWith(new DynamicResponseProvider(FilePut));
@@ -705,6 +709,21 @@ private IResponseMessage ScenarioReset(IRequestMessage requestMessage)
705709
ResponseMessageBuilder.Create(200, "Scenario reset") :
706710
ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'.");
707711
}
712+
713+
private IResponseMessage ScenariosSetState(IRequestMessage requestMessage)
714+
{
715+
var name = requestMessage.Path.Split('/').Reverse().Skip(1).First();
716+
if (!_options.Scenarios.ContainsKey(name))
717+
{
718+
ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'.");
719+
}
720+
721+
var update = DeserializeObject<ScenarioStateUpdateModel>(requestMessage);
722+
723+
return SetScenarioState(name, update.State) ?
724+
ResponseMessageBuilder.Create(200, $"Scenario state set to '{update.State}'") :
725+
ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'.");
726+
}
708727
#endregion
709728

710729
#region Pact

src/WireMock.Net.Minimal/Server/WireMockServer.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,32 @@ public bool ResetScenario(string name)
567567
return _options.Scenarios.ContainsKey(name) && _options.Scenarios.TryRemove(name, out _);
568568
}
569569

570+
/// <inheritdoc />
571+
[PublicAPI]
572+
public bool SetScenarioState(string name, string? state)
573+
{
574+
if (state == null)
575+
{
576+
return ResetScenario(name);
577+
}
578+
579+
_options.Scenarios.AddOrUpdate(
580+
name,
581+
_ => new ScenarioState
582+
{
583+
Name = name,
584+
NextState = state
585+
},
586+
(_, current) =>
587+
{
588+
current.NextState = state;
589+
return current;
590+
}
591+
);
592+
593+
return true;
594+
}
595+
570596
/// <inheritdoc cref="IWireMockServer.WithMapping(MappingModel[])" />
571597
[PublicAPI]
572598
public IWireMockServer WithMapping(params MappingModel[] mappings)

src/WireMock.Net.RestClient/IWireMockAdminApi.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ public interface IWireMockAdminApi
256256
/// Delete (reset) all scenarios
257257
/// </summary>
258258
/// <param name="cancellationToken">The optional cancellationToken.</param>
259-
[Post("scenarios")]
259+
[Post("scenarios/reset")]
260260
Task<StatusModel> ResetScenariosAsync(CancellationToken cancellationToken = default);
261261

262262
/// <summary>
@@ -269,14 +269,24 @@ public interface IWireMockAdminApi
269269
Task<StatusModel> DeleteScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
270270

271271
/// <summary>
272-
/// Delete (reset) all scenarios
272+
/// Delete (reset) a specific scenario
273273
/// </summary>
274274
/// <param name="name">Scenario name.</param>
275275
/// <param name="cancellationToken">The optional cancellationToken.</param>
276276
[Post("scenarios/{name}/reset")]
277277
[AllowAnyStatusCode]
278278
Task<StatusModel> ResetScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
279279

280+
/// <summary>
281+
/// Update the state for a scenario.
282+
/// </summary>
283+
/// <param name="name">Scenario name.</param>
284+
/// <param name="updateModel">Scenario state update model.</param>
285+
/// <param name="cancellationToken">The optional cancellationToken.</param>
286+
[Put("scenarios/{name}/state")]
287+
[AllowAnyStatusCode]
288+
Task<StatusModel> PutScenarioStateAsync([Path] string name, [Body] ScenarioStateUpdateModel updateModel, CancellationToken cancellationToken = default);
289+
280290
/// <summary>
281291
/// Create a new File
282292
/// </summary>

test/WireMock.Net.Tests/AdminApi/WireMockAdminApiTests.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using VerifyTests;
1818
using VerifyXunit;
1919
using WireMock.Admin.Mappings;
20+
using WireMock.Admin.Scenarios;
2021
using WireMock.Admin.Settings;
2122
using WireMock.Client;
2223
using WireMock.Client.Extensions;
@@ -743,6 +744,57 @@ public async Task IWireMockAdminApi_DeleteScenarioUsingPostAsync()
743744
status.Status.Should().Be("No scenario found by name 'x'.");
744745
}
745746

747+
[Fact]
748+
public async Task IWireMockAdminApi_UpdateNonExistingScenarioState()
749+
{
750+
// Arrange
751+
using var server = WireMockServer.StartWithAdminInterface();
752+
753+
var api = RestClient.For<IWireMockAdminApi>(server.Urls[0]);
754+
755+
// Act
756+
var update = new ScenarioStateUpdateModel
757+
{
758+
State = null
759+
};
760+
var status = await api.PutScenarioStateAsync("x", update).ConfigureAwait(false);
761+
status.Status.Should().Be("No scenario found by name 'x'.");
762+
}
763+
764+
[Fact]
765+
public async Task IWireMockAdminApi_UpdateScenarioState()
766+
{
767+
// Arrange
768+
using var server = WireMockServer.StartWithAdminInterface();
769+
server
770+
.Given(Request.Create()
771+
.WithPath("/state1")
772+
.UsingGet())
773+
.InScenario("s1")
774+
.WillSetStateTo("Test state 1")
775+
.RespondWith(Response.Create()
776+
.WithBody("No state msg 1"));
777+
778+
server
779+
.Given(Request.Create()
780+
.WithPath("/foostate1")
781+
.UsingGet())
782+
.InScenario("s1")
783+
.WhenStateIs("Test state 1")
784+
.RespondWith(Response.Create()
785+
.WithBody("Test state msg 1"));
786+
787+
var api = RestClient.For<IWireMockAdminApi>(server.Urls[0]);
788+
789+
// Act
790+
var update = new ScenarioStateUpdateModel
791+
{
792+
State = null
793+
};
794+
var status = await api.PutScenarioStateAsync("s1", update).ConfigureAwait(false);
795+
status.Status.Should().Be("Scenario state set to ''");
796+
}
797+
746798
[Fact]
747799
public async Task IWireMockAdminApi_GetMappingByGuidAsync()
748800
{

test/WireMock.Net.Tests/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ internal static class Constants
66
{
77
internal const int NumStaticMappings = 10;
88

9-
internal const int NumAdminMappings = 36;
9+
internal const int NumAdminMappings = 37;
1010
}

0 commit comments

Comments
 (0)