Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Copyright © WireMock.Net

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace WireMock.Handlers;
Expand All @@ -23,4 +21,4 @@ public interface IScenarioStateStore
bool TryRemove(string name);

void Clear();
}
}
24 changes: 19 additions & 5 deletions src/WireMock.Net.Minimal/Handlers/FileBasedScenarioStateStore.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
// Copyright © WireMock.Net

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Stef.Validation;

namespace WireMock.Handlers;

/// <summary>
/// Provides a file-based implementation of <see cref="IScenarioStateStore" /> that persists scenario states to disk and allows concurrent access.
/// </summary>
public class FileBasedScenarioStateStore : IScenarioStateStore
{
private readonly ConcurrentDictionary<string, ScenarioState> _scenarios = new(StringComparer.OrdinalIgnoreCase);
private readonly string _scenariosFolder;
private readonly object _lock = new();

/// <summary>
/// Initializes a new instance of the FileBasedScenarioStateStore class using the specified root folder as the base directory for scenario state storage.
/// </summary>
/// <param name="rootFolder">The root directory under which scenario state data will be stored. Must be a valid file system path.</param>
public FileBasedScenarioStateStore(string rootFolder)
{
Guard.NotNullOrEmpty(rootFolder);

_scenariosFolder = Path.Combine(rootFolder, "__admin", "scenarios");
Directory.CreateDirectory(_scenariosFolder);
LoadScenariosFromDisk();
}

/// <inheritdoc />
public bool TryGet(string name, [NotNullWhen(true)] out ScenarioState? state)
{
return _scenarios.TryGetValue(name, out state);
}

/// <inheritdoc />
public IReadOnlyList<ScenarioState> GetAll()
{
return _scenarios.Values.ToArray();
}

/// <inheritdoc />
public bool ContainsKey(string name)
{
return _scenarios.ContainsKey(name);
}

/// <inheritdoc />
public bool TryAdd(string name, ScenarioState scenarioState)
{
if (_scenarios.TryAdd(name, scenarioState))
Expand All @@ -49,6 +59,7 @@ public bool TryAdd(string name, ScenarioState scenarioState)
return false;
}

/// <inheritdoc />
public ScenarioState AddOrUpdate(string name, Func<string, ScenarioState> addFactory, Func<string, ScenarioState, ScenarioState> updateFactory)
{
lock (_lock)
Expand All @@ -59,6 +70,7 @@ public ScenarioState AddOrUpdate(string name, Func<string, ScenarioState> addFac
}
}

/// <inheritdoc />
public ScenarioState? Update(string name, Action<ScenarioState> updateAction)
{
lock (_lock)
Expand All @@ -74,6 +86,7 @@ public ScenarioState AddOrUpdate(string name, Func<string, ScenarioState> addFac
}
}

/// <inheritdoc />
public bool TryRemove(string name)
{
if (_scenarios.TryRemove(name, out _))
Expand All @@ -85,6 +98,7 @@ public bool TryRemove(string name)
return false;
}

/// <inheritdoc />
public void Clear()
{
_scenarios.Clear();
Expand Down Expand Up @@ -128,4 +142,4 @@ private void LoadScenariosFromDisk()
}
}
}
}
}
16 changes: 12 additions & 4 deletions src/WireMock.Net.Shared/Handlers/InMemoryScenarioStateStore.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
// Copyright © WireMock.Net

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace WireMock.Handlers;

/// <summary>
/// Provides an in-memory implementation of the <see cref="IScenarioStateStore" /> interface for managing scenario state objects by name.
/// </summary>
public class InMemoryScenarioStateStore : IScenarioStateStore
{
private readonly ConcurrentDictionary<string, ScenarioState> _scenarios = new(StringComparer.OrdinalIgnoreCase);

/// <inheritdoc />
public bool TryGet(string name, [NotNullWhen(true)] out ScenarioState? state)
{
return _scenarios.TryGetValue(name, out state);
}

/// <inheritdoc />
public IReadOnlyList<ScenarioState> GetAll()
{
return _scenarios.Values.ToArray();
}

/// <inheritdoc />
public bool ContainsKey(string name)
{
return _scenarios.ContainsKey(name);
}

/// <inheritdoc />
public bool TryAdd(string name, ScenarioState scenarioState)
{
return _scenarios.TryAdd(name, scenarioState);
}

/// <inheritdoc />
public ScenarioState AddOrUpdate(string name, Func<string, ScenarioState> addFactory, Func<string, ScenarioState, ScenarioState> updateFactory)
{
return _scenarios.AddOrUpdate(name, addFactory, updateFactory);
}

/// <inheritdoc />
public ScenarioState? Update(string name, Action<ScenarioState> updateAction)
{
if (_scenarios.TryGetValue(name, out var state))
Expand All @@ -48,13 +54,15 @@ public ScenarioState AddOrUpdate(string name, Func<string, ScenarioState> addFac
return null;
}

/// <inheritdoc />
public bool TryRemove(string name)
{
return _scenarios.TryRemove(name, out _);
}

/// <inheritdoc />
public void Clear()
{
_scenarios.Clear();
}
}
}
9 changes: 8 additions & 1 deletion src/WireMock.Net.Shared/Settings/WireMockServerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ public class WireMockServerSettings
[JsonIgnore]
public IFileSystemHandler FileSystemHandler { get; set; } = null!;

/// <summary>
/// Gets or sets the store used to persist scenario state information.
/// </summary>
/// <remarks>
/// The scenario state store manages the storage and retrieval of state data associated with scenarios.
/// By default, an in-memory implementation is used, but this property can be set to a custom implementation to support alternative storage mechanisms such as databases or distributed caches.
/// </remarks>
[PublicAPI]
[JsonIgnore]
public IScenarioStateStore ScenarioStateStore { get; set; } = new InMemoryScenarioStateStore();
Expand Down Expand Up @@ -258,7 +265,7 @@ public class WireMockServerSettings
/// Whether to accept any client certificate
/// </summary>
public bool AcceptAnyClientCertificate { get; set; }

/// <summary>
/// Defines the global IWebhookSettings to use.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@

<ItemGroup>
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PackageReference Include="coverlet.collector" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="WireMock.Net" Version="1.25.0" />
<PackageReference Include="WireMock.Net" Version="2.1.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
Loading