diff --git a/src/WireMock.Net.Testcontainers/WireMockContainer.cs b/src/WireMock.Net.Testcontainers/WireMockContainer.cs
index f34cc1b3..411e6a43 100644
--- a/src/WireMock.Net.Testcontainers/WireMockContainer.cs
+++ b/src/WireMock.Net.Testcontainers/WireMockContainer.cs
@@ -24,28 +24,21 @@ namespace WireMock.Net.Testcontainers;
///
/// A container for running WireMock in a docker environment.
///
-public sealed class WireMockContainer : DockerContainer
+///
+/// Initializes a new instance of the class.
+///
+/// The container configuration.
+public sealed class WireMockContainer(WireMockConfiguration configuration) : DockerContainer(configuration)
{
private const int EnhancedFileSystemWatcherTimeoutMs = 2000;
internal const int ContainerPort = 80;
- private readonly WireMockConfiguration _configuration;
+ private readonly WireMockConfiguration _configuration = Guard.NotNull(configuration);
private IWireMockAdminApi? _adminApi;
private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher;
private IDictionary? _publicUris;
- ///
- /// Initializes a new instance of the class.
- ///
- /// The container configuration.
- public WireMockContainer(WireMockConfiguration configuration) : base(configuration)
- {
- _configuration = Guard.NotNull(configuration);
-
- Started += async (sender, eventArgs) => await WireMockContainerStartedAsync(sender, eventArgs);
- }
-
///
/// Gets the public Url.
///
@@ -157,14 +150,28 @@ public sealed class WireMockContainer : DockerContainer
try
{
var result = await _adminApi.ReloadStaticMappingsAsync(cancellationToken);
- Logger.LogInformation("ReloadStaticMappings result: {Result}", result);
+ Logger.LogInformation("WireMock.Net -> ReloadStaticMappings result: {Result}", result);
}
catch (Exception ex)
{
- Logger.LogWarning(ex, "Error calling /__admin/mappings/reloadStaticMappings");
+ Logger.LogWarning(ex, "WireMock.Net -> Error calling /__admin/mappings/reloadStaticMappings");
}
}
+ ///
+ /// Performs additional actions after the container is ready.
+ ///
+ public Task CallAdditionalActionsAfterReadyAsync()
+ {
+ Logger.LogInformation("WireMock.Net -> Calling additional actions.");
+
+ _adminApi = CreateWireMockAdminClient();
+
+ RegisterEnhancedFileSystemWatcher();
+
+ return AddProtoDefinitionsAsync();
+ }
+
///
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()
{
if (!_configuration.WatchStaticMappings || string.IsNullOrEmpty(_configuration.StaticMappingsPath))
@@ -223,22 +221,22 @@ public sealed class WireMockContainer : DockerContainer
_enhancedFileSystemWatcher.EnableRaisingEvents = true;
}
- private async Task CallAdditionalActionsAfterStartedAsync()
+ private async Task AddProtoDefinitionsAsync()
{
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)
{
try
{
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)
{
- 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
{
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)
{
- 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)
{
- 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);
}
diff --git a/src/WireMock.Net.Testcontainers/WireMockContainerBuilder.cs b/src/WireMock.Net.Testcontainers/WireMockContainerBuilder.cs
index 37241598..5820f7c5 100644
--- a/src/WireMock.Net.Testcontainers/WireMockContainerBuilder.cs
+++ b/src/WireMock.Net.Testcontainers/WireMockContainerBuilder.cs
@@ -253,8 +253,9 @@ public sealed class WireMockContainerBuilder : ContainerBuilder waitStrategy.WithTimeout(TimeSpan.FromSeconds(30)))
.UntilHttpRequestIsSucceeded(httpWaitStrategy => httpWaitStrategy
.ForPort(WireMockContainer.ContainerPort)
.WithMethod(HttpMethod.Get)
@@ -267,6 +268,7 @@ public sealed class WireMockContainerBuilder : ContainerBuilder waitStrategy.WithTimeout(TimeSpan.FromSeconds(30)))
- );
+ .WithCommand($"--WireMockLogger {DefaultLogger}");
}
///
diff --git a/src/WireMock.Net.Testcontainers/WireMockWaitStrategy.cs b/src/WireMock.Net.Testcontainers/WireMockWaitStrategy.cs
new file mode 100644
index 00000000..d33364d8
--- /dev/null
+++ b/src/WireMock.Net.Testcontainers/WireMockWaitStrategy.cs
@@ -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 UntilAsync(IContainer container)
+ {
+ if (container is not WireMockContainer wireMockContainer)
+ {
+ throw new InvalidOperationException("The passed container is not a WireMockContainer.");
+
+ }
+
+ await wireMockContainer.CallAdditionalActionsAfterReadyAsync();
+ return true;
+ }
+}
diff --git a/test/WireMock.Net.Tests/Testcontainers/TestcontainersTests.cs b/test/WireMock.Net.Tests/Testcontainers/TestcontainersTests.cs
index 8bde055b..c1cefe1d 100644
--- a/test/WireMock.Net.Tests/Testcontainers/TestcontainersTests.cs
+++ b/test/WireMock.Net.Tests/Testcontainers/TestcontainersTests.cs
@@ -7,6 +7,8 @@ using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
using FluentAssertions;
using FluentAssertions.Execution;
+using Meziantou.Extensions.Logging.Xunit;
+using Microsoft.Extensions.Logging;
using WireMock.Net.Testcontainers;
using WireMock.Net.Testcontainers.Utils;
using WireMock.Net.Tests.Facts;
@@ -17,6 +19,12 @@ namespace WireMock.Net.Tests.Testcontainers;
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]
public async Task WireMockContainer_Build_And_StartAsync_and_StopAsync()
{
@@ -24,6 +32,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword)
.WithAutoRemove(true)
.WithCleanUp(true)
@@ -43,6 +52,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
.Build();
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.WithNetwork(dummyNetwork)
.WithWatchStaticMappings(true)
.Build();
@@ -58,6 +68,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainerBuilder = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword);
var imageOS = await TestcontainersUtils.GetImageOSAsync.Value;
@@ -83,6 +94,7 @@ public class TestcontainersTests(ITestOutputHelper testOutputHelper)
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainerBuilder = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword);
var imageOS = await TestcontainersUtils.GetImageOSAsync.Value;
diff --git a/test/WireMock.Net.Tests/Testcontainers/TestcontainersTestsGrpc.cs b/test/WireMock.Net.Tests/Testcontainers/TestcontainersTestsGrpc.cs
index e28f71f7..13163ced 100644
--- a/test/WireMock.Net.Tests/Testcontainers/TestcontainersTestsGrpc.cs
+++ b/test/WireMock.Net.Tests/Testcontainers/TestcontainersTestsGrpc.cs
@@ -11,6 +11,8 @@ using FluentAssertions;
using FluentAssertions.Execution;
using Greet;
using Grpc.Net.Client;
+using Meziantou.Extensions.Logging.Xunit;
+using Microsoft.Extensions.Logging;
using WireMock.Constants;
using WireMock.Net.Testcontainers;
using WireMock.Util;
@@ -22,6 +24,12 @@ namespace WireMock.Net.Tests.Testcontainers;
[Collection("Grpc")]
public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
{
+ 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()
{
@@ -32,6 +40,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
// Act
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword)
.WithCommand("--UseHttp2")
.WithCommand("--Urls", $"http://*:80 grpc://*:{port}")
@@ -88,6 +97,7 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
// Act
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.WithAdminUserNameAndPassword(adminUsername, adminPassword)
.AddUrl($"http://*:{ports[0]}")
.AddUrl($"grpc://*:{ports[1]}")
@@ -222,10 +232,11 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
}
}
- private static async Task Given_WireMockContainerIsStartedForHttpAndGrpcAsync()
+ private async Task Given_WireMockContainerIsStartedForHttpAndGrpcAsync()
{
var port = PortUtils.FindFreeTcpPort();
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.AddUrl($"grpc://*:{port}")
.Build();
@@ -234,10 +245,11 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
return wireMockContainer;
}
- private static async Task Given_WireMockContainerWithProtoDefinitionAtServerLevelIsStartedForHttpAndGrpcAsync()
+ private async Task Given_WireMockContainerWithProtoDefinitionAtServerLevelIsStartedForHttpAndGrpcAsync()
{
var port = PortUtils.FindFreeTcpPort();
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.AddUrl($"grpc://*:{port}")
.AddProtoDefinition("my-greeter", ReadFile("greet.proto"))
.Build();
@@ -247,10 +259,11 @@ public class TestcontainersTestsGrpc(ITestOutputHelper testOutputHelper)
return wireMockContainer;
}
- private static async Task Given_WireMockContainerWithProtoDefinitionAtServerLevelWithWatchStaticMappingsIsStartedForHttpAndGrpcAsync()
+ private async Task Given_WireMockContainerWithProtoDefinitionAtServerLevelWithWatchStaticMappingsIsStartedForHttpAndGrpcAsync()
{
var port = PortUtils.FindFreeTcpPort();
var wireMockContainer = new WireMockContainerBuilder()
+ .WithLogger(_logger)
.AddUrl($"grpc://*:{port}")
.AddProtoDefinition("my-greeter", ReadFile("greet.proto"))
.WithMappings(Path.Combine(Directory.GetCurrentDirectory(), "__admin", "mappings"))
diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
index afeecb45..39c9445c 100644
--- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
+++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
@@ -121,6 +121,7 @@
+