WireMock.Net.Testcontainers: Use 'sheyenrath/wiremock.net-alpine' image as default for Linux (#1181)

* WireMock.Net.Testcontainers: Use 'sheyenrath/wiremock.net-alpine' image as default for Linux

* ...

* .

* WithBindMount

* fix

* r

* .
This commit is contained in:
Stef Heyenrath
2024-09-27 19:10:51 +02:00
committed by GitHub
parent 95994421ae
commit dca3fd0260
4 changed files with 265 additions and 57 deletions

View File

@@ -1,7 +1,7 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System.Runtime.InteropServices;
using Newtonsoft.Json; using Newtonsoft.Json;
using Testcontainers.MsSql;
using WireMock.Net.Testcontainers; using WireMock.Net.Testcontainers;
namespace WireMock.Net.TestcontainersExample; namespace WireMock.Net.TestcontainersExample;
@@ -10,17 +10,134 @@ internal class Program
{ {
private static async Task Main(string[] args) private static async Task Main(string[] args)
{ {
var container = new WireMockContainerBuilder() var original = Console.ForegroundColor;
try
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Linux");
await TestAsync("sheyenrath/wiremock.net:1.6.4");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Linux Alpine");
await TestAsync("sheyenrath/wiremock.net-alpine:1.6.4");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("WithLinux");
await TestAsync("WithLinux");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Windows");
await TestAsync("sheyenrath/wiremock.net-windows:1.6.4");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("WithWindows");
await TestAsync("WithWindows");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Automatic");
await TestAsync();
}
finally
{
Console.ForegroundColor = original;
}
}
private static async Task TestAsync(string? image = null)
{
var builder = new WireMockContainerBuilder()
.WithAdminUserNameAndPassword("x", "y") .WithAdminUserNameAndPassword("x", "y")
.WithMappings(@"C:\Dev\GitHub\WireMock.Net\examples\WireMock.Net.Console.NET6\__admin\mappings")
.WithWatchStaticMappings(true) .WithWatchStaticMappings(true)
.WithAutoRemove(true) .WithAutoRemove(true)
.WithCleanUp(true) .WithCleanUp(true);
.Build();
await container.StartAsync().ConfigureAwait(false); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
builder = builder.WithMappings(@"C:\Dev\GitHub\WireMock.Net\examples\WireMock.Net.Console.NET6\__admin\mappings");
}
else
{
builder = builder.WithMappings("./examples/WireMock.Net.Console.NET6/__admin/mappings");
}
var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1)).ConfigureAwait(false); if (image != null)
{
builder = image switch
{
"WithWindows" => builder.WithWindowsImage(),
"WithLinux" => builder.WithLinuxImage(),
_ => builder.WithImage(image)
};
}
var container = builder.Build();
await container.StartAsync();
await Task.Delay(1_000);
var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1));
Console.WriteLine("logs = " + logs.Stdout); Console.WriteLine("logs = " + logs.Stdout);
var restEaseApiClient = container.CreateWireMockAdminClient(); var restEaseApiClient = container.CreateWireMockAdminClient();
@@ -36,10 +153,5 @@ internal class Program
Console.WriteLine("result = " + result); Console.WriteLine("result = " + result);
await container.StopAsync(); await container.StopAsync();
var sql = new MsSqlBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.Build();
} }
} }

View File

@@ -1,24 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Testcontainers.MsSql" Version="3.6.0" /> <ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" /> <None Update="873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
</ItemGroup> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<ItemGroup> </ItemGroup>
<None Update="873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Docker.DotNet.Models; using Docker.DotNet.Models;
using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Builders;
@@ -17,15 +18,14 @@ namespace WireMock.Net.Testcontainers;
/// </summary> /// </summary>
public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContainerBuilder, WireMockContainer, WireMockConfiguration> public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContainerBuilder, WireMockContainer, WireMockConfiguration>
{ {
private readonly Dictionary<bool, ContainerInfo> _info = new() private const string DefaultLogger = "WireMockConsoleLogger";
private readonly Dictionary<OSPlatform, ContainerInfo> _info = new()
{ {
{ false, new ContainerInfo("sheyenrath/wiremock.net:latest", "/app/__admin/mappings") }, { OSPlatform.Linux, new ContainerInfo("sheyenrath/wiremock.net-alpine", "/app/__admin/mappings") },
{ true, new ContainerInfo("sheyenrath/wiremock.net-windows:latest", @"c:\app\__admin\mappings") } { OSPlatform.Windows, new ContainerInfo("sheyenrath/wiremock.net-windows", @"c:\app\__admin\mappings") }
}; };
private const string DefaultLogger = "WireMockConsoleLogger"; private readonly Lazy<Task<OSPlatform>> _getOSAsLazy = new(async () =>
private readonly Lazy<Task<bool>> _isWindowsAsLazy = new(async () =>
{ {
if (TestcontainersSettings.OS.DockerEndpointAuthConfig == null) if (TestcontainersSettings.OS.DockerEndpointAuthConfig == null)
{ {
@@ -36,9 +36,12 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
using var dockerClient = dockerClientConfig.CreateClient(); using var dockerClient = dockerClientConfig.CreateClient();
var version = await dockerClient.System.GetVersionAsync(); var version = await dockerClient.System.GetVersionAsync();
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) > -1; return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
}); });
private OSPlatform? _imageOS;
private string? _staticMappingsPath;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class. /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary> /// </summary>
@@ -48,14 +51,36 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
} }
/// <summary> /// <summary>
/// Automatically set the correct image (Linux or Windows) for WireMock which to create the container. /// Automatically use the correct image for WireMock.
/// For Linux this is "sheyenrath/wiremock.net-alpine:latest"
/// For Windows this is "sheyenrath/wiremock.net-windows:latest"
/// </summary> /// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns> /// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI] [PublicAPI]
public WireMockContainerBuilder WithImage() public WireMockContainerBuilder WithImage()
{ {
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult(); _imageOS ??= _getOSAsLazy.Value.GetAwaiter().GetResult();
return WithImage(_info[isWindows].Image); return WithImage(_imageOS.Value);
}
/// <summary>
/// Automatically use a Linux image for WireMock. This is "sheyenrath/wiremock.net-alpine:latest"
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithLinuxImage()
{
return WithImage(OSPlatform.Linux);
}
/// <summary>
/// Automatically use a Windows image for WireMock. This is "sheyenrath/wiremock.net-windows:latest"
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithWindowsImage()
{
return WithImage(OSPlatform.Windows);
} }
/// <summary> /// <summary>
@@ -118,13 +143,9 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
[PublicAPI] [PublicAPI]
public WireMockContainerBuilder WithMappings(string path, bool includeSubDirectories = false) public WireMockContainerBuilder WithMappings(string path, bool includeSubDirectories = false)
{ {
Guard.NotNullOrEmpty(path); _staticMappingsPath = Guard.NotNullOrEmpty(path);
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult(); return WithReadStaticMappings().WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}");
return WithReadStaticMappings()
.WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}")
.WithBindMount(path, _info[isWindows].MappingsPath);
} }
private WireMockContainerBuilder(WireMockConfiguration dockerResourceConfiguration) : base(dockerResourceConfiguration) private WireMockContainerBuilder(WireMockConfiguration dockerResourceConfiguration) : base(dockerResourceConfiguration)
@@ -138,9 +159,33 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
/// <inheritdoc /> /// <inheritdoc />
public override WireMockContainer Build() public override WireMockContainer Build()
{ {
Validate(); var builder = this;
return new WireMockContainer(DockerResourceConfiguration); // In case no image has been set, set the image using internal logic.
if (DockerResourceConfiguration.Image == null)
{
builder = WithImage();
}
// In case the _imageOS is not set, determine it from the Image FullName.
if (_imageOS == null)
{
if (builder.DockerResourceConfiguration.Image.FullName.IndexOf("wiremock.net", StringComparison.OrdinalIgnoreCase) < 0)
{
throw new InvalidOperationException();
}
_imageOS = builder.DockerResourceConfiguration.Image.FullName.IndexOf("windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
}
if (!string.IsNullOrEmpty(_staticMappingsPath))
{
builder = builder.WithBindMount(_staticMappingsPath, _info[_imageOS.Value].MappingsPath);
}
builder.Validate();
return new WireMockContainer(builder.DockerResourceConfiguration);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -148,14 +193,7 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
{ {
var builder = base.Init(); var builder = base.Init();
// In case no image has been set, set the image using internal logic. var waitForContainerOS = _imageOS == OSPlatform.Windows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
if (builder.DockerResourceConfiguration.Image == null)
{
builder = builder.WithImage();
}
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
var waitForContainerOS = isWindows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
return builder return builder
.WithPortBinding(WireMockContainer.ContainerPort, true) .WithPortBinding(WireMockContainer.ContainerPort, true)
.WithCommand($"--WireMockLogger {DefaultLogger}") .WithCommand($"--WireMockLogger {DefaultLogger}")
@@ -179,4 +217,10 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
{ {
return new WireMockContainerBuilder(new WireMockConfiguration(oldValue, newValue)); return new WireMockContainerBuilder(new WireMockConfiguration(oldValue, newValue));
} }
private WireMockContainerBuilder WithImage(OSPlatform os)
{
_imageOS = os;
return WithImage(_info[os].Image);
}
} }

View File

@@ -2,6 +2,7 @@
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
using System; using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using FluentAssertions.Execution; using FluentAssertions.Execution;
@@ -13,7 +14,7 @@ namespace WireMock.Net.Tests.Testcontainers;
public class TestcontainersTests public class TestcontainersTests
{ {
[Fact] [Fact]
public async Task WireMockContainer_Build_and_StartAsync_and_StopAsync() public async Task WireMockContainer_Build_WithNoImage_And_StartAsync_and_StopAsync()
{ {
// Act // Act
var adminUsername = $"username_{Guid.NewGuid()}"; var adminUsername = $"username_{Guid.NewGuid()}";
@@ -24,6 +25,61 @@ public class TestcontainersTests
.WithAdminUserNameAndPassword(adminUsername, adminPassword) .WithAdminUserNameAndPassword(adminUsername, adminPassword)
.Build(); .Build();
await StartTestAndStopAsync(wireMockContainer);
}
[Fact]
public async Task WireMockContainer_Build_WithImage_And_StartAsync_and_StopAsync()
{
// Arrange
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainerBuilder = new WireMockContainerBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.WithAdminUserNameAndPassword(adminUsername, adminPassword);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
wireMockContainerBuilder = wireMockContainerBuilder.WithWindowsImage();
}
else
{
wireMockContainerBuilder = wireMockContainerBuilder.WithLinuxImage();
}
var wireMockContainer = wireMockContainerBuilder.Build();
await StartTestAndStopAsync(wireMockContainer);
}
[Fact]
public async Task WireMockContainer_Build_WithImageAsText_And_StartAsync_and_StopAsync()
{
// Arrange
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainerBuilder = new WireMockContainerBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.WithAdminUserNameAndPassword(adminUsername, adminPassword);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
wireMockContainerBuilder = wireMockContainerBuilder.WithImage("sheyenrath/wiremock.net-windows");
}
else
{
wireMockContainerBuilder = wireMockContainerBuilder.WithImage("sheyenrath/wiremock.net");
}
var wireMockContainer = wireMockContainerBuilder.Build();
await StartTestAndStopAsync(wireMockContainer);
}
private static async Task StartTestAndStopAsync(WireMockContainer wireMockContainer)
{
try try
{ {
await wireMockContainer.StartAsync().ConfigureAwait(false); await wireMockContainer.StartAsync().ConfigureAwait(false);