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

@@ -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>
bool ResetScenario(string name);
/// <summary>
/// Sets a scenario to a state.
/// </summary>
bool SetScenarioState(string name, string? state);
/// <summary>
/// Resets the LogEntries.
/// </summary>

View File

@@ -86,7 +86,7 @@ public interface IMapping
WireMockServerSettings Settings { get; }
/// <summary>
/// Is State started ?
/// Indicates if the state is started or manually set to a value.
/// </summary>
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 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 ScenariosNameWithStateMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/state$");
public RegexMatcher ScenariosNameWithResetMatcher => new($"^{_prefixEscaped}\\/scenarios\\/.+\\/reset$");
public RegexMatcher FilesFilenamePathMatcher => new($"^{_prefixEscaped}\\/files\\/.+$");
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.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}
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));
@@ -705,6 +709,21 @@ public partial class WireMockServer
ResponseMessageBuilder.Create(200, "Scenario reset") :
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
#region Pact

View File

@@ -567,6 +567,32 @@ public partial class WireMockServer : IWireMockServer
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[])" />
[PublicAPI]
public IWireMockServer WithMapping(params MappingModel[] mappings)

View File

@@ -256,7 +256,7 @@ public interface IWireMockAdminApi
/// Delete (reset) all scenarios
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("scenarios")]
[Post("scenarios/reset")]
Task<StatusModel> ResetScenariosAsync(CancellationToken cancellationToken = default);
/// <summary>
@@ -269,7 +269,7 @@ public interface IWireMockAdminApi
Task<StatusModel> DeleteScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) all scenarios
/// Delete (reset) a specific scenario
/// </summary>
/// <param name="name">Scenario name.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
@@ -277,6 +277,16 @@ public interface IWireMockAdminApi
[AllowAnyStatusCode]
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>
/// Create a new File
/// </summary>