Skip to content

Commit

Permalink
WireMock.Net.Testcontainers: implement watching the static mapping fo…
Browse files Browse the repository at this point in the history
…lder for changes (#1189)

* WireMock.Net.Testcontainers: implement watching the static mapping files + folder for changes

* ReloadStaticMappings

* fix

* .

* .

* .

* .

* .

* .

* .

* CopyAsync

* <VersionPrefix>1.6.7-preview-02</VersionPrefix>

* <VersionPrefix>1.6.7-preview-03</VersionPrefix>
  • Loading branch information
StefH authored Dec 15, 2024
1 parent c548600 commit 2a19b44
Show file tree
Hide file tree
Showing 26 changed files with 509 additions and 119 deletions.
28 changes: 17 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: 'Execute Tests'
run: |
dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0
dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0

- name: 'WireMock.Net.TUnitTests'
run: dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0

- name: 'WireMock.Net.Middleware.Tests'
run: dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0

linux-build-and-run:
name: Run Tests on Linux
Expand All @@ -35,14 +38,17 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: 'Execute Tests'
run: |
dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0
dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0

- name: 'WireMock.Net.TUnitTests'
run: dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0

- name: 'WireMock.Net.Middleware.Tests'
run: dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0

- name: Install .NET Aspire workload
run: dotnet workload install aspire

- name: 'Execute .NET Aspire Tests'
- name: 'WireMock.Net.Aspire.Tests'
run: dotnet test './test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj' -c Release
2 changes: 1 addition & 1 deletion WireMock.Net Solution.sln
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TUnit", "src\W
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TUnitTests", "test\WireMock.Net.TUnitTests\WireMock.Net.TUnitTests.csproj", "{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.WebApplication", "examples\WireMock.Net.WebApplication\WireMock.Net.WebApplication.csproj", "{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication", "examples\WireMock.Net.WebApplication\WireMock.Net.WebApplication.csproj", "{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.AspNetCore.Middleware", "src\WireMock.Net.AspNetCore.Middleware\WireMock.Net.AspNetCore.Middleware.csproj", "{B6269AAC-170A-4346-8B9A-579DED3D9A13}"
EndProject
Expand Down
35 changes: 26 additions & 9 deletions azure-pipelines-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,25 @@ jobs:
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml"
displayName: 'WireMock.Net.Tests with Coverage'

- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml"
displayName: 'WireMock.Net.TUnitTests with Coverage'

- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml"
displayName: 'Execute WireMock.Net.Tests with Coverage'
displayName: 'WireMock.Net.Middleware.Tests with Coverage'

- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-aspire.xml"
displayName: 'Execute WireMock.Net.Aspire.Tests with Coverage'
displayName: 'WireMock.Net.Aspire.Tests with Coverage'

- task: CmdLine@2
displayName: 'Merge coverage files'
Expand Down Expand Up @@ -105,18 +115,25 @@ jobs:
version: '8.0.x'

- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
displayName: 'WireMock.Net.Tests with Coverage'
inputs:
command: 'build'
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework net8.0'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'

- task: DotNetCoreCLI@2
displayName: 'Execute Unit Tests with Coverage'
displayName: 'WireMock.Net.TUnitTests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--no-build --configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
projects: './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'

- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'

- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test
Expand Down
13 changes: 7 additions & 6 deletions examples-Aspire/AspireApp1.AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

var builder = DistributedApplication.CreateBuilder(args);

IResourceBuilder<ProjectResource> apiService = builder.AddProject<Projects.AspireApp1_ApiService>("apiservice");
// IResourceBuilder<ProjectResource> apiService = builder.AddProject<Projects.AspireApp1_ApiService>("apiservice");

var mappingsPath = Path.Combine(Directory.GetCurrentDirectory(), "WireMockMappings");

//IResourceBuilder<WireMockServerResource> apiService = builder
// .AddWireMock("apiservice", WireMockServerArguments.DefaultPort)
// .WithMappingsPath(mappingsPath)
// .WithReadStaticMappings()
// .WithApiMappingBuilder(WeatherForecastApiMock.BuildAsync);
IResourceBuilder<WireMockServerResource> apiService = builder
.AddWireMock("apiservice", WireMockServerArguments.DefaultPort)
.WithMappingsPath(mappingsPath)
.WithReadStaticMappings()
.WithWatchStaticMappings()
.WithApiMappingBuilder(WeatherForecastApiMock.BuildAsync);

//var apiServiceUsedForDocs = builder
// .AddWireMock("apiservice1", WireMockServerArguments.DefaultPort)
Expand Down
4 changes: 2 additions & 2 deletions examples-Aspire/AspireApp1.AppHost/WeatherForecastApiMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace AspireApp1.AppHost;

internal class WeatherForecastApiMock
{
public static async Task BuildAsync(AdminApiMappingBuilder builder)
public static async Task BuildAsync(AdminApiMappingBuilder builder, CancellationToken cancellationToken)
{
var summaries = new[]
{
Expand All @@ -29,7 +29,7 @@ public static async Task BuildAsync(AdminApiMappingBuilder builder)
)
);

await builder.BuildAndPostAsync();
await builder.BuildAndPostAsync(cancellationToken);
}
}

Expand Down
100 changes: 88 additions & 12 deletions examples/WireMock.Net.TestcontainersExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright © WireMock.Net

using DotNet.Testcontainers.Configurations;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using WireMock.Net.Testcontainers;
Expand All @@ -12,6 +13,32 @@ private static async Task Main(string[] args)
{
var original = Console.ForegroundColor;

try
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine("Copy");
await TestCopyAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}

try
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine("Automatic");
await TestAsync();
}
finally
{
Console.ForegroundColor = original;
}

try
{
Console.ForegroundColor = ConsoleColor.Yellow;
Expand Down Expand Up @@ -91,17 +118,44 @@ private static async Task Main(string[] args)
{
Console.ForegroundColor = original;
}
}

try
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Automatic");
await TestAsync();
}
finally
private static async Task TestCopyAsync()
{
var builder = new WireMockContainerBuilder()
.WithWatchStaticMappings(true)
.WithAutoRemove(true)
.WithCleanUp(true);

var container = builder.Build();

await container.StartAsync();

if (await GetImageOSAsync.Value == OSPlatform.Linux)
{
Console.ForegroundColor = original;
try
{
await container.CopyAsync(@"C:\temp-wiremock\__admin\mappings\StefBodyAsFileExample.json", "/app/__admin/mappings");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}

Console.WriteLine("PublicUrl = " + container.GetPublicUrl());

var adminClient = container.CreateWireMockAdminClient();

var mappings = await adminClient.GetMappingsAsync();
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));

await Task.Delay(1_000);

//Console.WriteLine("Press any key to stop.");
//Console.ReadKey();

await container.StopAsync();
}

private static async Task TestAsync(string? image = null)
Expand Down Expand Up @@ -129,23 +183,45 @@ private static async Task TestAsync(string? image = null)

await container.StartAsync();

await Task.Delay(1_000);
await container.ReloadStaticMappingsAsync();

var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1));
Console.WriteLine("logs = " + logs.Stdout);
//var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1));
//Console.WriteLine("logs = " + logs.Stdout);

Console.WriteLine("PublicUrl = " + container.GetPublicUrl());

var restEaseApiClient = container.CreateWireMockAdminClient();

var settings = await restEaseApiClient.GetSettingsAsync();
Console.WriteLine("settings = " + JsonConvert.SerializeObject(settings, Formatting.Indented));

var mappings = await restEaseApiClient.GetMappingsAsync();
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
Console.WriteLine("mappingsStef = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));

var client = container.CreateClient();
var result = await client.GetStringAsync("/static/mapping");
Console.WriteLine("result = " + result);

//if (image == null)
//{
// Console.WriteLine("Press any key to stop.");
// Console.ReadKey();
//}

await container.StopAsync();
}

private static Lazy<Task<OSPlatform>> GetImageOSAsync = new(async () =>
{
if (TestcontainersSettings.OS.DockerEndpointAuthConfig == null)
{
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
}

using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
using var dockerClient = dockerClientConfig.CreateClient();

var version = await dockerClient.System.GetVersionAsync();
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright © WireMock.Net

using Aspire.Hosting.ApplicationModel;

namespace WireMock.Net.Aspire.Extensions;

internal static class ResourceLoggerServiceExtensions
{
public static void SetLogger(this ResourceLoggerService resourceLoggerService, WireMockServerResource wireMockServerResource)
{
var logger = resourceLoggerService.GetLogger(wireMockServerResource);
wireMockServerResource.SetLogger(logger);
}
}
4 changes: 4 additions & 0 deletions src/WireMock.Net.Aspire/WireMock.Net.Aspire.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
Expand Down
6 changes: 3 additions & 3 deletions src/WireMock.Net.Aspire/WireMockServerArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class WireMockServerArguments
///
/// Default value is <c>false</c>.
/// </summary>
public bool WithWatchStaticMappings { get; set; }
public bool WatchStaticMappings { get; set; }

/// <summary>
/// Specifies the path for the (static) mapping json files.
Expand All @@ -65,7 +65,7 @@ public class WireMockServerArguments
/// <summary>
/// Optional delegate that will be invoked to configure the WireMock.Net resource using the <see cref="AdminApiMappingBuilder"/>.
/// </summary>
public Func<AdminApiMappingBuilder, Task>? ApiMappingBuilder { get; set; }
public Func<AdminApiMappingBuilder, CancellationToken, Task>? ApiMappingBuilder { get; set; }

/// <summary>
/// Converts the current instance's properties to an array of command-line arguments for starting the WireMock.Net server.
Expand All @@ -88,7 +88,7 @@ public string[] GetArgs()
Add(args, "--ReadStaticMappings", "true");
}

if (WithWatchStaticMappings)
if (WatchStaticMappings)
{
Add(args, "--ReadStaticMappings", "true");
Add(args, "--WatchStaticMappings", "true");
Expand Down
19 changes: 16 additions & 3 deletions src/WireMock.Net.Aspire/WireMockServerBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public static IResourceBuilder<WireMockServerResource> WithReadStaticMappings(th
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.WithWatchStaticMappings = true;
Guard.NotNull(wiremock).Resource.Arguments.WatchStaticMappings = true;
return wiremock;
}

Expand All @@ -124,8 +124,10 @@ public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(t
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithMappingsPath(this IResourceBuilder<WireMockServerResource> wiremock, string mappingsPath)
{
return Guard.NotNull(wiremock)
.WithBindMount(Guard.NotNullOrWhiteSpace(mappingsPath), DefaultLinuxMappingsPath);
Guard.NotNullOrWhiteSpace(mappingsPath);
Guard.NotNull(wiremock).Resource.Arguments.MappingsPath = mappingsPath;

return wiremock.WithBindMount(mappingsPath, DefaultLinuxMappingsPath);
}

/// <summary>
Expand All @@ -151,6 +153,17 @@ public static IResourceBuilder<WireMockServerResource> WithAdminUserNameAndPassw
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, Task> configure)
{
return wiremock.WithApiMappingBuilder((adminApiMappingBuilder, _) => configure.Invoke(adminApiMappingBuilder));
}

/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, CancellationToken, Task> configure)
{
Guard.NotNull(wiremock);

Expand Down
Loading

0 comments on commit 2a19b44

Please sign in to comment.