mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-19 15:31:39 +02:00
Grpc: Fix parsing null value for google.protobuf.Timestamp (#1293)
* Add another example for Grpc client + mapping * <PackageReference Include="ProtoBufJsonConverter" Version="0.9.0" />
This commit is contained in:
@@ -2,22 +2,42 @@
|
|||||||
|
|
||||||
using Greet;
|
using Greet;
|
||||||
using Grpc.Net.Client;
|
using Grpc.Net.Client;
|
||||||
|
using Policy2;
|
||||||
|
|
||||||
namespace WireMock.Net.Console.GrpcClient;
|
await TestPolicyAsync();
|
||||||
|
// await TestGreeterAsync();
|
||||||
|
return;
|
||||||
|
|
||||||
internal class Program
|
async Task TestGreeterAsync()
|
||||||
{
|
{
|
||||||
static async Task Main(string[] args)
|
var channel = GrpcChannel.ForAddress("http://localhost:9093/grpc3", new GrpcChannelOptions
|
||||||
{
|
{
|
||||||
var channel = GrpcChannel.ForAddress("http://localhost:9093/grpc3", new GrpcChannelOptions
|
Credentials = Grpc.Core.ChannelCredentials.Insecure
|
||||||
|
});
|
||||||
|
|
||||||
|
var client = new Greeter.GreeterClient(channel);
|
||||||
|
|
||||||
|
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
|
||||||
|
|
||||||
|
Console.WriteLine("Greeting: " + reply.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task TestPolicyAsync()
|
||||||
|
{
|
||||||
|
var channel = GrpcChannel.ForAddress("http://localhost:9093/grpc-policy", new GrpcChannelOptions
|
||||||
|
{
|
||||||
|
Credentials = Grpc.Core.ChannelCredentials.Insecure
|
||||||
|
});
|
||||||
|
|
||||||
|
var client = new PolicyService2.PolicyService2Client(channel);
|
||||||
|
|
||||||
|
var reply = await client.GetCancellationDetailAsync(new GetCancellationDetailRequest
|
||||||
|
{
|
||||||
|
Client = new Client
|
||||||
{
|
{
|
||||||
Credentials = Grpc.Core.ChannelCredentials.Insecure
|
CorrelationId = "abc"
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var client = new Greeter.GreeterClient(channel);
|
Console.WriteLine("PolicyService2:reply.CancellationName " + reply.CancellationName);
|
||||||
|
|
||||||
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
|
|
||||||
|
|
||||||
System.Console.WriteLine("Greeting: " + reply.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Protobuf Include="greet.proto" GrpcServices="Client" />
|
<Protobuf Include="greet.proto" GrpcServices="Client" />
|
||||||
|
<Protobuf Include="policy.proto" GrpcServices="Client" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
64
examples/WireMock.Net.Console.GrpcClient/policy.proto
Normal file
64
examples/WireMock.Net.Console.GrpcClient/policy.proto
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
// option csharp_namespace = "NarrowIntegrationTest.Lookup";
|
||||||
|
|
||||||
|
package Policy2;
|
||||||
|
|
||||||
|
service PolicyService2 {
|
||||||
|
rpc GetCancellationDetail (GetCancellationDetailRequest) returns (GetCancellationDetailResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetCancellationDetailRequest {
|
||||||
|
Client Client = 1;
|
||||||
|
LegacyPolicyKey LegacyPolicyKey = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetCancellationDetailResponse {
|
||||||
|
ResponseStatus Status = 1;
|
||||||
|
string CancellationCode = 2;
|
||||||
|
string CancellationName = 3;
|
||||||
|
string CancellationDescription = 4;
|
||||||
|
google.protobuf.Timestamp CancellationEffDate = 5;
|
||||||
|
string NonRenewalCode = 6;
|
||||||
|
string NonRenewalName = 7;
|
||||||
|
string NonRenewalDescription = 8;
|
||||||
|
google.protobuf.Timestamp NonRenewalEffDate = 9;
|
||||||
|
google.protobuf.Timestamp LastReinstatementDate = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LegacyPolicyKey {
|
||||||
|
string Group = 1;
|
||||||
|
int32 UnitNumber = 2;
|
||||||
|
int32 Year = 3;
|
||||||
|
string Suffix = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ResponseStatus {
|
||||||
|
bool HasErrors = 1;
|
||||||
|
bool HasWarnings = 2;
|
||||||
|
repeated string Errors = 3;
|
||||||
|
repeated string Warnings = 4;
|
||||||
|
string CorrelationId = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Clients ClientName = 2;
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
@@ -45,57 +44,129 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
|
|
||||||
public static class MainApp
|
public static class MainApp
|
||||||
{
|
{
|
||||||
private const string ProtoDefinition = @"
|
private const string ProtoDefinitionGreeter =
|
||||||
syntax = ""proto3"";
|
"""
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
package greet;
|
package greet;
|
||||||
|
|
||||||
service Greeter {
|
service Greeter {
|
||||||
rpc SayHello (HelloRequest) returns (HelloReply);
|
rpc SayHello (HelloRequest) returns (HelloReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
message HelloRequest {
|
message HelloRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HelloReply {
|
message HelloReply {
|
||||||
string message = 1;
|
string message = 1;
|
||||||
}
|
}
|
||||||
";
|
|
||||||
|
|
||||||
private const string TestSchema = @"
|
""";
|
||||||
scalar DateTime
|
|
||||||
scalar MyCustomScalar
|
|
||||||
|
|
||||||
input MessageInput {
|
private const string ProtoDefinitionPolicy =
|
||||||
content: String
|
"""
|
||||||
author: String
|
syntax = "proto3";
|
||||||
}
|
|
||||||
|
|
||||||
type Message {
|
import "google/protobuf/timestamp.proto";
|
||||||
id: ID!
|
|
||||||
content: String
|
|
||||||
author: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mutation {
|
// option csharp_namespace = "NarrowIntegrationTest.Lookup";
|
||||||
createMessage(input: MessageInput): Message
|
|
||||||
createAnotherMessage(x: MyCustomScalar, dt: DateTime): Message
|
|
||||||
updateMessage(id: ID!, input: MessageInput): Message
|
|
||||||
}
|
|
||||||
|
|
||||||
type Query {
|
package Policy2;
|
||||||
greeting:String
|
|
||||||
students:[Student]
|
|
||||||
studentById(id:ID!):Student
|
|
||||||
}
|
|
||||||
|
|
||||||
type Student {
|
service PolicyService2 {
|
||||||
id:ID!
|
rpc GetCancellationDetail (GetCancellationDetailRequest) returns (GetCancellationDetailResponse);
|
||||||
firstName:String
|
}
|
||||||
lastName:String
|
|
||||||
fullName:String
|
message GetCancellationDetailRequest {
|
||||||
}";
|
Client Client = 1;
|
||||||
|
LegacyPolicyKey LegacyPolicyKey = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetCancellationDetailResponse {
|
||||||
|
ResponseStatus Status = 1;
|
||||||
|
string CancellationCode = 2;
|
||||||
|
string CancellationName = 3;
|
||||||
|
string CancellationDescription = 4;
|
||||||
|
google.protobuf.Timestamp CancellationEffDate = 5;
|
||||||
|
string NonRenewalCode = 6;
|
||||||
|
string NonRenewalName = 7;
|
||||||
|
string NonRenewalDescription = 8;
|
||||||
|
google.protobuf.Timestamp NonRenewalEffDate = 9;
|
||||||
|
google.protobuf.Timestamp LastReinstatementDate = 10; // Always send the last reinstatement date if present on the policy term.
|
||||||
|
}
|
||||||
|
|
||||||
|
message LegacyPolicyKey {
|
||||||
|
string Group = 1;
|
||||||
|
int32 UnitNumber = 2;
|
||||||
|
int32 Year = 3;
|
||||||
|
string Suffix = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message ResponseStatus {
|
||||||
|
bool HasErrors = 1;
|
||||||
|
bool HasWarnings = 2;
|
||||||
|
repeated string Errors = 3;
|
||||||
|
repeated string Warnings = 4;
|
||||||
|
string CorrelationId = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Clients ClientName = 2;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private const string TestSchema =
|
||||||
|
"""
|
||||||
|
scalar DateTime
|
||||||
|
scalar MyCustomScalar
|
||||||
|
|
||||||
|
input MessageInput {
|
||||||
|
content: String
|
||||||
|
author: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type Message {
|
||||||
|
id: ID!
|
||||||
|
content: String
|
||||||
|
author: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
createMessage(input: MessageInput): Message
|
||||||
|
createAnotherMessage(x: MyCustomScalar, dt: DateTime): Message
|
||||||
|
updateMessage(id: ID!, input: MessageInput): Message
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query {
|
||||||
|
greeting:String
|
||||||
|
students:[Student]
|
||||||
|
studentById(id:ID!):Student
|
||||||
|
}
|
||||||
|
|
||||||
|
type Student {
|
||||||
|
id:ID!
|
||||||
|
firstName:String
|
||||||
|
lastName:String
|
||||||
|
fullName:String
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
private static void RunSse()
|
private static void RunSse()
|
||||||
{
|
{
|
||||||
@@ -282,11 +353,11 @@ message HelloReply {
|
|||||||
.UsingPost()
|
.UsingPost()
|
||||||
.WithHttpVersion("2")
|
.WithHttpVersion("2")
|
||||||
.WithPath("/grpc/greet.Greeter/SayHello")
|
.WithPath("/grpc/greet.Greeter/SayHello")
|
||||||
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", protoBufJsonMatcher)
|
.WithBodyAsProtoBuf(ProtoDefinitionGreeter, "greet.HelloRequest", protoBufJsonMatcher)
|
||||||
)
|
)
|
||||||
.RespondWith(Response.Create()
|
.RespondWith(Response.Create()
|
||||||
.WithHeader("Content-Type", "application/grpc")
|
.WithHeader("Content-Type", "application/grpc")
|
||||||
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply",
|
.WithBodyAsProtoBuf(ProtoDefinitionGreeter, "greet.HelloReply",
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
message = "hello {{request.BodyAsJson.name}}"
|
message = "hello {{request.BodyAsJson.name}}"
|
||||||
@@ -303,7 +374,7 @@ message HelloReply {
|
|||||||
.WithPath("/grpc2/greet.Greeter/SayHello")
|
.WithPath("/grpc2/greet.Greeter/SayHello")
|
||||||
.WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher)
|
.WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher)
|
||||||
)
|
)
|
||||||
.WithProtoDefinition(ProtoDefinition)
|
.WithProtoDefinition(ProtoDefinitionGreeter)
|
||||||
.RespondWith(Response.Create()
|
.RespondWith(Response.Create()
|
||||||
.WithHeader("Content-Type", "application/grpc")
|
.WithHeader("Content-Type", "application/grpc")
|
||||||
.WithBodyAsProtoBuf("greet.HelloReply",
|
.WithBodyAsProtoBuf("greet.HelloReply",
|
||||||
@@ -317,7 +388,7 @@ message HelloReply {
|
|||||||
);
|
);
|
||||||
|
|
||||||
server
|
server
|
||||||
.AddProtoDefinition("my-greeter", ProtoDefinition)
|
.AddProtoDefinition("my-greeter", ProtoDefinitionGreeter)
|
||||||
.Given(Request.Create()
|
.Given(Request.Create()
|
||||||
.UsingPost()
|
.UsingPost()
|
||||||
.WithPath("/grpc3/greet.Greeter/SayHello")
|
.WithPath("/grpc3/greet.Greeter/SayHello")
|
||||||
@@ -335,6 +406,25 @@ message HelloReply {
|
|||||||
.WithTrailingHeader("grpc-status", "0")
|
.WithTrailingHeader("grpc-status", "0")
|
||||||
.WithTransformer()
|
.WithTransformer()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var protoBufJsonMatcherForGetCancellationDetailRequest = new JsonPartialWildcardMatcher("{\"Client\":{\"CorrelationId\":\"*\"}}", false, true);
|
||||||
|
var getCancellationDetailResponseAsJsonObject = JsonConvert.DeserializeObject(
|
||||||
|
"""{"Status":{"HasErrors":false,"HasWarnings":false,"Errors":[],"Warnings":[],"CorrelationId":"b8ad0d04-ed2f-42e1-ac85-339d91dc9855"},"CancellationCode":"cc123","CancellationName":"cn123","CancellationDescription":"","CancellationEffDate":null,"NonRenewalCode":"","NonRenewalName":"","NonRenewalDescription":"","NonRenewalEffDate":null,"LastReinstatementDate":null}"""
|
||||||
|
)!;
|
||||||
|
server
|
||||||
|
.AddProtoDefinition("grpc-policy", ProtoDefinitionPolicy)
|
||||||
|
.Given(Request.Create()
|
||||||
|
.UsingPost()
|
||||||
|
.WithPath("/Policy2.PolicyService2/GetCancellationDetail")
|
||||||
|
.WithBodyAsProtoBuf("Policy2.GetCancellationDetailRequest", protoBufJsonMatcherForGetCancellationDetailRequest)
|
||||||
|
)
|
||||||
|
.WithProtoDefinition("grpc-policy")
|
||||||
|
.RespondWith(Response.Create()
|
||||||
|
.WithHeader("Content-Type", "application/grpc")
|
||||||
|
.WithBodyAsProtoBuf("Policy2.GetCancellationDetailResponse", getCancellationDetailResponseAsJsonObject)
|
||||||
|
.WithTrailingHeader("grpc-status", "0")
|
||||||
|
.WithTransformer()
|
||||||
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
@@ -596,9 +686,9 @@ message HelloReply {
|
|||||||
.WithHeader("Content-Type", "application/json")
|
.WithHeader("Content-Type", "application/json")
|
||||||
.WithBodyAsJson(new { result = "data:headers posted with 201" }));
|
.WithBodyAsJson(new { result = "data:headers posted with 201" }));
|
||||||
|
|
||||||
if (!System.IO.File.Exists(@"c:\temp\x.json"))
|
if (!File.Exists(@"c:\temp\x.json"))
|
||||||
{
|
{
|
||||||
System.IO.File.WriteAllText(@"c:\temp\x.json", "{ \"hello\": \"world\", \"answer\": 42 }");
|
File.WriteAllText(@"c:\temp\x.json", "{ \"hello\": \"world\", \"answer\": 42 }");
|
||||||
}
|
}
|
||||||
|
|
||||||
server
|
server
|
||||||
@@ -925,7 +1015,7 @@ message HelloReply {
|
|||||||
BodyData = new BodyData
|
BodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsString = "random200or505:" + code + ", HeadersFromRequest = " + string.Join(",", request.Headers),
|
BodyAsString = "random200or505:" + code + ", HeadersFromRequest = " + string.Join(",", request.Headers),
|
||||||
DetectedBodyType = Types.BodyType.String,
|
DetectedBodyType = BodyType.String,
|
||||||
},
|
},
|
||||||
StatusCode = code
|
StatusCode = code
|
||||||
};
|
};
|
||||||
@@ -941,7 +1031,7 @@ message HelloReply {
|
|||||||
|
|
||||||
return new ResponseMessage
|
return new ResponseMessage
|
||||||
{
|
{
|
||||||
BodyData = new BodyData { BodyAsString = "random200or505async:" + code, DetectedBodyType = Types.BodyType.String },
|
BodyData = new BodyData { BodyAsString = "random200or505async:" + code, DetectedBodyType = BodyType.String },
|
||||||
StatusCode = code
|
StatusCode = code
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -150,7 +150,7 @@
|
|||||||
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
<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="GraphQL.NewtonsoftJson" Version="8.2.1" />
|
||||||
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
|
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
|
||||||
<PackageReference Include="ProtoBufJsonConverter" Version="0.8.0" />
|
<PackageReference Include="ProtoBufJsonConverter" Version="0.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
||||||
|
|||||||
Reference in New Issue
Block a user