mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-25 10:52:52 +01:00
Add "AddUrl" to WireMockContainerBuilder to support grpc (#1246)
* Add "AddUrl" to WireMockContainerBuilder to support grpc * fix * fix for windows * wip * fix ! * change some example code
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="..\WireMock.Net\Http\HttpClientFactory2.cs" Link="Http\HttpClientFactory2.cs" />
|
||||
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
|
||||
<Compile Include="..\WireMock.Net\Util\PortUtils.cs" Link="Util\PortUtils.cs" />
|
||||
<Compile Include="..\WireMock.Net\Constants\WireMockConstants.cs" Link="Constants\WireMockConstants.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -28,6 +30,10 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Nullable" Version="1.3.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
||||
<PackageReference Include="Testcontainers" Version="4.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Docker.DotNet.Models;
|
||||
using DotNet.Testcontainers.Builders;
|
||||
using DotNet.Testcontainers.Configurations;
|
||||
@@ -24,6 +26,8 @@ public sealed class WireMockConfiguration : ContainerConfiguration
|
||||
|
||||
public bool HasBasicAuthentication => !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);
|
||||
|
||||
public List<string> AdditionalUrls { get; private set; } = [];
|
||||
|
||||
public WireMockConfiguration(string? username = null, string? password = null)
|
||||
{
|
||||
Username = username;
|
||||
@@ -70,6 +74,7 @@ public sealed class WireMockConfiguration : ContainerConfiguration
|
||||
StaticMappingsPath = BuildConfiguration.Combine(oldValue.StaticMappingsPath, newValue.StaticMappingsPath);
|
||||
WatchStaticMappings = BuildConfiguration.Combine(oldValue.WatchStaticMappings, newValue.WatchStaticMappings);
|
||||
WatchStaticMappingsInSubdirectories = BuildConfiguration.Combine(oldValue.WatchStaticMappingsInSubdirectories, newValue.WatchStaticMappingsInSubdirectories);
|
||||
AdditionalUrls = BuildConfiguration.Combine(oldValue.AdditionalUrls.AsEnumerable(), newValue.AdditionalUrls.AsEnumerable()).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,4 +99,15 @@ public sealed class WireMockConfiguration : ContainerConfiguration
|
||||
WatchStaticMappingsInSubdirectories = includeSubDirectories;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An additional Url on which WireMock listens.
|
||||
/// </summary>
|
||||
/// <param name="url">The url to add.</param>
|
||||
/// <returns><see cref="WireMockConfiguration"/></returns>
|
||||
public WireMockConfiguration WithAdditionalUrl(string url)
|
||||
{
|
||||
AdditionalUrls.Add(url);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -30,6 +32,7 @@ public sealed class WireMockContainer : DockerContainer
|
||||
|
||||
private IWireMockAdminApi? _adminApi;
|
||||
private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher;
|
||||
private IDictionary<int, Uri>? _publicUris;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WireMockContainer" /> class.
|
||||
@@ -48,6 +51,21 @@ public sealed class WireMockContainer : DockerContainer
|
||||
[PublicAPI]
|
||||
public string GetPublicUrl() => GetPublicUri().ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public Urls as a dictionary with the internal port as the key.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public IDictionary<int, string> GetPublicUrls() => GetPublicUris().ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mapped public port for the given container port.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string GetMappedPublicUrl(int containerPort)
|
||||
{
|
||||
return GetPublicUris()[containerPort].ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a RestEase Admin client which can be used to call the admin REST endpoint.
|
||||
/// </summary>
|
||||
@@ -121,7 +139,7 @@ public sealed class WireMockContainer : DockerContainer
|
||||
await ReloadStaticMappingsAsync(target, ct);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reload the static mappings.
|
||||
/// </summary>
|
||||
@@ -198,7 +216,14 @@ public sealed class WireMockContainer : DockerContainer
|
||||
|
||||
private async void FileCreatedChangedOrDeleted(object sender, FileSystemEventArgs args)
|
||||
{
|
||||
await ReloadStaticMappingsAsync(args.FullPath);
|
||||
try
|
||||
{
|
||||
await ReloadStaticMappingsAsync(args.FullPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex, "Error reloading static mappings from '{FullPath}'.", args.FullPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReloadStaticMappingsAsync(string path, CancellationToken cancellationToken = default)
|
||||
@@ -207,5 +232,27 @@ public sealed class WireMockContainer : DockerContainer
|
||||
await ReloadStaticMappingsAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private Uri GetPublicUri() => new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(ContainerPort)).Uri;
|
||||
private Uri GetPublicUri() => GetPublicUris()[ContainerPort];
|
||||
|
||||
private IDictionary<int, Uri> GetPublicUris()
|
||||
{
|
||||
if (_publicUris != null)
|
||||
{
|
||||
return _publicUris;
|
||||
}
|
||||
|
||||
_publicUris = _configuration.ExposedPorts.Keys
|
||||
.Select(int.Parse)
|
||||
.ToDictionary(port => port, port => new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(port)).Uri);
|
||||
|
||||
foreach (var url in _configuration.AdditionalUrls)
|
||||
{
|
||||
if (PortUtils.TryExtract(url, out _, out _, out _, out _, out var port))
|
||||
{
|
||||
_publicUris[port] = new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(port)).Uri;
|
||||
}
|
||||
}
|
||||
|
||||
return _publicUris;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Docker.DotNet.Models;
|
||||
using DotNet.Testcontainers.Builders;
|
||||
@@ -8,6 +9,7 @@ using DotNet.Testcontainers.Configurations;
|
||||
using JetBrains.Annotations;
|
||||
using Stef.Validation;
|
||||
using WireMock.Net.Testcontainers.Utils;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Net.Testcontainers;
|
||||
|
||||
@@ -132,6 +134,36 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
|
||||
WithCommand("--WatchStaticMappingsInSubdirectories", includeSubDirectories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use Http version 2.
|
||||
/// </summary>
|
||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
||||
[PublicAPI]
|
||||
public WireMockContainerBuilder WithHttp2()
|
||||
{
|
||||
return WithCommand("--UseHttp2 true");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds another URL to the WireMock container. By default, the WireMock container will listen on <c>http://*:80</c>.
|
||||
///
|
||||
/// This method can be used to also host the WireMock container on another port or protocol (like grpc).
|
||||
/// </summary>
|
||||
/// <example>grpc://*:9090</example>
|
||||
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
|
||||
[PublicAPI]
|
||||
public WireMockContainerBuilder AddUrl(string url)
|
||||
{
|
||||
if (!PortUtils.TryExtract(Guard.NotNullOrEmpty(url), out _, out _, out _, out _, out var port))
|
||||
{
|
||||
throw new ArgumentException("The URL is not valid.", nameof(url));
|
||||
}
|
||||
|
||||
DockerResourceConfiguration.WithAdditionalUrl(url);
|
||||
|
||||
return WithPortBinding(port, true);
|
||||
}
|
||||
|
||||
private WireMockContainerBuilder WithCommand(string param, bool value)
|
||||
{
|
||||
return !value ? this : WithCommand($"{param} true");
|
||||
@@ -172,6 +204,11 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
|
||||
builder = builder.WithBindMount(builder.DockerResourceConfiguration.StaticMappingsPath, ContainerInfoProvider.Info[_imageOS.Value].MappingsPath);
|
||||
}
|
||||
|
||||
if (builder.DockerResourceConfiguration.AdditionalUrls.Any())
|
||||
{
|
||||
builder = builder.WithCommand($"--Urls http://*:80 {string.Join(" ", builder.DockerResourceConfiguration.AdditionalUrls)}");
|
||||
}
|
||||
|
||||
builder.Validate();
|
||||
|
||||
return new WireMockContainer(builder.DockerResourceConfiguration);
|
||||
|
||||
@@ -83,32 +83,6 @@ internal static class PortUtils
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Finds free TCP ports.
|
||||
///// </summary>
|
||||
//public static IReadOnlyList<int> FindFreeTcpPorts(int numPorts)
|
||||
//{
|
||||
// var freePorts = new List<int>();
|
||||
|
||||
// TcpListener? tcpListener = null;
|
||||
// try
|
||||
// {
|
||||
// for (var i = 0; i < numPorts; i++)
|
||||
// {
|
||||
// tcpListener = new TcpListener(IPAddress.Loopback, 0);
|
||||
// tcpListener.Start();
|
||||
|
||||
// freePorts.Add(((IPEndPoint)tcpListener.LocalEndpoint).Port);
|
||||
// }
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// tcpListener?.Stop();
|
||||
// }
|
||||
|
||||
// return freePorts;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Extract the isHttps, isHttp2, protocol, host and port from a URL.
|
||||
/// </summary>
|
||||
@@ -118,7 +92,7 @@ internal static class PortUtils
|
||||
isHttp2 = false;
|
||||
protocol = null;
|
||||
host = null;
|
||||
port = default;
|
||||
port = 0;
|
||||
|
||||
var match = UrlDetailsRegex.Match(url);
|
||||
if (match.Success)
|
||||
|
||||
Reference in New Issue
Block a user