Compare commits

...

12 Commits

Author SHA1 Message Date
Stef Heyenrath
abe996671e Add Copilot Setup Steps action (#1419) 2026-01-09 18:20:12 +01:00
Petr Houška
9f819de696 Update aspire to 13.1 (examples + code) (#1417)
Allows usage of aspire CLI which is very useful for dev in codespaces (for my next PR).
2026-01-09 18:01:45 +01:00
Stef Heyenrath
f5d53453e5 1.23.0 2026-01-05 21:34:11 +01:00
samlatham
0e60e3f3f9 Fix: Pass AllowedHandlebarsHelpers configuration to Handlebars.Net.Helpers (#1416)
Pass AllowedHandlebarsHelpers configuration to Handlebars.Net.Helpers so that optional handlebars helpers can be enabled.

Co-authored-by: Sam Latham <sam.latham@citrix.com>
2026-01-05 21:24:48 +01:00
Luca Ma
9cee6dde00 Pass the parameter matchOperator in Request.WithPath to its inner calls (#1414)
Co-authored-by: Luca Ma <lucama@microsoft.com>
2026-01-04 08:03:19 +01:00
Stef Heyenrath
c88e7378a7 1.22.0 2026-01-02 21:30:59 +01:00
Vadim Hatsura
b090296559 chore(testcontainers): bump up Testcontainers to version 4.10.0 (#1412) 2026-01-02 21:25:28 +01:00
Stef Heyenrath
e5afd69f7c 1.21.0 2025-12-25 15:00:54 +01:00
Stef Heyenrath
f38133d7a4 Fix readyness-check for Testcontainers (#1408)
* Add XUnit Logging to TestcontainersTests

* .
2025-12-25 13:56:29 +01:00
Stef Heyenrath
597c95000e vmImage: 'windows-2025' (#1407) 2025-12-24 16:59:02 +01:00
Stef Heyenrath
4617b99c30 [Collection("Grpc")] 2025-12-24 12:32:56 +01:00
Stef Heyenrath
ffd4d89946 Re-enable TestcontainersTestsGrpc (#1406)
* Re-enable TestcontainersTestsGrpc

* //[Collection("Grpc")]
2025-12-24 12:16:56 +01:00
23 changed files with 255 additions and 67 deletions

View File

@@ -0,0 +1,36 @@
name: "Copilot Setup Steps"
# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
copilot-setup-steps:
runs-on: ubuntu-latest
# Set the permissions to the lowest permissions possible needed for your steps.
# Copilot will be given its own token for its operations.
permissions:
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
contents: read
# You can define any steps you want, and they will run before the agent starts.
# If you do not check out your code, Copilot will do this for you.
steps:
- name: Install .NET 10.x
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
10.x
dotnet-quality: preview
- name: dotnet --info
run: dotnet --info

View File

@@ -1,3 +1,16 @@
# 1.23.0 (05 January 2026)
- [#1414](https://github.com/wiremock/WireMock.Net/pull/1414) - Pass the parameter matchOperator in Request.WithPath to its inner calls [bug] contributed by [gbamqzkdyg](https://github.com/gbamqzkdyg)
- [#1416](https://github.com/wiremock/WireMock.Net/pull/1416) - Fix: Pass AllowedHandlebarsHelpers configuration to Handlebars.Net.Helpers library contributed by [samlatham](https://github.com/samlatham)
- [#1413](https://github.com/wiremock/WireMock.Net/issues/1413) - Parameter `matchOperator` is not respected in the method Request.WithPath [bug]
- [#1415](https://github.com/wiremock/WireMock.Net/issues/1415) - HandlebarsSettings AllowedHandlebarsHelpers Configuration Not Applied [bug]
# 1.22.0 (02 January 2026)
- [#1412](https://github.com/wiremock/WireMock.Net/pull/1412) - chore(testcontainers): bump up Testcontainers to version 4.10.0 [feature] contributed by [vhatsura](https://github.com/vhatsura)
- [#1411](https://github.com/wiremock/WireMock.Net/issues/1411) - WireMock.Net.Testcontainers isn't compatible with Testcontainers 4.10.0 [bug]
# 1.21.0 (25 December 2025)
- [#1408](https://github.com/wiremock/WireMock.Net/pull/1408) - Fix readyness-check for Testcontainers [bug] contributed by [StefH](https://github.com/StefH)
# 1.20.0 (24 December 2025) # 1.20.0 (24 December 2025)
- [#1399](https://github.com/wiremock/WireMock.Net/pull/1399) - Upgrade RamlToOpenApiConverter and YamlDotNet [feature] contributed by [StefH](https://github.com/StefH) - [#1399](https://github.com/wiremock/WireMock.Net/pull/1399) - Upgrade RamlToOpenApiConverter and YamlDotNet [feature] contributed by [StefH](https://github.com/StefH)
- [#1400](https://github.com/wiremock/WireMock.Net/pull/1400) - Add WireMock.Net.NUnit project [feature] contributed by [StefH](https://github.com/StefH) - [#1400](https://github.com/wiremock/WireMock.Net/pull/1400) - Add WireMock.Net.NUnit project [feature] contributed by [StefH](https://github.com/StefH)

View File

@@ -4,7 +4,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<VersionPrefix>1.20.0</VersionPrefix> <VersionPrefix>1.23.0</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

@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.20.0 SET version=1.23.0
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels wontfix test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN% GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels wontfix test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%

View File

@@ -1,8 +1,7 @@
# 1.20.0 (24 December 2025) # 1.23.0 (05 January 2026)
- #1399 Upgrade RamlToOpenApiConverter and YamlDotNet [feature] - #1414 Pass the parameter matchOperator in Request.WithPath to its inner calls [bug]
- #1400 Add WireMock.Net.NUnit project [feature] - #1416 Fix: Pass AllowedHandlebarsHelpers configuration to Handlebars.Net.Helpers library
- #1405 Fix Testcontainers AddProtoDefinition [bug] - #1413 Parameter `matchOperator` is not respected in the method Request.WithPath [bug]
- #1398 Upgrade YamlDotNet dependency [feature] - #1415 HandlebarsSettings AllowedHandlebarsHelpers Configuration Not Applied [bug]
- #1404 An exception occurs when adding multiple proto definitions in the TestContainer. [bug]
The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -100,7 +100,7 @@ jobs:
- job: Windows_Build_Test - job: Windows_Build_Test
pool: pool:
vmImage: 'windows-2022' vmImage: 'windows-2025'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
@@ -141,7 +141,7 @@ jobs:
dependsOn: Windows_Build_Test dependsOn: Windows_Build_Test
pool: pool:
vmImage: 'windows-2022' vmImage: 'windows-2025'
steps: steps:
- script: | - script: |

View File

@@ -1,5 +1,5 @@
pool: pool:
vmImage: 'windows-2022' vmImage: 'windows-2025'
variables: variables:
Prerelease: '' Prerelease: ''

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" /> <Sdk Name="Aspire.AppHost.Sdk" Version="13.1.0" />
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@@ -18,7 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" /> <PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" /> <Sdk Name="Aspire.AppHost.Sdk" Version="13.1.0" />
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@@ -15,7 +15,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" /> <PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -9,7 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="8.0.0" /> <PackageReference Include="Aspire.Hosting.Testing" Version="13.1.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0" /> <PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.5.3" /> <PackageReference Include="xunit" Version="2.5.3" />

View File

@@ -45,7 +45,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="9.2.0" /> <PackageReference Include="Aspire.Hosting" Version="13.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -21,7 +21,7 @@ public partial class Request
{ {
Guard.NotNullOrEmpty(matchers); Guard.NotNullOrEmpty(matchers);
_requestMatchers.Add(new RequestMessagePathMatcher(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, matchers)); _requestMatchers.Add(new RequestMessagePathMatcher(MatchBehaviour.AcceptOnMatch, matchOperator, matchers));
return this; return this;
} }

View File

@@ -39,6 +39,8 @@ internal static class WireMockHandlebarsHelpers
#endif #endif
o.CustomHelperPaths = paths; o.CustomHelperPaths = paths;
o.Categories = settings.HandlebarsSettings?.AllowedHandlebarsHelpers ?? HandlebarsSettings.DefaultAllowedHandlebarsHelpers;
o.CustomHelpers = new Dictionary<string, IHelpers>(); o.CustomHelpers = new Dictionary<string, IHelpers>();
if (settings.HandlebarsSettings?.AllowedCustomHandlebarsHelpers.HasFlag(CustomHandlebarsHelpers.File) == true) if (settings.HandlebarsSettings?.AllowedCustomHandlebarsHelpers.HasFlag(CustomHandlebarsHelpers.File) == true)
{ {

View File

@@ -39,7 +39,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Stef.Validation" Version="0.1.1" /> <PackageReference Include="Stef.Validation" Version="0.1.1" />
<PackageReference Include="Testcontainers" Version="4.8.0" /> <PackageReference Include="Testcontainers" Version="4.10.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -24,28 +24,21 @@ namespace WireMock.Net.Testcontainers;
/// <summary> /// <summary>
/// A container for running WireMock in a docker environment. /// A container for running WireMock in a docker environment.
/// </summary> /// </summary>
public sealed class WireMockContainer : DockerContainer /// <remarks>
/// Initializes a new instance of the <see cref="WireMockContainer" /> class.
/// </remarks>
/// <param name="configuration">The container configuration.</param>
public sealed class WireMockContainer(WireMockConfiguration configuration) : DockerContainer(configuration)
{ {
private const int EnhancedFileSystemWatcherTimeoutMs = 2000; private const int EnhancedFileSystemWatcherTimeoutMs = 2000;
internal const int ContainerPort = 80; internal const int ContainerPort = 80;
private readonly WireMockConfiguration _configuration; private readonly WireMockConfiguration _configuration = Guard.NotNull(configuration);
private IWireMockAdminApi? _adminApi; private IWireMockAdminApi? _adminApi;
private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher; private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher;
private IDictionary<int, Uri>? _publicUris; private IDictionary<int, Uri>? _publicUris;
/// <summary>
/// Initializes a new instance of the <see cref="WireMockContainer" /> class.
/// </summary>
/// <param name="configuration">The container configuration.</param>
public WireMockContainer(WireMockConfiguration configuration) : base(configuration)
{
_configuration = Guard.NotNull(configuration);
Started += async (sender, eventArgs) => await WireMockContainerStartedAsync(sender, eventArgs);
}
/// <summary> /// <summary>
/// Gets the public Url. /// Gets the public Url.
/// </summary> /// </summary>
@@ -157,14 +150,28 @@ public sealed class WireMockContainer : DockerContainer
try try
{ {
var result = await _adminApi.ReloadStaticMappingsAsync(cancellationToken); var result = await _adminApi.ReloadStaticMappingsAsync(cancellationToken);
Logger.LogInformation("ReloadStaticMappings result: {Result}", result); Logger.LogInformation("WireMock.Net -> ReloadStaticMappings result: {Result}", result);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogWarning(ex, "Error calling /__admin/mappings/reloadStaticMappings"); Logger.LogWarning(ex, "WireMock.Net -> Error calling /__admin/mappings/reloadStaticMappings");
} }
} }
/// <summary>
/// Performs additional actions after the container is ready.
/// </summary>
public Task CallAdditionalActionsAfterReadyAsync()
{
Logger.LogInformation("WireMock.Net -> Calling additional actions.");
_adminApi = CreateWireMockAdminClient();
RegisterEnhancedFileSystemWatcher();
return AddProtoDefinitionsAsync();
}
/// <inheritdoc /> /// <inheritdoc />
protected override ValueTask DisposeAsyncCore() protected override ValueTask DisposeAsyncCore()
{ {
@@ -197,15 +204,6 @@ public sealed class WireMockContainer : DockerContainer
} }
} }
private async Task WireMockContainerStartedAsync(object sender, EventArgs e)
{
_adminApi = CreateWireMockAdminClient();
RegisterEnhancedFileSystemWatcher();
await CallAdditionalActionsAfterStartedAsync();
}
private void RegisterEnhancedFileSystemWatcher() private void RegisterEnhancedFileSystemWatcher()
{ {
if (!_configuration.WatchStaticMappings || string.IsNullOrEmpty(_configuration.StaticMappingsPath)) if (!_configuration.WatchStaticMappings || string.IsNullOrEmpty(_configuration.StaticMappingsPath))
@@ -223,22 +221,22 @@ public sealed class WireMockContainer : DockerContainer
_enhancedFileSystemWatcher.EnableRaisingEvents = true; _enhancedFileSystemWatcher.EnableRaisingEvents = true;
} }
private async Task CallAdditionalActionsAfterStartedAsync() private async Task AddProtoDefinitionsAsync()
{ {
foreach (var kvp in _configuration.ProtoDefinitions) foreach (var kvp in _configuration.ProtoDefinitions)
{ {
Logger.LogInformation("Adding ProtoDefinition {Id}", kvp.Key); Logger.LogInformation("WireMock.Net -> Adding ProtoDefinition '{Id}'", kvp.Key);
foreach (var protoDefinition in kvp.Value) foreach (var protoDefinition in kvp.Value)
{ {
try try
{ {
var result = await _adminApi!.AddProtoDefinitionAsync(kvp.Key, protoDefinition); var result = await _adminApi!.AddProtoDefinitionAsync(kvp.Key, protoDefinition);
Logger.LogInformation("AddProtoDefinition '{Id}' result: {Result}", kvp.Key, result); Logger.LogInformation("WireMock.Net -> AddProtoDefinition '{Id}' result: {Result}", kvp.Key, result);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogWarning(ex, "Error adding ProtoDefinition '{Id}'.", kvp.Key); Logger.LogWarning(ex, "WireMock.Net -> Error adding ProtoDefinition '{Id}'.", kvp.Key);
} }
} }
} }
@@ -255,17 +253,17 @@ public sealed class WireMockContainer : DockerContainer
try try
{ {
await ReloadStaticMappingsAsync(args.FullPath); await ReloadStaticMappingsAsync(args.FullPath);
Logger.LogInformation("ReloadStaticMappings triggered from file change: '{FullPath}'.", args.FullPath); Logger.LogInformation("WireMock.Net -> ReloadStaticMappings triggered from file change: '{FullPath}'.", args.FullPath);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogWarning(ex, "Error reloading static mappings from '{FullPath}'.", args.FullPath); Logger.LogWarning(ex, "WireMock.Net -> Error reloading static mappings from '{FullPath}'.", args.FullPath);
} }
} }
private async Task ReloadStaticMappingsAsync(string path, CancellationToken cancellationToken = default) private async Task ReloadStaticMappingsAsync(string path, CancellationToken cancellationToken = default)
{ {
Logger.LogInformation("MappingFile created, changed or deleted: '{Path}'. Triggering ReloadStaticMappings.", path); Logger.LogInformation("WireMock.Net -> MappingFile created, changed or deleted: '{Path}'. Triggering ReloadStaticMappings.", path);
await ReloadStaticMappingsAsync(cancellationToken); await ReloadStaticMappingsAsync(cancellationToken);
} }

View File

@@ -253,8 +253,9 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
builder.Validate(); builder.Validate();
var waitForContainerOS = _imageOS == OSPlatform.Windows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer(); var waitForContainerOS = _imageOS == OSPlatform.Windows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
builder builder = builder
.WithWaitStrategy(waitForContainerOS .WithWaitStrategy(waitForContainerOS
.UntilMessageIsLogged("WireMock.Net server running", waitStrategy => waitStrategy.WithTimeout(TimeSpan.FromSeconds(30)))
.UntilHttpRequestIsSucceeded(httpWaitStrategy => httpWaitStrategy .UntilHttpRequestIsSucceeded(httpWaitStrategy => httpWaitStrategy
.ForPort(WireMockContainer.ContainerPort) .ForPort(WireMockContainer.ContainerPort)
.WithMethod(HttpMethod.Get) .WithMethod(HttpMethod.Get)
@@ -267,6 +268,7 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
return content?.Contains("Healthy") == true; return content?.Contains("Healthy") == true;
}) })
) )
.AddCustomWaitStrategy(new WireMockWaitStrategy())
); );
return new WireMockContainer(builder.DockerResourceConfiguration); return new WireMockContainer(builder.DockerResourceConfiguration);
@@ -277,13 +279,9 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
{ {
var builder = base.Init(); var builder = base.Init();
var waitForContainerOS = _imageOS == OSPlatform.Windows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
return builder return builder
.WithPortBinding(WireMockContainer.ContainerPort, true) .WithPortBinding(WireMockContainer.ContainerPort, true)
.WithCommand($"--WireMockLogger {DefaultLogger}") .WithCommand($"--WireMockLogger {DefaultLogger}");
.WithWaitStrategy(waitForContainerOS
.UntilMessageIsLogged("WireMock.Net server running", waitStrategy => waitStrategy.WithTimeout(TimeSpan.FromSeconds(30)))
);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -0,0 +1,23 @@
// Copyright © WireMock.Net
using System;
using System.Threading.Tasks;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
namespace WireMock.Net.Testcontainers;
internal class WireMockWaitStrategy : IWaitUntil
{
public async Task<bool> UntilAsync(IContainer container)
{
if (container is not WireMockContainer wireMockContainer)
{
throw new InvalidOperationException("The passed container is not a WireMockContainer.");
}
await wireMockContainer.CallAdditionalActionsAfterReadyAsync();
return true;
}
}

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" /> <Sdk Name="Aspire.AppHost.Sdk" Version="13.1.0" />
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" /> <PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -13,7 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.2.0" /> <PackageReference Include="Aspire.Hosting.Testing" Version="13.1.0" />
<PackageReference Include="Codecov" Version="1.13.0" /> <PackageReference Include="Codecov" Version="1.13.0" />
<PackageReference Include="coverlet.msbuild" Version="6.0.2"> <PackageReference Include="coverlet.msbuild" Version="6.0.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

View File

@@ -0,0 +1,93 @@
// Copyright © WireMock.Net
using System;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using HandlebarsDotNet;
using HandlebarsDotNet.Helpers.Enums;
using Moq;
using WireMock.Handlers;
using WireMock.Models;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using Xunit;
namespace WireMock.Net.Tests.Settings;
public class HandlebarsSettingsTests
{
private const string ClientIp = "::1";
private readonly WireMockServerSettings _settings;
private readonly Mock<IMapping> _mappingMock;
private readonly Mock<IFileSystemHandler> _fileSystemHandlerMock;
public HandlebarsSettingsTests()
{
_mappingMock = new Mock<IMapping>();
_fileSystemHandlerMock = new Mock<IFileSystemHandler>(MockBehavior.Strict);
_settings = new WireMockServerSettings
{
FileSystemHandler = _fileSystemHandlerMock.Object
};
}
[Fact]
public async Task Response_HandlebarsHelpers_Environment_NotAllowed_By_Default()
{
// Arrange
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "GET", ClientIp);
var responseBuilder = Response.Create()
.WithBody("Username: {{Environment.GetEnvironmentVariable \"USERNAME\"}}")
.WithTransformer();
// Act
Func<Task> action = () => responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings);
// Assert
await action.Should().ThrowAsync<HandlebarsRuntimeException>();
}
[Fact]
public async Task Response_HandlebarsHelpers_Environment_Allowed_When_Configured()
{
// Arrange
var settingsWithEnv = new WireMockServerSettings
{
FileSystemHandler = _fileSystemHandlerMock.Object,
HandlebarsSettings = new HandlebarsSettings
{
AllowedHandlebarsHelpers = HandlebarsSettings.DefaultAllowedHandlebarsHelpers
.Concat([Category.Environment])
.ToArray()
}
};
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "GET", ClientIp);
var responseBuilder = Response.Create()
.WithBody("User: {{Environment.GetEnvironmentVariable \"USERNAME\"}}")
.WithTransformer();
// Act
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, settingsWithEnv).ConfigureAwait(false);
// Assert
response.Message?.BodyData?.BodyAsString.Should().NotContain("{{Environment.GetEnvironmentVariable");
response.Message?.BodyData?.BodyAsString.Should().StartWith("User: ");
}
[Fact]
public void DefaultAllowedHandlebarsHelpers_Should_Not_Include_EnvironmentAndDynamicLinq()
{
// Assert
HandlebarsSettings.DefaultAllowedHandlebarsHelpers.Should()
.NotContain(Category.Environment)
.And
.NotContain(Category.DynamicLinq);
}
}

View File

@@ -7,6 +7,8 @@ using System.Threading.Tasks;
using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Builders;
using FluentAssertions; using FluentAssertions;
using FluentAssertions.Execution; using FluentAssertions.Execution;
using Meziantou.Extensions.Logging.Xunit;
using Microsoft.Extensions.Logging;
using WireMock.Net.Testcontainers; using WireMock.Net.Testcontainers;
using WireMock.Net.Testcontainers.Utils; using WireMock.Net.Testcontainers.Utils;
using WireMock.Net.Tests.Facts; using WireMock.Net.Tests.Facts;
@@ -17,6 +19,12 @@ namespace WireMock.Net.Tests.Testcontainers;
public class TestcontainersTests(ITestOutputHelper testOutputHelper) public class TestcontainersTests(ITestOutputHelper testOutputHelper)
{ {
private readonly ILogger _logger = new XUnitLogger(testOutputHelper, new LoggerExternalScopeProvider(), nameof(TestcontainersTests), new XUnitLoggerOptions
{
IncludeCategory = true,
TimestampFormat = "yyy-MM-dd HH:mm:ss.fff"
});
[Fact] [Fact]
public async Task WireMockContainer_Build_And_StartAsync_and_StopAsync() public async Task WireMockContainer_Build_And_StartAsync_and_StopAsync()
{ {
@@ -24,6 +32,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
var adminUsername = $"username_{Guid.NewGuid()}"; var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}"; var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword) .WithAdminUserNameAndPassword(adminUsername, adminPassword)
.WithAutoRemove(true) .WithAutoRemove(true)
.WithCleanUp(true) .WithCleanUp(true)
@@ -43,6 +52,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
.Build(); .Build();
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.WithNetwork(dummyNetwork) .WithNetwork(dummyNetwork)
.WithWatchStaticMappings(true) .WithWatchStaticMappings(true)
.Build(); .Build();
@@ -58,6 +68,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
var adminUsername = $"username_{Guid.NewGuid()}"; var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}"; var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainerBuilder = new WireMockContainerBuilder() var wireMockContainerBuilder = new WireMockContainerBuilder()
.WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword); .WithAdminUserNameAndPassword(adminUsername, adminPassword);
var imageOS = await TestcontainersUtils.GetImageOSAsync.Value; var imageOS = await TestcontainersUtils.GetImageOSAsync.Value;
@@ -83,6 +94,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
var adminUsername = $"username_{Guid.NewGuid()}"; var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}"; var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainerBuilder = new WireMockContainerBuilder() var wireMockContainerBuilder = new WireMockContainerBuilder()
.WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword); .WithAdminUserNameAndPassword(adminUsername, adminPassword);
var imageOS = await TestcontainersUtils.GetImageOSAsync.Value; var imageOS = await TestcontainersUtils.GetImageOSAsync.Value;

View File

@@ -11,6 +11,8 @@ using FluentAssertions;
using FluentAssertions.Execution; using FluentAssertions.Execution;
using Greet; using Greet;
using Grpc.Net.Client; using Grpc.Net.Client;
using Meziantou.Extensions.Logging.Xunit;
using Microsoft.Extensions.Logging;
using WireMock.Constants; using WireMock.Constants;
using WireMock.Net.Testcontainers; using WireMock.Net.Testcontainers;
using WireMock.Util; using WireMock.Util;
@@ -22,7 +24,13 @@ namespace WireMock.Net.Tests.Testcontainers;
[Collection("Grpc")] [Collection("Grpc")]
public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper) public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
{ {
[Fact(Skip = "TODO")] private readonly ILogger _logger = new XUnitLogger(testOutputHelper, new LoggerExternalScopeProvider(), nameof(TestcontainersTestsGrpc), new XUnitLoggerOptions
{
IncludeCategory = true,
TimestampFormat = "yyy-MM-dd HH:mm:ss.fff"
});
[Fact]
public async Task WireMockContainer_Build_Grpc_TestPortsAndUrls1() public async Task WireMockContainer_Build_Grpc_TestPortsAndUrls1()
{ {
// Arrange // Arrange
@@ -32,6 +40,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
// Act // Act
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword) .WithAdminUserNameAndPassword(adminUsername, adminPassword)
.WithCommand("--UseHttp2") .WithCommand("--UseHttp2")
.WithCommand("--Urls", $"http://*:80 grpc://*:{port}") .WithCommand("--Urls", $"http://*:80 grpc://*:{port}")
@@ -78,7 +87,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
} }
} }
[Fact(Skip = "TODO")] [Fact]
public async Task WireMockContainer_Build_Grpc_TestPortsAndUrls2() public async Task WireMockContainer_Build_Grpc_TestPortsAndUrls2()
{ {
// Arrange // Arrange
@@ -88,6 +97,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
// Act // Act
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword) .WithAdminUserNameAndPassword(adminUsername, adminPassword)
.AddUrl($"http://*:{ports[0]}") .AddUrl($"http://*:{ports[0]}")
.AddUrl($"grpc://*:{ports[1]}") .AddUrl($"grpc://*:{ports[1]}")
@@ -131,7 +141,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
} }
} }
[Fact(Skip = "TODO")] [Fact]
public async Task WireMockContainer_Build_Grpc_ProtoDefinitionFromJson_UsingGrpcGeneratedClient() public async Task WireMockContainer_Build_Grpc_ProtoDefinitionFromJson_UsingGrpcGeneratedClient()
{ {
var wireMockContainer = await Given_WireMockContainerIsStartedForHttpAndGrpcAsync(); var wireMockContainer = await Given_WireMockContainerIsStartedForHttpAndGrpcAsync();
@@ -145,7 +155,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
await StopAsync(wireMockContainer); await StopAsync(wireMockContainer);
} }
[Fact(Skip = "TODO")] [Fact]
public async Task WireMockContainer_Build_Grpc_ProtoDefinitionAtServerLevel_UsingGrpcGeneratedClient() public async Task WireMockContainer_Build_Grpc_ProtoDefinitionAtServerLevel_UsingGrpcGeneratedClient()
{ {
var wireMockContainer = await Given_WireMockContainerWithProtoDefinitionAtServerLevelIsStartedForHttpAndGrpcAsync(); var wireMockContainer = await Given_WireMockContainerWithProtoDefinitionAtServerLevelIsStartedForHttpAndGrpcAsync();
@@ -159,7 +169,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
await StopAsync(wireMockContainer); await StopAsync(wireMockContainer);
} }
[Fact(Skip = "TODO")] [Fact]
public async Task WireMockContainer_Build_Grpc_ProtoDefinitionAtServerLevel_UsingGrpcGeneratedClient_AndWithWatchStaticMappings() public async Task WireMockContainer_Build_Grpc_ProtoDefinitionAtServerLevel_UsingGrpcGeneratedClient_AndWithWatchStaticMappings()
{ {
var wireMockContainer = await Given_WireMockContainerWithProtoDefinitionAtServerLevelWithWatchStaticMappingsIsStartedForHttpAndGrpcAsync(); var wireMockContainer = await Given_WireMockContainerWithProtoDefinitionAtServerLevelWithWatchStaticMappingsIsStartedForHttpAndGrpcAsync();
@@ -222,10 +232,11 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
} }
} }
private static async Task<WireMockContainer> Given_WireMockContainerIsStartedForHttpAndGrpcAsync() private async Task<WireMockContainer> Given_WireMockContainerIsStartedForHttpAndGrpcAsync()
{ {
var port = PortUtils.FindFreeTcpPort(); var port = PortUtils.FindFreeTcpPort();
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.AddUrl($"grpc://*:{port}") .AddUrl($"grpc://*:{port}")
.Build(); .Build();
@@ -234,10 +245,11 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
return wireMockContainer; return wireMockContainer;
} }
private static async Task<WireMockContainer> Given_WireMockContainerWithProtoDefinitionAtServerLevelIsStartedForHttpAndGrpcAsync() private async Task<WireMockContainer> Given_WireMockContainerWithProtoDefinitionAtServerLevelIsStartedForHttpAndGrpcAsync()
{ {
var port = PortUtils.FindFreeTcpPort(); var port = PortUtils.FindFreeTcpPort();
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.AddUrl($"grpc://*:{port}") .AddUrl($"grpc://*:{port}")
.AddProtoDefinition("my-greeter", ReadFile("greet.proto")) .AddProtoDefinition("my-greeter", ReadFile("greet.proto"))
.Build(); .Build();
@@ -247,10 +259,11 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
return wireMockContainer; return wireMockContainer;
} }
private static async Task<WireMockContainer> Given_WireMockContainerWithProtoDefinitionAtServerLevelWithWatchStaticMappingsIsStartedForHttpAndGrpcAsync() private async Task<WireMockContainer> Given_WireMockContainerWithProtoDefinitionAtServerLevelWithWatchStaticMappingsIsStartedForHttpAndGrpcAsync()
{ {
var port = PortUtils.FindFreeTcpPort(); var port = PortUtils.FindFreeTcpPort();
var wireMockContainer = new WireMockContainerBuilder() var wireMockContainer = new WireMockContainerBuilder()
.WithLogger(_logger)
.AddUrl($"grpc://*:{port}") .AddUrl($"grpc://*:{port}")
.AddProtoDefinition("my-greeter", ReadFile("greet.proto")) .AddProtoDefinition("my-greeter", ReadFile("greet.proto"))
.WithMappings(Path.Combine(Directory.GetCurrentDirectory(), "__admin", "mappings")) .WithMappings(Path.Combine(Directory.GetCurrentDirectory(), "__admin", "mappings"))

View File

@@ -121,6 +121,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0'">
<ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" /> <ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" />
<PackageReference Include="Meziantou.Extensions.Logging.Xunit" Version="1.0.21" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>