mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-26 11:21:51 +01:00
Add Aspire Extension (#1109)
* WireMock.Net.Aspire * . * xxx * nuget * [CodeFactor] Apply fixes * ut * t * **WireMock.Net.Aspire** * . * t * . * . * . * TESTS * docker utils * Install .NET Aspire workload * 4 * 4! * projects: '**/test/**/*.csproj' * script: 'dotnet workload install aspire' * projects: '**/test/**/*.csproj' * coverage * WithWatchStaticMappings * Admin * typo * port * fix * . * x * ... * wait * readme * x * 2 * async * <Version>0.0.1-preview-03</Version> * ... * fix aspire * admin/pwd * Install .NET Aspire workload * 0.0.1-preview-04 * WaitForHealthAsync * ... * IsHealthyAsync * . * add eps * name: 'Execute Aspire Tests' * name: Install .NET Aspire workload * . * dotnet test * remove duplicate * . * cc * dotnet tool install --global coverlet.console * -* * merge * /d:sonar.pullrequest.provider=github * <Version>0.0.1-preview-05</Version> * // Copyright © WireMock.Net * . --------- Co-authored-by: codefactor-io <support@codefactor.io>
This commit is contained in:
96
src/WireMock.Net.Aspire/DistributedApplicationExtensions.cs
Normal file
96
src/WireMock.Net.Aspire/DistributedApplicationExtensions.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Globalization;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using Aspire.Hosting.ApplicationModel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using RestEase;
|
||||
using WireMock.Client;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Aspire.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Some WireMock.Net extension methods for working with <see cref="DistributedApplication"/>.
|
||||
/// Based on https://github.com/dotnet/aspire/blob/main/src/Aspire.Hosting.Testing/DistributedApplicationHostingTestingExtensions.cs
|
||||
/// </summary>
|
||||
public static class DistributedApplicationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a RestEase Admin client which can be used to call the admin REST endpoint.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="DistributedApplication"/>.</param>
|
||||
/// <param name="resourceName">The resourceName of the resource.</param>
|
||||
/// <param name="endpointName">The resourceName of the endpoint on the resource to communicate with.</param>
|
||||
/// <returns>A <see cref="IWireMockAdminApi"/></returns>
|
||||
public static IWireMockAdminApi CreateWireMockAdminClient(this DistributedApplication app, string resourceName, string? endpointName = default)
|
||||
{
|
||||
ThrowIfNotStarted(app);
|
||||
|
||||
var (resource, endpointUri) = GetResourceAndEndpointUri(app, resourceName);
|
||||
|
||||
var api = RestClient.For<IWireMockAdminApi>(endpointUri);
|
||||
if (resource.Arguments.HasBasicAuthentication)
|
||||
{
|
||||
api.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{resource.Arguments.AdminUsername}:{resource.Arguments.AdminPassword}")));
|
||||
}
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
private static (WireMockServerResource WireMockServerResource, string EndpointUri) GetResourceAndEndpointUri(IHost app, string resourceName, string? endpointName = default)
|
||||
{
|
||||
var wireMockServerResource = GetWireMockServerResource(app, resourceName);
|
||||
|
||||
EndpointReference? endpoint;
|
||||
if (!string.IsNullOrEmpty(endpointName))
|
||||
{
|
||||
endpoint = GetEndpointOrDefault(wireMockServerResource, endpointName);
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = GetEndpointOrDefault(wireMockServerResource, "http") ?? GetEndpointOrDefault(wireMockServerResource, "https");
|
||||
}
|
||||
|
||||
if (endpoint is null)
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Endpoint '{0}' for resource '{1}' not found.", endpointName, resourceName), nameof(endpointName));
|
||||
}
|
||||
|
||||
return (wireMockServerResource, endpoint.Url);
|
||||
}
|
||||
|
||||
private static WireMockServerResource GetWireMockServerResource(IHost app, string resourceName)
|
||||
{
|
||||
var applicationModel = app.Services.GetRequiredService<DistributedApplicationModel>();
|
||||
|
||||
var resource = applicationModel.Resources
|
||||
.OfType<WireMockServerResource>()
|
||||
.SingleOrDefault(r => string.Equals(r.Name, resourceName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (resource is null)
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "WireMockServerResource with name '{0}' not found.", resourceName), nameof(resourceName));
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private static EndpointReference? GetEndpointOrDefault(IResourceWithEndpoints wireMockServerResource, string endpointName)
|
||||
{
|
||||
var reference = wireMockServerResource.GetEndpoint(endpointName);
|
||||
|
||||
return reference.IsAllocated ? reference : null;
|
||||
}
|
||||
|
||||
private static void ThrowIfNotStarted(IHost app)
|
||||
{
|
||||
var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
|
||||
if (!lifetime.ApplicationStarted.IsCancellationRequested)
|
||||
{
|
||||
throw new InvalidOperationException("The application must be started before resolving endpoints or connection strings");
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/WireMock.Net.Aspire/Properties/AssemblyInfo.cs
Normal file
6
src/WireMock.Net.Aspire/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("WireMock.Net.Aspire.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||
|
||||
// Needed for Moq in the UnitTest project
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
||||
47
src/WireMock.Net.Aspire/WireMock.Net.Aspire.csproj
Normal file
47
src/WireMock.Net.Aspire/WireMock.Net.Aspire.csproj
Normal file
@@ -0,0 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>0.0.1-preview-05</Version>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Description>Aspire extension to start a WireMock.Net server to stub an api.</Description>
|
||||
<AssemblyTitle>WireMock.Net.Aspire</AssemblyTitle>
|
||||
<Authors>Stef Heyenrath</Authors>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<AssemblyName>WireMock.Net.Aspire</AssemblyName>
|
||||
<PackageId>WireMock.Net.Aspire</PackageId>
|
||||
<PackageTags>dotnet;aspire;wiremock;extension</PackageTags>
|
||||
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A12}</ProjectGuid>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageIcon>WireMock.Net-LogoAspire.png</PackageIcon>
|
||||
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="../../resources/WireMock.Net-Logo.png" />
|
||||
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
112
src/WireMock.Net.Aspire/WireMockServerArguments.cs
Normal file
112
src/WireMock.Net.Aspire/WireMockServerArguments.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using WireMock.Client.Builders;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Aspire.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the arguments required to configure and start a WireMock.Net Server.
|
||||
/// </summary>
|
||||
public class WireMockServerArguments
|
||||
{
|
||||
internal const int HttpContainerPort = 80;
|
||||
|
||||
/// <summary>
|
||||
/// The default HTTP port where WireMock.Net is listening.
|
||||
/// </summary>
|
||||
public const int DefaultPort = 9091;
|
||||
|
||||
private const string DefaultLogger = "WireMockConsoleLogger";
|
||||
|
||||
/// <summary>
|
||||
/// The HTTP port where WireMock.Net is listening.
|
||||
/// If not defined, .NET Aspire automatically assigns a random port.
|
||||
/// </summary>
|
||||
public int? HttpPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The admin username.
|
||||
/// </summary>
|
||||
[MemberNotNullWhen(true, nameof(HasBasicAuthentication))]
|
||||
public string? AdminUsername { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The admin password.
|
||||
/// </summary>
|
||||
[MemberNotNullWhen(true, nameof(HasBasicAuthentication))]
|
||||
public string? AdminPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the static mappings should be read at startup.
|
||||
///
|
||||
/// Default value is <c>false</c>.
|
||||
/// </summary>
|
||||
public bool ReadStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Watch the static mapping files + folder for changes when running.
|
||||
///
|
||||
/// Default value is <c>false</c>.
|
||||
/// </summary>
|
||||
public bool WithWatchStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the path for the (static) mapping json files.
|
||||
/// </summary>
|
||||
public string? MappingsPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the admin interface has Basic Authentication.
|
||||
/// </summary>
|
||||
public bool HasBasicAuthentication => !string.IsNullOrEmpty(AdminUsername) && !string.IsNullOrEmpty(AdminPassword);
|
||||
|
||||
/// <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; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current instance's properties to an array of command-line arguments for starting the WireMock.Net server.
|
||||
/// </summary>
|
||||
/// <returns>An array of strings representing the command-line arguments.</returns>
|
||||
public string[] GetArgs()
|
||||
{
|
||||
var args = new Dictionary<string, string>();
|
||||
|
||||
Add(args, "--WireMockLogger", DefaultLogger);
|
||||
|
||||
if (HasBasicAuthentication)
|
||||
{
|
||||
Add(args, "--AdminUserName", AdminUsername!);
|
||||
Add(args, "--AdminPassword", AdminPassword!);
|
||||
}
|
||||
|
||||
if (ReadStaticMappings)
|
||||
{
|
||||
Add(args, "--ReadStaticMappings", "true");
|
||||
}
|
||||
|
||||
if (WithWatchStaticMappings)
|
||||
{
|
||||
Add(args, "--ReadStaticMappings", "true");
|
||||
Add(args, "--WatchStaticMappings", "true");
|
||||
Add(args, "--WatchStaticMappingsInSubdirectories", "true");
|
||||
}
|
||||
|
||||
return args
|
||||
.SelectMany(k => new[] { k.Key, k.Value })
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static void Add(IDictionary<string, string> args, string argument, string value)
|
||||
{
|
||||
args[argument] = value;
|
||||
}
|
||||
|
||||
private static void Add(IDictionary<string, string> args, string argument, Func<string> action)
|
||||
{
|
||||
args[argument] = action();
|
||||
}
|
||||
}
|
||||
162
src/WireMock.Net.Aspire/WireMockServerBuilderExtensions.cs
Normal file
162
src/WireMock.Net.Aspire/WireMockServerBuilderExtensions.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Aspire.Hosting.ApplicationModel;
|
||||
using Aspire.Hosting.Lifecycle;
|
||||
using Stef.Validation;
|
||||
using WireMock.Client.Builders;
|
||||
using WireMock.Net.Aspire;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Aspire.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for adding WireMock.Net Server resources to the application model.
|
||||
/// </summary>
|
||||
public static class WireMockServerBuilderExtensions
|
||||
{
|
||||
// Linux only (https://github.com/dotnet/aspire/issues/854)
|
||||
private const string DefaultLinuxImage = "sheyenrath/wiremock.net-alpine";
|
||||
private const string DefaultLinuxMappingsPath = "/app/__admin/mappings";
|
||||
|
||||
/// <summary>
|
||||
/// Adds a WireMock.Net Server resource to the application model.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
|
||||
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
|
||||
/// <param name="port">The HTTP port for the WireMock Server.</param>
|
||||
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
|
||||
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, int? port = null)
|
||||
{
|
||||
Guard.NotNull(builder);
|
||||
Guard.NotNullOrWhiteSpace(name);
|
||||
Guard.Condition(port, p => p is null or > 0 and <= ushort.MaxValue);
|
||||
|
||||
return builder.AddWireMock(name, callback =>
|
||||
{
|
||||
callback.HttpPort = port;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a WireMock.Net Server resource to the application model.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
|
||||
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
|
||||
/// <param name="arguments">The arguments to start the WireMock.Net Server.</param>
|
||||
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
|
||||
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, WireMockServerArguments arguments)
|
||||
{
|
||||
Guard.NotNull(builder);
|
||||
Guard.NotNullOrWhiteSpace(name);
|
||||
Guard.NotNull(arguments);
|
||||
|
||||
var wireMockContainerResource = new WireMockServerResource(name, arguments);
|
||||
var resourceBuilder = builder
|
||||
.AddResource(wireMockContainerResource)
|
||||
.WithImage(DefaultLinuxImage)
|
||||
.WithEnvironment(ctx => ctx.EnvironmentVariables.Add("DOTNET_USE_POLLING_FILE_WATCHER", "1")) // https://khalidabuhakmeh.com/aspnet-docker-gotchas-and-workarounds#configuration-reloads-and-filesystemwatcher
|
||||
.WithHttpEndpoint(port: arguments.HttpPort, targetPort: WireMockServerArguments.HttpContainerPort);
|
||||
|
||||
if (!string.IsNullOrEmpty(arguments.MappingsPath))
|
||||
{
|
||||
resourceBuilder = resourceBuilder.WithBindMount(arguments.MappingsPath, DefaultLinuxMappingsPath);
|
||||
}
|
||||
|
||||
resourceBuilder = resourceBuilder.WithArgs(ctx =>
|
||||
{
|
||||
foreach (var arg in arguments.GetArgs())
|
||||
{
|
||||
ctx.Args.Add(arg);
|
||||
}
|
||||
});
|
||||
|
||||
return resourceBuilder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a WireMock.Net Server resource to the application model.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
|
||||
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
|
||||
/// <param name="callback">A callback that allows for setting the <see cref="WireMockServerArguments"/>.</param>
|
||||
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
|
||||
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, Action<WireMockServerArguments> callback)
|
||||
{
|
||||
Guard.NotNull(builder);
|
||||
Guard.NotNullOrWhiteSpace(name);
|
||||
Guard.NotNull(callback);
|
||||
|
||||
var arguments = new WireMockServerArguments();
|
||||
callback(arguments);
|
||||
|
||||
return builder.AddWireMock(name, arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the static mappings should be read at startup.
|
||||
///
|
||||
/// Default set to <c>false</c>.
|
||||
/// </summary>
|
||||
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
|
||||
public static IResourceBuilder<WireMockServerResource> WithReadStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
|
||||
{
|
||||
Guard.NotNull(wiremock).Resource.Arguments.ReadStaticMappings = true;
|
||||
return wiremock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Watch the static mapping files + folder for changes when running.
|
||||
///
|
||||
/// Default set to <c>false</c>.
|
||||
/// </summary>
|
||||
/// <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;
|
||||
return wiremock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the path for the (static) mapping json files.
|
||||
/// </summary>
|
||||
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
|
||||
/// <param name="mappingsPath">The local path.</param>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the admin username and password for accessing the admin interface from WireMock.Net via HTTP.
|
||||
/// </summary>
|
||||
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
|
||||
/// <param name="username">The admin username.</param>
|
||||
/// <param name="password">The admin password.</param>
|
||||
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
|
||||
public static IResourceBuilder<WireMockServerResource> WithAdminUserNameAndPassword(this IResourceBuilder<WireMockServerResource> wiremock, string username, string password)
|
||||
{
|
||||
Guard.NotNull(wiremock);
|
||||
|
||||
wiremock.Resource.Arguments.AdminUsername = Guard.NotNull(username);
|
||||
wiremock.Resource.Arguments.AdminPassword = Guard.NotNull(password);
|
||||
return wiremock;
|
||||
}
|
||||
|
||||
/// <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, Task> configure)
|
||||
{
|
||||
Guard.NotNull(wiremock);
|
||||
|
||||
wiremock.ApplicationBuilder.Services.TryAddLifecycleHook<WireMockServerLifecycleHook>();
|
||||
wiremock.Resource.Arguments.ApiMappingBuilder = configure;
|
||||
|
||||
return wiremock;
|
||||
}
|
||||
}
|
||||
52
src/WireMock.Net.Aspire/WireMockServerLifecycleHook.cs
Normal file
52
src/WireMock.Net.Aspire/WireMockServerLifecycleHook.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Aspire.Hosting.ApplicationModel;
|
||||
using Aspire.Hosting.Lifecycle;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RestEase;
|
||||
using WireMock.Client;
|
||||
using WireMock.Client.Extensions;
|
||||
|
||||
namespace WireMock.Net.Aspire;
|
||||
|
||||
internal class WireMockServerLifecycleHook(ResourceLoggerService loggerService) : IDistributedApplicationLifecycleHook
|
||||
{
|
||||
public async Task AfterResourcesCreatedAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var wireMockServerResources = appModel.Resources
|
||||
.OfType<WireMockServerResource>()
|
||||
.Where(resource => resource.Arguments.ApiMappingBuilder is not null)
|
||||
.ToArray();
|
||||
|
||||
if (wireMockServerResources.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var wireMockServerResource in wireMockServerResources)
|
||||
{
|
||||
var endpoint = wireMockServerResource.GetEndpoint();
|
||||
if (endpoint.IsAllocated)
|
||||
{
|
||||
var adminApi = CreateWireMockAdminApi(wireMockServerResource);
|
||||
|
||||
var logger = loggerService.GetLogger(wireMockServerResource);
|
||||
logger.LogInformation("Checking Health status from WireMock.Net");
|
||||
|
||||
await adminApi.WaitForHealthAsync(cancellationToken: cancellationToken);
|
||||
|
||||
logger.LogInformation("Calling ApiMappingBuilder to add mappings to WireMock.Net");
|
||||
var mappingBuilder = adminApi.GetMappingBuilder();
|
||||
await wireMockServerResource.Arguments.ApiMappingBuilder!.Invoke(mappingBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IWireMockAdminApi CreateWireMockAdminApi(WireMockServerResource resource)
|
||||
{
|
||||
var adminApi = RestClient.For<IWireMockAdminApi>(resource.GetEndpoint().Url);
|
||||
return resource.Arguments.HasBasicAuthentication ?
|
||||
adminApi.WithAuthorization(resource.Arguments.AdminUsername!, resource.Arguments.AdminPassword!) :
|
||||
adminApi;
|
||||
}
|
||||
}
|
||||
33
src/WireMock.Net.Aspire/WireMockServerResource.cs
Normal file
33
src/WireMock.Net.Aspire/WireMockServerResource.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Stef.Validation;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Aspire.Hosting.ApplicationModel;
|
||||
|
||||
/// <summary>
|
||||
/// A resource that represents a WireMock.Net Server.
|
||||
/// </summary>
|
||||
public class WireMockServerResource : ContainerResource, IResourceWithServiceDiscovery
|
||||
{
|
||||
internal WireMockServerArguments Arguments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WireMockServerResource"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the resource.</param>
|
||||
/// <param name="arguments">The arguments to start the WireMock.Net Server.</param>
|
||||
public WireMockServerResource(string name, WireMockServerArguments arguments) : base(name)
|
||||
{
|
||||
Arguments = Guard.NotNull(arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an endpoint reference.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="EndpointReference"/> object representing the endpoint reference.</returns>
|
||||
public EndpointReference GetEndpoint()
|
||||
{
|
||||
return new EndpointReference(this, "http");
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using DotNet.Testcontainers.Containers;
|
||||
using JetBrains.Annotations;
|
||||
using RestEase;
|
||||
@@ -103,4 +101,4 @@ public sealed class WireMockContainer : DockerContainer
|
||||
}
|
||||
|
||||
private Uri GetPublicUri() => new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(ContainerPort)).Uri;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user