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:
Stef Heyenrath
2025-01-29 22:09:17 +01:00
committed by GitHub
parent f5fe51e227
commit 52b00d74a9
11 changed files with 332 additions and 61 deletions

View File

@@ -12,7 +12,7 @@ using FluentAssertions;
using Google.Protobuf.WellKnownTypes;
using Greet;
using Grpc.Net.Client;
using NarrowIntegrationTest.Lookup;
using ExampleIntegrationTest.Lookup;
using WireMock.Constants;
using WireMock.Matchers;
using WireMock.RequestBuilders;
@@ -668,7 +668,7 @@ message Other {
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf(definition, "NarrowIntegrationTest.Lookup.GetVersionResponse",
.WithBodyAsProtoBuf(definition, "ExampleIntegrationTest.Lookup.GetVersionResponse",
new GetVersionResponse
{
Version = version,
@@ -677,9 +677,9 @@ message Other {
Seconds = seconds,
Nanos = nanos
},
Client = new NarrowIntegrationTest.Lookup.Client
Client = new ExampleIntegrationTest.Lookup.Client
{
ClientName = NarrowIntegrationTest.Lookup.Client.Types.Clients.BillingCenter,
ClientName = ExampleIntegrationTest.Lookup.Client.Types.Clients.Test,
CorrelationId = correlationId
}
}
@@ -695,23 +695,34 @@ message Other {
// Assert
reply.Version.Should().Be(version);
reply.DateHired.Should().Be(new Timestamp { Seconds = seconds, Nanos = nanos });
reply.Client.ClientName.Should().Be(NarrowIntegrationTest.Lookup.Client.Types.Clients.BillingCenter);
reply.Client.ClientName.Should().Be(ExampleIntegrationTest.Lookup.Client.Types.Clients.Test);
reply.Client.CorrelationId.Should().Be(correlationId);
}
[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinitionFromJson_UsingGrpcGeneratedClient()
public async Task WireMockServer_WithBodyAsProtoBuf_FromJson_UsingGrpcGeneratedClient()
{
var server = Given_When_ServerStartedUsingHttp2();
Given_ProtoDefinition_IsAddedOnServerLevel(server);
await Given_When_ProtoBufMappingIsAddedViaAdminInterfaceAsync(server);
var server = Given_When_ServerStarted_And_RunningOnHttpAndGrpc();
await Given_When_ProtoBufMappingIsAddedViaAdminInterfaceAsync(server, "protobuf-mapping-1.json");
var reply = await When_GrpcClient_Calls_SayHelloAsync(server.Urls[1]);
Then_ReplyMessage_Should_BeCorrect(reply);
}
private static WireMockServer Given_When_ServerStartedUsingHttp2()
[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinitionFromJson_UsingGrpcGeneratedClient()
{
var server = Given_When_ServerStarted_And_RunningOnHttpAndGrpc();
Given_ProtoDefinition_IsAddedOnServerLevel(server);
await Given_When_ProtoBufMappingIsAddedViaAdminInterfaceAsync(server, "protobuf-mapping-3.json");
var reply = await When_GrpcClient_Calls_SayHelloAsync(server.Urls[1]);
Then_ReplyMessage_Should_BeCorrect(reply);
}
private static WireMockServer Given_When_ServerStarted_And_RunningOnHttpAndGrpc()
{
var ports = PortUtils.FindFreeTcpPorts(2);
@@ -728,9 +739,9 @@ message Other {
server.AddProtoDefinition("my-greeter", ReadProtoFile("greet.proto"));
}
private static async Task Given_When_ProtoBufMappingIsAddedViaAdminInterfaceAsync(WireMockServer server)
private static async Task Given_When_ProtoBufMappingIsAddedViaAdminInterfaceAsync(WireMockServer server, string filename)
{
var mappingsJson = ReadMappingFile("protobuf-mapping-3.json");
var mappingsJson = ReadMappingFile(filename);
using var httpClient = server.CreateClient();

View File

@@ -1,6 +1,6 @@
syntax = "proto3";
option csharp_namespace = "NarrowIntegrationTest.Lookup";
option csharp_namespace = "ExampleIntegrationTest.Lookup";
import "google/protobuf/timestamp.proto";
@@ -24,17 +24,8 @@ message Client {
string CorrelationId = 1;
enum Clients {
Unknown = 0;
QMS = 1;
BillingCenter = 2;
PAS = 3;
Payroll = 4;
Portal = 5;
SFO = 6;
QuoteAndBind = 7;
LegacyConversion = 8;
BindNow = 9;
PaymentPortal = 10 ;
PricingEngine = 11;
Other = 1;
Test = 2;
}
Clients ClientName = 2;
}

View File

@@ -0,0 +1,186 @@
// Copyright © WireMock.Net
#if NET6_0_OR_GREATER
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using FluentAssertions.Execution;
using Greet;
using Grpc.Net.Client;
using WireMock.Constants;
using WireMock.Net.Testcontainers;
using Xunit;
namespace WireMock.Net.Tests.Testcontainers;
public partial class TestcontainersTests
{
[Fact]
public async Task WireMockContainer_Build_Grpc_TestPortsAndUrls1()
{
// Act
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainer = new WireMockContainerBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.WithAdminUserNameAndPassword(adminUsername, adminPassword)
.WithCommand("--UseHttp2")
.WithCommand("--Urls", "http://*:80 grpc://*:9090")
.WithPortBinding(9090, true)
.Build();
try
{
await wireMockContainer.StartAsync().ConfigureAwait(false);
// Assert
using (new AssertionScope())
{
var logs = await wireMockContainer.GetLogsAsync(DateTime.MinValue);
logs.Should().NotBeNull();
var url = wireMockContainer.GetPublicUrl();
url.Should().NotBeNullOrWhiteSpace();
var urls = wireMockContainer.GetPublicUrls();
urls.Should().HaveCount(2);
var httpPort = wireMockContainer.GetMappedPublicPort(80);
httpPort.Should().BeGreaterThan(0);
var httpUrl = wireMockContainer.GetMappedPublicUrl(80);
httpUrl.Should().StartWith("http://");
var grpcPort = wireMockContainer.GetMappedPublicPort(9090);
grpcPort.Should().BeGreaterThan(0);
var grpcUrl = wireMockContainer.GetMappedPublicUrl(80);
grpcUrl.Should().StartWith("http://");
var adminClient = wireMockContainer.CreateWireMockAdminClient();
var settings = await adminClient.GetSettingsAsync();
settings.Should().NotBeNull();
}
}
finally
{
await wireMockContainer.StopAsync();
}
}
[Fact]
public async Task WireMockContainer_Build_Grpc_TestPortsAndUrls2()
{
// Act
var adminUsername = $"username_{Guid.NewGuid()}";
var adminPassword = $"password_{Guid.NewGuid()}";
var wireMockContainer = new WireMockContainerBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.WithAdminUserNameAndPassword(adminUsername, adminPassword)
.AddUrl("http://*:8080")
.AddUrl("grpc://*:9090")
.AddUrl("grpc://*:9091")
.Build();
try
{
await wireMockContainer.StartAsync().ConfigureAwait(false);
// Assert
using (new AssertionScope())
{
var logs = await wireMockContainer.GetLogsAsync(DateTime.MinValue);
logs.Should().NotBeNull();
var url = wireMockContainer.GetPublicUrl();
url.Should().NotBeNullOrWhiteSpace();
var urls = wireMockContainer.GetPublicUrls();
urls.Should().HaveCount(4);
foreach (var internalPort in new[] { 80, 8080, 9090, 9091 })
{
var publicPort = wireMockContainer.GetMappedPublicPort(internalPort);
publicPort.Should().BeGreaterThan(0);
var publicUrl = wireMockContainer.GetMappedPublicUrl(internalPort);
publicUrl.Should().StartWith("http://");
}
var adminClient = wireMockContainer.CreateWireMockAdminClient();
var settings = await adminClient.GetSettingsAsync();
settings.Should().NotBeNull();
}
}
finally
{
await wireMockContainer.StopAsync();
}
}
[Fact]
public async Task WireMockContainer_Build_Grpc_ProtoDefinitionFromJson_UsingGrpcGeneratedClient()
{
var wireMockContainer = await Given_WireMockContainerIsStartedForHttpAndGrpc();
await Given_ProtoBufMappingIsAddedViaAdminInterfaceAsync(wireMockContainer);
var reply = await When_GrpcClient_Calls_SayHelloAsync(wireMockContainer);
Then_ReplyMessage_Should_BeCorrect(reply);
await wireMockContainer.StopAsync();
}
private static async Task<WireMockContainer> Given_WireMockContainerIsStartedForHttpAndGrpc()
{
var wireMockContainer = new WireMockContainerBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.AddUrl("grpc://*:9090")
.Build();
await wireMockContainer.StartAsync();
return wireMockContainer;
}
private static async Task Given_ProtoBufMappingIsAddedViaAdminInterfaceAsync(WireMockContainer wireMockContainer)
{
var mappingsJson = ReadMappingFile("protobuf-mapping-1.json");
using var httpClient = wireMockContainer.CreateClient();
var result = await httpClient.PostAsync("/__admin/mappings", new StringContent(mappingsJson, Encoding.UTF8, WireMockConstants.ContentTypeJson));
result.EnsureSuccessStatusCode();
}
private static async Task<HelloReply> When_GrpcClient_Calls_SayHelloAsync(WireMockContainer wireMockContainer)
{
var address = wireMockContainer.GetPublicUrls()[9090];
var channel = GrpcChannel.ForAddress(address);
var client = new Greeter.GreeterClient(channel);
return await client.SayHelloAsync(new HelloRequest { Name = "stef" });
}
private static void Then_ReplyMessage_Should_BeCorrect(HelloReply reply)
{
reply.Message.Should().Be("hello stef POST");
}
private static string ReadMappingFile(string filename)
{
return File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "__admin", "mappings", filename));
}
}
#endif

View File

@@ -8,15 +8,16 @@ using DotNet.Testcontainers.Builders;
using FluentAssertions;
using FluentAssertions.Execution;
using WireMock.Net.Testcontainers;
using WireMock.Net.Testcontainers.Utils;
using WireMock.Net.Tests.Facts;
using Xunit;
namespace WireMock.Net.Tests.Testcontainers;
public class TestcontainersTests
public partial class TestcontainersTests
{
[Fact]
public async Task WireMockContainer_Build_WithNoImage_And_StartAsync_and_StopAsync()
public async Task WireMockContainer_Build_And_StartAsync_and_StopAsync()
{
// Act
var adminUsername = $"username_{Guid.NewGuid()}";
@@ -32,7 +33,7 @@ public class TestcontainersTests
// https://github.com/testcontainers/testcontainers-dotnet/issues/1322
[RunOnDockerPlatformFact("Linux")]
public async Task WireMockContainer_Build_WithNoImageAndNetwork_And_StartAsync_and_StopAsync()
public async Task WireMockContainer_Build_WithNetwork_And_StartAsync_and_StopAsync()
{
// Act
var dummyNetwork = new NetworkBuilder()
@@ -61,7 +62,8 @@ public class TestcontainersTests
.WithCleanUp(true)
.WithAdminUserNameAndPassword(adminUsername, adminPassword);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
var imageOS = await TestcontainersUtils.GetImageOSAsync.Value;
if (imageOS == OSPlatform.Windows)
{
wireMockContainerBuilder = wireMockContainerBuilder.WithWindowsImage();
}
@@ -86,7 +88,8 @@ public class TestcontainersTests
.WithCleanUp(true)
.WithAdminUserNameAndPassword(adminUsername, adminPassword);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
var imageOS = await TestcontainersUtils.GetImageOSAsync.Value;
if (imageOS == OSPlatform.Windows)
{
wireMockContainerBuilder = wireMockContainerBuilder.WithImage("sheyenrath/wiremock.net-windows");
}

View File

@@ -32,7 +32,7 @@
},
"Response": {
"BodyAsJson": {
"message": "hello {{request.BodyAsJson.name}}"
"message": "hello {{request.BodyAsJson.name}} {{request.method}}"
},
"UseTransformer": true,
"TransformerType": "Handlebars",