Skip to content

Commit

Permalink
Fix protobuf Empty
Browse files Browse the repository at this point in the history
  • Loading branch information
StefH committed Jan 3, 2025
1 parent c4f6ffa commit 38d78fc
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright © WireMock.Net

#pragma warning disable CS1591
using WireMock.Extensions;
using WireMock.Matchers;

// ReSharper disable once CheckNamespace
namespace WireMock.FluentAssertions;

#pragma warning disable CS1591
public partial class WireMockAssertions
{
[CustomAssertion]
Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private bool IsFault(IResponseMessage responseMessage)
#if PROTOBUF
case BodyType.ProtoBuf:
var protoDefinitions = bodyData.ProtoDefinition?.Invoke().Texts;
return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinitions, responseMessage.BodyData.ProtoBufMessageType, responseMessage.BodyData.BodyAsJson).ConfigureAwait(false);
return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinitions, bodyData.ProtoBufMessageType, bodyData.BodyAsJson).ConfigureAwait(false);
#endif

case BodyType.Bytes:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright © WireMock.Net

using System.Collections.Generic;
using System.Linq;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.Models;
Expand Down
10 changes: 6 additions & 4 deletions src/WireMock.Net/ResponseBuilders/Response.WithBody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ public IResponseBuilder WithBodyAsProtoBuf(
Guard.NotNull(value);

#if !PROTOBUF
throw new System.NotSupportedException("The WithBodyAsProtoBuf method can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
throw new NotSupportedException("The WithBodyAsProtoBuf method can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
#else
ResponseMessage.BodyDestination = null;
ResponseMessage.BodyData = new BodyData
Expand All @@ -252,8 +252,9 @@ public IResponseBuilder WithBodyAsProtoBuf(
ProtoDefinition = () => new IdOrTexts(null, protoDefinitions),
ProtoBufMessageType = messageType
};
#endif

return this;
#endif
}

/// <inheritdoc />
Expand All @@ -268,7 +269,7 @@ public IResponseBuilder WithBodyAsProtoBuf(
Guard.NotNull(value);

#if !PROTOBUF
throw new System.NotSupportedException("The WithBodyAsProtoBuf method can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
throw new NotSupportedException("The WithBodyAsProtoBuf method can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
#else
ResponseMessage.BodyDestination = null;
ResponseMessage.BodyData = new BodyData
Expand All @@ -278,7 +279,8 @@ public IResponseBuilder WithBodyAsProtoBuf(
ProtoDefinition = () => Mapping.ProtoDefinition ?? throw new WireMockException("ProtoDefinition cannot be resolved. You probably forgot to call .WithProtoDefinition(...) on the mapping."),
ProtoBufMessageType = messageType
};
#endif

return this;
#endif
}
}
2 changes: 1 addition & 1 deletion src/WireMock.Net/Util/ProtoBufUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ internal static async Task<byte[]> GetProtoBufMessageWithHeaderAsync(
}

var resolver = new WireMockProtoFileResolver(protoDefinitions);
var request = new ConvertToProtoBufRequest(protoDefinitions[0], messageType, value, true)
var request = new ConvertToProtoBufRequest(protoDefinitions[0], messageType!, value, true)
.WithProtoFileResolver(resolver);

return await SingletonFactory<Converter>
Expand Down
3 changes: 2 additions & 1 deletion src/WireMock.Net/WireMock.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,15 @@
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
<PackageReference Include="GraphQL.NewtonsoftJson" Version="8.2.1" />
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
<PackageReference Include="ProtoBufJsonConverter" Version="0.6.0-preview-01" />
<PackageReference Include="ProtoBufJsonConverter" Version="0.6.0-preview-03" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Copyright © WireMock.Net

using System;
using System.Diagnostics.CodeAnalysis;
using Xunit;

namespace WireMock.Net.Tests.Facts;

[ExcludeFromCodeCoverage]
public sealed class IgnoreOnContinuousIntegrationFact : FactAttribute
{
private const string SkipReason = "Ignore when run via CI/CD";
Expand Down
2 changes: 2 additions & 0 deletions test/WireMock.Net.Tests/Facts/RunOnDockerPlatformFact.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// Copyright © WireMock.Net
#if NET6_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using WireMock.Net.Testcontainers.Utils;
using Xunit;

namespace WireMock.Net.Tests.Facts;

[ExcludeFromCodeCoverage]
public sealed class RunOnDockerPlatformFact : FactAttribute
{
public RunOnDockerPlatformFact(string platform)
Expand Down
121 changes: 117 additions & 4 deletions test/WireMock.Net.Tests/Grpc/WireMockServerTests.Grpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Net.Http.Headers;
using System.Threading.Tasks;
using FluentAssertions;
using Google.Protobuf.WellKnownTypes;
using Greet;
using Grpc.Net.Client;
using WireMock.Matchers;
Expand All @@ -17,6 +18,7 @@

// ReSharper disable once CheckNamespace
namespace WireMock.Net.Tests;

public partial class WireMockServerTests
{
private const string ProtoDefinition = @"
Expand Down Expand Up @@ -183,7 +185,6 @@ public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes_Empty()
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc/Greeter/SayNothing")
.WithBody(new NotNullOrEmptyMatcher())
)
.RespondWith(Response.Create()
.WithBodyAsProtoBuf(ProtoDefinitionWithWellKnownTypes, "google.protobuf.Empty",
Expand All @@ -205,7 +206,7 @@ public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes_Empty()
response.StatusCode.Should().Be(HttpStatusCode.OK);
var responseBytes = await response.Content.ReadAsByteArrayAsync();

Convert.ToBase64String(responseBytes).Should().Be("");
Convert.ToBase64String(responseBytes).Should().Be("AAAAAAA=");
}

[Fact]
Expand Down Expand Up @@ -307,7 +308,6 @@ public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinition_WithWe
.Given(Request.Create()
.UsingPost()
.WithPath("/grpc/Greeter/SayNothing")
.WithBody(new NotNullOrEmptyMatcher())
)
.WithProtoDefinition(id)
.RespondWith(Response.Create()
Expand All @@ -329,7 +329,7 @@ public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinition_WithWe
response.StatusCode.Should().Be(HttpStatusCode.OK);
var responseBytes = await response.Content.ReadAsByteArrayAsync();

Convert.ToBase64String(responseBytes).Should().Be("");
Convert.ToBase64String(responseBytes).Should().Be("AAAAAAA=");
}

[Fact]
Expand Down Expand Up @@ -487,5 +487,118 @@ public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinition_UsingG
// Assert
reply.Message.Should().Be("hello stef POST");
}

[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes_Empty_UsingGrpcGeneratedClient()
{
// Arrange
var definition = await System.IO.File.ReadAllTextAsync("./Grpc/greet.proto");

using var server = WireMockServer.Start(useHttp2: true);

server
.Given(Request.Create()
.UsingPost()
.WithPath("/greet.Greeter/SayNothing")
)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf(definition, "google.protobuf.Empty",
new { }
)
);

// Act
var channel = GrpcChannel.ForAddress(server.Url!);
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayNothingAsync(new Empty());

// Assert
reply.Should().Be(new Empty());
}

[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes_Timestamp_UsingGrpcGeneratedClient()
{
// Arrange
const int seconds = 1722301323;
const int nanos = 12300;
var definition = await System.IO.File.ReadAllTextAsync("./Grpc/greet.proto");

using var server = WireMockServer.Start(useHttp2: true);

server
.Given(Request.Create()
.UsingPost()
.WithPath("/greet.Greeter/SayTimestamp")
.WithBody(new NotNullOrEmptyMatcher())
)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf(definition, "greet.MyMessageTimestamp",
new
{
ts = new
{
seconds,
nanos
}
}
)
);

// Act
var channel = GrpcChannel.ForAddress(server.Url!);
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayTimestampAsync(new MyMessageTimestamp { Ts = Timestamp.FromDateTime(DateTime.UtcNow) });

// Assert
reply.Ts.Should().Be(new Timestamp { Seconds = seconds, Nanos = nanos });
}

[Fact]
public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes_Duration_UsingGrpcGeneratedClient()
{
// Arrange
const int seconds = 1722301323;
const int nanos = 12300;
var definition = await System.IO.File.ReadAllTextAsync("./Grpc/greet.proto");

using var server = WireMockServer.Start(useHttp2: true);

server
.Given(Request.Create()
.UsingPost()
.WithPath("/greet.Greeter/SayDuration")
.WithBody(new NotNullOrEmptyMatcher())
)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc")
.WithTrailingHeader("grpc-status", "0")
.WithBodyAsProtoBuf(definition, "greet.MyMessageDuration",
new
{
du = new
{
seconds,
nanos
}
}
)
);

// Act
var channel = GrpcChannel.ForAddress(server.Url!);
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayDurationAsync(new MyMessageDuration { Du = Duration.FromTimeSpan(TimeSpan.MinValue) });

// Assert
reply.Du.Should().Be(new Duration { Seconds = seconds, Nanos = nanos });
}
}
#endif
38 changes: 20 additions & 18 deletions test/WireMock.Net.Tests/Grpc/greet.proto
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package greet;

// The greeting service definition.
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";

service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
rpc SayEmpty (MyMessageEmpty) returns (MyMessageEmpty);
rpc SayNothing (google.protobuf.Empty) returns (google.protobuf.Empty);
rpc SayTimestamp (MyMessageTimestamp) returns (MyMessageTimestamp);
rpc SayDuration (MyMessageDuration) returns (MyMessageDuration);
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}

message MyMessageTimestamp {
google.protobuf.Timestamp ts = 1;
}

message MyMessageDuration {
google.protobuf.Duration du = 1;
}

message MyMessageEmpty {
google.protobuf.Empty e = 1;
}
3 changes: 2 additions & 1 deletion test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net461;netcoreapp3.1;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net452;net461;netcoreapp3.1;net6.0;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<DebugType>full</DebugType>
Expand Down Expand Up @@ -134,6 +134,7 @@
</None>
<None Update="Grpc\greet.proto">
<GrpcServices>Client</GrpcServices>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="responsebody.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
Loading

0 comments on commit 38d78fc

Please sign in to comment.