mirror of https://github.com/grpc/grpc.git
Merge pull request #423 from jtattermusch/interop_testing
Adding interop client for C#pull/436/head
commit
d2785749f8
21 changed files with 3971 additions and 51 deletions
@ -0,0 +1,282 @@ |
||||
// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT! |
||||
#pragma warning disable 1591, 0612, 3021 |
||||
#region Designer generated code |
||||
|
||||
using pb = global::Google.ProtocolBuffers; |
||||
using pbc = global::Google.ProtocolBuffers.Collections; |
||||
using pbd = global::Google.ProtocolBuffers.Descriptors; |
||||
using scg = global::System.Collections.Generic; |
||||
namespace grpc.testing { |
||||
|
||||
namespace Proto { |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public static partial class Empty { |
||||
|
||||
#region Extension registration |
||||
public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { |
||||
} |
||||
#endregion |
||||
#region Static variables |
||||
internal static pbd::MessageDescriptor internal__static_grpc_testing_Empty__Descriptor; |
||||
internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Empty, global::grpc.testing.Empty.Builder> internal__static_grpc_testing_Empty__FieldAccessorTable; |
||||
#endregion |
||||
#region Descriptor |
||||
public static pbd::FileDescriptor Descriptor { |
||||
get { return descriptor; } |
||||
} |
||||
private static pbd::FileDescriptor descriptor; |
||||
|
||||
static Empty() { |
||||
byte[] descriptorData = global::System.Convert.FromBase64String( |
||||
string.Concat( |
||||
"CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5")); |
||||
pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { |
||||
descriptor = root; |
||||
internal__static_grpc_testing_Empty__Descriptor = Descriptor.MessageTypes[0]; |
||||
internal__static_grpc_testing_Empty__FieldAccessorTable = |
||||
new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Empty, global::grpc.testing.Empty.Builder>(internal__static_grpc_testing_Empty__Descriptor, |
||||
new string[] { }); |
||||
return null; |
||||
}; |
||||
pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, |
||||
new pbd::FileDescriptor[] { |
||||
}, assigner); |
||||
} |
||||
#endregion |
||||
|
||||
} |
||||
} |
||||
#region Messages |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class Empty : pb::GeneratedMessage<Empty, Empty.Builder> { |
||||
private Empty() { } |
||||
private static readonly Empty defaultInstance = new Empty().MakeReadOnly(); |
||||
private static readonly string[] _emptyFieldNames = new string[] { }; |
||||
private static readonly uint[] _emptyFieldTags = new uint[] { }; |
||||
public static Empty DefaultInstance { |
||||
get { return defaultInstance; } |
||||
} |
||||
|
||||
public override Empty DefaultInstanceForType { |
||||
get { return DefaultInstance; } |
||||
} |
||||
|
||||
protected override Empty ThisMessage { |
||||
get { return this; } |
||||
} |
||||
|
||||
public static pbd::MessageDescriptor Descriptor { |
||||
get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__Descriptor; } |
||||
} |
||||
|
||||
protected override pb::FieldAccess.FieldAccessorTable<Empty, Empty.Builder> InternalFieldAccessors { |
||||
get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__FieldAccessorTable; } |
||||
} |
||||
|
||||
public override bool IsInitialized { |
||||
get { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
public override void WriteTo(pb::ICodedOutputStream output) { |
||||
int size = SerializedSize; |
||||
string[] field_names = _emptyFieldNames; |
||||
UnknownFields.WriteTo(output); |
||||
} |
||||
|
||||
private int memoizedSerializedSize = -1; |
||||
public override int SerializedSize { |
||||
get { |
||||
int size = memoizedSerializedSize; |
||||
if (size != -1) return size; |
||||
|
||||
size = 0; |
||||
size += UnknownFields.SerializedSize; |
||||
memoizedSerializedSize = size; |
||||
return size; |
||||
} |
||||
} |
||||
|
||||
public static Empty ParseFrom(pb::ByteString data) { |
||||
return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { |
||||
return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(byte[] data) { |
||||
return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { |
||||
return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(global::System.IO.Stream input) { |
||||
return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { |
||||
return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); |
||||
} |
||||
public static Empty ParseDelimitedFrom(global::System.IO.Stream input) { |
||||
return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); |
||||
} |
||||
public static Empty ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { |
||||
return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(pb::ICodedInputStream input) { |
||||
return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); |
||||
} |
||||
public static Empty ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { |
||||
return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); |
||||
} |
||||
private Empty MakeReadOnly() { |
||||
return this; |
||||
} |
||||
|
||||
public static Builder CreateBuilder() { return new Builder(); } |
||||
public override Builder ToBuilder() { return CreateBuilder(this); } |
||||
public override Builder CreateBuilderForType() { return new Builder(); } |
||||
public static Builder CreateBuilder(Empty prototype) { |
||||
return new Builder(prototype); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||
public sealed partial class Builder : pb::GeneratedBuilder<Empty, Builder> { |
||||
protected override Builder ThisBuilder { |
||||
get { return this; } |
||||
} |
||||
public Builder() { |
||||
result = DefaultInstance; |
||||
resultIsReadOnly = true; |
||||
} |
||||
internal Builder(Empty cloneFrom) { |
||||
result = cloneFrom; |
||||
resultIsReadOnly = true; |
||||
} |
||||
|
||||
private bool resultIsReadOnly; |
||||
private Empty result; |
||||
|
||||
private Empty PrepareBuilder() { |
||||
if (resultIsReadOnly) { |
||||
Empty original = result; |
||||
result = new Empty(); |
||||
resultIsReadOnly = false; |
||||
MergeFrom(original); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public override bool IsInitialized { |
||||
get { return result.IsInitialized; } |
||||
} |
||||
|
||||
protected override Empty MessageBeingBuilt { |
||||
get { return PrepareBuilder(); } |
||||
} |
||||
|
||||
public override Builder Clear() { |
||||
result = DefaultInstance; |
||||
resultIsReadOnly = true; |
||||
return this; |
||||
} |
||||
|
||||
public override Builder Clone() { |
||||
if (resultIsReadOnly) { |
||||
return new Builder(result); |
||||
} else { |
||||
return new Builder().MergeFrom(result); |
||||
} |
||||
} |
||||
|
||||
public override pbd::MessageDescriptor DescriptorForType { |
||||
get { return global::grpc.testing.Empty.Descriptor; } |
||||
} |
||||
|
||||
public override Empty DefaultInstanceForType { |
||||
get { return global::grpc.testing.Empty.DefaultInstance; } |
||||
} |
||||
|
||||
public override Empty BuildPartial() { |
||||
if (resultIsReadOnly) { |
||||
return result; |
||||
} |
||||
resultIsReadOnly = true; |
||||
return result.MakeReadOnly(); |
||||
} |
||||
|
||||
public override Builder MergeFrom(pb::IMessage other) { |
||||
if (other is Empty) { |
||||
return MergeFrom((Empty) other); |
||||
} else { |
||||
base.MergeFrom(other); |
||||
return this; |
||||
} |
||||
} |
||||
|
||||
public override Builder MergeFrom(Empty other) { |
||||
if (other == global::grpc.testing.Empty.DefaultInstance) return this; |
||||
PrepareBuilder(); |
||||
this.MergeUnknownFields(other.UnknownFields); |
||||
return this; |
||||
} |
||||
|
||||
public override Builder MergeFrom(pb::ICodedInputStream input) { |
||||
return MergeFrom(input, pb::ExtensionRegistry.Empty); |
||||
} |
||||
|
||||
public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { |
||||
PrepareBuilder(); |
||||
pb::UnknownFieldSet.Builder unknownFields = null; |
||||
uint tag; |
||||
string field_name; |
||||
while (input.ReadTag(out tag, out field_name)) { |
||||
if(tag == 0 && field_name != null) { |
||||
int field_ordinal = global::System.Array.BinarySearch(_emptyFieldNames, field_name, global::System.StringComparer.Ordinal); |
||||
if(field_ordinal >= 0) |
||||
tag = _emptyFieldTags[field_ordinal]; |
||||
else { |
||||
if (unknownFields == null) { |
||||
unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); |
||||
} |
||||
ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); |
||||
continue; |
||||
} |
||||
} |
||||
switch (tag) { |
||||
case 0: { |
||||
throw pb::InvalidProtocolBufferException.InvalidTag(); |
||||
} |
||||
default: { |
||||
if (pb::WireFormat.IsEndGroupTag(tag)) { |
||||
if (unknownFields != null) { |
||||
this.UnknownFields = unknownFields.Build(); |
||||
} |
||||
return this; |
||||
} |
||||
if (unknownFields == null) { |
||||
unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); |
||||
} |
||||
ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (unknownFields != null) { |
||||
this.UnknownFields = unknownFields.Build(); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
} |
||||
static Empty() { |
||||
object.ReferenceEquals(global::grpc.testing.Proto.Empty.Descriptor, null); |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
|
||||
#endregion Designer generated code |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,170 @@ |
||||
using System; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using System.Collections.Generic; |
||||
using System.Reactive.Linq; |
||||
using Google.GRPC.Core; |
||||
|
||||
namespace grpc.testing |
||||
{ |
||||
/// <summary> |
||||
/// TestService (this is handwritten version of code that will normally be generated). |
||||
/// </summary> |
||||
public class TestServiceGrpc |
||||
{ |
||||
readonly static Marshaller<Empty> emptyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Empty.ParseFrom); |
||||
readonly static Marshaller<SimpleRequest> simpleRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleRequest.ParseFrom); |
||||
readonly static Marshaller<SimpleResponse> simpleResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleResponse.ParseFrom); |
||||
readonly static Marshaller<StreamingOutputCallRequest> streamingOutputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallRequest.ParseFrom); |
||||
readonly static Marshaller<StreamingOutputCallResponse> streamingOutputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallResponse.ParseFrom); |
||||
readonly static Marshaller<StreamingInputCallRequest> streamingInputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallRequest.ParseFrom); |
||||
readonly static Marshaller<StreamingInputCallResponse> streamingInputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallResponse.ParseFrom); |
||||
|
||||
readonly static Method<Empty, Empty> emptyCallMethod = new Method<Empty, Empty>( |
||||
MethodType.Unary, |
||||
"/grpc.testing.TestService/EmptyCall", |
||||
emptyMarshaller, |
||||
emptyMarshaller |
||||
); |
||||
readonly static Method<SimpleRequest, SimpleResponse> unaryCallMethod = new Method<SimpleRequest, SimpleResponse>( |
||||
MethodType.Unary, |
||||
"/grpc.testing.TestService/UnaryCall", |
||||
simpleRequestMarshaller, |
||||
simpleResponseMarshaller |
||||
); |
||||
readonly static Method<StreamingOutputCallRequest, StreamingOutputCallResponse> streamingOutputCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>( |
||||
MethodType.ServerStreaming, |
||||
"/grpc.testing.TestService/StreamingOutputCall", |
||||
streamingOutputCallRequestMarshaller, |
||||
streamingOutputCallResponseMarshaller |
||||
); |
||||
readonly static Method<StreamingInputCallRequest, StreamingInputCallResponse> streamingInputCallMethod = new Method<StreamingInputCallRequest, StreamingInputCallResponse>( |
||||
MethodType.ClientStreaming, |
||||
"/grpc.testing.TestService/StreamingInputCall", |
||||
streamingInputCallRequestMarshaller, |
||||
streamingInputCallResponseMarshaller |
||||
); |
||||
readonly static Method<StreamingOutputCallRequest, StreamingOutputCallResponse> fullDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>( |
||||
MethodType.DuplexStreaming, |
||||
"/grpc.testing.TestService/FullDuplexCall", |
||||
streamingOutputCallRequestMarshaller, |
||||
streamingOutputCallResponseMarshaller |
||||
); |
||||
readonly static Method<StreamingOutputCallRequest, StreamingOutputCallResponse> halfDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>( |
||||
MethodType.DuplexStreaming, |
||||
"/grpc.testing.TestService/HalfDuplexCall", |
||||
streamingOutputCallRequestMarshaller, |
||||
streamingOutputCallResponseMarshaller |
||||
); |
||||
|
||||
public interface ITestServiceClient |
||||
{ |
||||
Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken)); |
||||
|
||||
Task<Empty> EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken)); |
||||
|
||||
SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken)); |
||||
|
||||
Task<SimpleResponse> UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken)); |
||||
|
||||
Task StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)); |
||||
|
||||
ClientStreamingAsyncResult<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken)); |
||||
|
||||
IObserver<StreamingOutputCallRequest> FullDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)); |
||||
|
||||
IObserver<StreamingOutputCallRequest> HalfDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)); |
||||
} |
||||
|
||||
public class TestServiceClientStub : ITestServiceClient |
||||
{ |
||||
readonly Channel channel; |
||||
|
||||
public TestServiceClientStub(Channel channel) |
||||
{ |
||||
this.channel = channel; |
||||
} |
||||
|
||||
public Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<Empty, Empty>(emptyCallMethod, channel); |
||||
return Calls.BlockingUnaryCall(call, request, token); |
||||
} |
||||
|
||||
public Task<Empty> EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<Empty, Empty>(emptyCallMethod, channel); |
||||
return Calls.AsyncUnaryCall(call, request, token); |
||||
} |
||||
|
||||
public SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<SimpleRequest, SimpleResponse>(unaryCallMethod, channel); |
||||
return Calls.BlockingUnaryCall(call, request, token); |
||||
} |
||||
|
||||
public Task<SimpleResponse> UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<SimpleRequest, SimpleResponse>(unaryCallMethod, channel); |
||||
return Calls.AsyncUnaryCall(call, request, token); |
||||
} |
||||
|
||||
public Task StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)) { |
||||
var call = new Google.GRPC.Core.Call<StreamingOutputCallRequest, StreamingOutputCallResponse>(streamingOutputCallMethod, channel); |
||||
return Calls.AsyncServerStreamingCall(call, request, responseObserver, token); |
||||
} |
||||
|
||||
public ClientStreamingAsyncResult<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<StreamingInputCallRequest, StreamingInputCallResponse>(streamingInputCallMethod, channel); |
||||
return Calls.AsyncClientStreamingCall(call, token); |
||||
} |
||||
|
||||
public IObserver<StreamingOutputCallRequest> FullDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<StreamingOutputCallRequest, StreamingOutputCallResponse>(fullDuplexCallMethod, channel); |
||||
return Calls.DuplexStreamingCall(call, responseObserver, token); |
||||
} |
||||
|
||||
|
||||
public IObserver<StreamingOutputCallRequest> HalfDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)) |
||||
{ |
||||
var call = new Google.GRPC.Core.Call<StreamingOutputCallRequest, StreamingOutputCallResponse>(halfDuplexCallMethod, channel); |
||||
return Calls.DuplexStreamingCall(call, responseObserver, token); |
||||
} |
||||
} |
||||
|
||||
// server-side interface |
||||
public interface ITestService |
||||
{ |
||||
void EmptyCall(Empty request, IObserver<Empty> responseObserver); |
||||
|
||||
void UnaryCall(SimpleRequest request, IObserver<SimpleResponse> responseObserver); |
||||
|
||||
void StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver); |
||||
|
||||
IObserver<StreamingInputCallRequest> StreamingInputCall(IObserver<StreamingInputCallResponse> responseObserver); |
||||
|
||||
IObserver<StreamingOutputCallRequest> FullDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver); |
||||
|
||||
IObserver<StreamingOutputCallRequest> HalfDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver); |
||||
} |
||||
|
||||
public static ServerServiceDefinition BindService(ITestService serviceImpl) |
||||
{ |
||||
return ServerServiceDefinition.CreateBuilder("/grpc.testing.TestService/") |
||||
.AddMethod(emptyCallMethod, serviceImpl.EmptyCall) |
||||
.AddMethod(unaryCallMethod, serviceImpl.UnaryCall) |
||||
.AddMethod(streamingOutputCallMethod, serviceImpl.StreamingOutputCall) |
||||
.AddMethod(streamingInputCallMethod, serviceImpl.StreamingInputCall) |
||||
.AddMethod(fullDuplexCallMethod, serviceImpl.FullDuplexCall) |
||||
.AddMethod(halfDuplexCallMethod, serviceImpl.HalfDuplexCall) |
||||
.Build(); |
||||
} |
||||
|
||||
public static ITestServiceClient NewStub(Channel channel) |
||||
{ |
||||
return new TestServiceClientStub(channel); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
syntax = "proto2"; |
||||
|
||||
package grpc.testing; |
||||
|
||||
// An empty message that you can re-use to avoid defining duplicated empty |
||||
// messages in your project. A typical example is to use it as argument or the |
||||
// return value of a service API. For instance: |
||||
// |
||||
// service Foo { |
||||
// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; |
||||
// }; |
||||
// |
||||
message Empty {} |
@ -0,0 +1,102 @@ |
||||
// Message definitions to be used by integration test service definitions. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
package grpc.testing; |
||||
|
||||
// The type of payload that should be returned. |
||||
enum PayloadType { |
||||
// Compressable text format. |
||||
COMPRESSABLE = 0; |
||||
|
||||
// Uncompressable binary format. |
||||
UNCOMPRESSABLE = 1; |
||||
|
||||
// Randomly chosen from all other formats defined in this enum. |
||||
RANDOM = 2; |
||||
} |
||||
|
||||
// A block of data, to simply increase gRPC message size. |
||||
message Payload { |
||||
// The type of data in body. |
||||
optional PayloadType type = 1; |
||||
// Primary contents of payload. |
||||
optional bytes body = 2; |
||||
} |
||||
|
||||
// Unary request. |
||||
message SimpleRequest { |
||||
// Desired payload type in the response from the server. |
||||
// If response_type is RANDOM, server randomly chooses one from other formats. |
||||
optional PayloadType response_type = 1; |
||||
|
||||
// Desired payload size in the response from the server. |
||||
// If response_type is COMPRESSABLE, this denotes the size before compression. |
||||
optional int32 response_size = 2; |
||||
|
||||
// Optional input payload sent along with the request. |
||||
optional Payload payload = 3; |
||||
|
||||
// Whether SimpleResponse should include username. |
||||
optional bool fill_username = 4; |
||||
|
||||
// Whether SimpleResponse should include OAuth scope. |
||||
optional bool fill_oauth_scope = 5; |
||||
} |
||||
|
||||
// Unary response, as configured by the request. |
||||
message SimpleResponse { |
||||
// Payload to increase message size. |
||||
optional Payload payload = 1; |
||||
// The user the request came from, for verifying authentication was |
||||
// successful when the client expected it. |
||||
optional string username = 2; |
||||
// OAuth scope. |
||||
optional string oauth_scope = 3; |
||||
} |
||||
|
||||
// Client-streaming request. |
||||
message StreamingInputCallRequest { |
||||
// Optional input payload sent along with the request. |
||||
optional Payload payload = 1; |
||||
|
||||
// Not expecting any payload from the response. |
||||
} |
||||
|
||||
// Client-streaming response. |
||||
message StreamingInputCallResponse { |
||||
// Aggregated size of payloads received from the client. |
||||
optional int32 aggregated_payload_size = 1; |
||||
} |
||||
|
||||
// Configuration for a particular response. |
||||
message ResponseParameters { |
||||
// Desired payload sizes in responses from the server. |
||||
// If response_type is COMPRESSABLE, this denotes the size before compression. |
||||
optional int32 size = 1; |
||||
|
||||
// Desired interval between consecutive responses in the response stream in |
||||
// microseconds. |
||||
optional int32 interval_us = 2; |
||||
} |
||||
|
||||
// Server-streaming request. |
||||
message StreamingOutputCallRequest { |
||||
// Desired payload type in the response from the server. |
||||
// If response_type is RANDOM, the payload from each response in the stream |
||||
// might be of different types. This is to simulate a mixed type of payload |
||||
// stream. |
||||
optional PayloadType response_type = 1; |
||||
|
||||
// Configuration for each expected response message. |
||||
repeated ResponseParameters response_parameters = 2; |
||||
|
||||
// Optional input payload sent along with the request. |
||||
optional Payload payload = 3; |
||||
} |
||||
|
||||
// Server-streaming response, as configured by the request and parameters. |
||||
message StreamingOutputCallResponse { |
||||
// Payload to increase response size. |
||||
optional Payload payload = 1; |
||||
} |
@ -0,0 +1,42 @@ |
||||
// An integration test service that covers all the method signature permutations |
||||
// of unary/streaming requests/responses. |
||||
syntax = "proto2"; |
||||
|
||||
import "empty.proto"; |
||||
import "messages.proto"; |
||||
|
||||
package grpc.testing; |
||||
|
||||
// A simple service to test the various types of RPCs and experiment with |
||||
// performance with various types of payload. |
||||
service TestService { |
||||
// One empty request followed by one empty response. |
||||
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); |
||||
|
||||
// One request followed by one response. |
||||
// The server returns the client payload as-is. |
||||
rpc UnaryCall(SimpleRequest) returns (SimpleResponse); |
||||
|
||||
// One request followed by a sequence of responses (streamed download). |
||||
// The server returns the payload with client desired type and sizes. |
||||
rpc StreamingOutputCall(StreamingOutputCallRequest) |
||||
returns (stream StreamingOutputCallResponse); |
||||
|
||||
// A sequence of requests followed by one response (streamed upload). |
||||
// The server returns the aggregated size of client payload as the result. |
||||
rpc StreamingInputCall(stream StreamingInputCallRequest) |
||||
returns (StreamingInputCallResponse); |
||||
|
||||
// A sequence of requests with each request served by the server immediately. |
||||
// As one request could lead to multiple responses, this interface |
||||
// demonstrates the idea of full duplexing. |
||||
rpc FullDuplexCall(stream StreamingOutputCallRequest) |
||||
returns (stream StreamingOutputCallResponse); |
||||
|
||||
// A sequence of requests followed by a sequence of responses. |
||||
// The server buffers all the client requests and then serves them in order. A |
||||
// stream of responses are returned to the client when the server starts with |
||||
// first request. |
||||
rpc HalfDuplexCall(stream StreamingOutputCallRequest) |
||||
returns (stream StreamingOutputCallResponse); |
||||
} |
@ -0,0 +1,50 @@ |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using System.Collections.Generic; |
||||
using System.Collections.Concurrent; |
||||
|
||||
namespace Google.GRPC.Core.Utils |
||||
{ |
||||
/// <summary> |
||||
/// Observer that allows us to await incoming messages one-by-one. |
||||
/// The implementation is not ideal and class will be probably replaced |
||||
/// by something more versatile in the future. |
||||
/// </summary> |
||||
public class RecordingQueue<T> : IObserver<T> |
||||
{ |
||||
readonly BlockingCollection<T> queue = new BlockingCollection<T>(); |
||||
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); |
||||
|
||||
public void OnCompleted() |
||||
{ |
||||
tcs.SetResult(null); |
||||
} |
||||
|
||||
public void OnError(Exception error) |
||||
{ |
||||
tcs.SetException(error); |
||||
} |
||||
|
||||
public void OnNext(T value) |
||||
{ |
||||
queue.Add(value); |
||||
} |
||||
|
||||
public BlockingCollection<T> Queue |
||||
{ |
||||
get |
||||
{ |
||||
return queue; |
||||
} |
||||
} |
||||
|
||||
public Task Finished |
||||
{ |
||||
get |
||||
{ |
||||
return tcs.Task; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,303 @@ |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using NUnit.Framework; |
||||
using System.Text.RegularExpressions; |
||||
using Google.GRPC.Core; |
||||
using Google.GRPC.Core.Utils; |
||||
using Google.ProtocolBuffers; |
||||
using grpc.testing; |
||||
|
||||
namespace Google.GRPC.Interop |
||||
{ |
||||
class Client |
||||
{ |
||||
private class ClientOptions |
||||
{ |
||||
public bool help; |
||||
public string serverHost; |
||||
public string serverHostOverride; |
||||
public int? serverPort; |
||||
public string testCase; |
||||
public bool useTls; |
||||
public bool useTestCa; |
||||
} |
||||
|
||||
ClientOptions options; |
||||
|
||||
private Client(ClientOptions options) |
||||
{ |
||||
this.options = options; |
||||
} |
||||
|
||||
public static void Main(string[] args) |
||||
{ |
||||
Console.WriteLine("gRPC C# interop testing client"); |
||||
ClientOptions options = ParseArguments(args); |
||||
|
||||
if (options.serverHost == null || !options.serverPort.HasValue || options.testCase == null) |
||||
{ |
||||
Console.WriteLine("Missing required argument."); |
||||
Console.WriteLine(); |
||||
options.help = true; |
||||
} |
||||
|
||||
if (options.help) |
||||
{ |
||||
Console.WriteLine("Usage:"); |
||||
Console.WriteLine(" --server_host=HOSTNAME"); |
||||
Console.WriteLine(" --server_host_override=HOSTNAME"); |
||||
Console.WriteLine(" --server_port=PORT"); |
||||
Console.WriteLine(" --test_case=TESTCASE"); |
||||
Console.WriteLine(" --use_tls=BOOLEAN"); |
||||
Console.WriteLine(" --use_test_ca=BOOLEAN"); |
||||
Console.WriteLine(); |
||||
Environment.Exit(1); |
||||
} |
||||
|
||||
var interopClient = new Client(options); |
||||
interopClient.Run(); |
||||
} |
||||
|
||||
private void Run() |
||||
{ |
||||
string addr = string.Format("{0}:{1}", options.serverHost, options.serverPort); |
||||
using (Channel channel = new Channel(addr)) |
||||
{ |
||||
TestServiceGrpc.ITestServiceClient client = new TestServiceGrpc.TestServiceClientStub(channel); |
||||
|
||||
RunTestCase(options.testCase, client); |
||||
} |
||||
|
||||
GrpcEnvironment.Shutdown(); |
||||
} |
||||
|
||||
private void RunTestCase(string testCase, TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
switch (testCase) |
||||
{ |
||||
case "empty_unary": |
||||
RunEmptyUnary(client); |
||||
break; |
||||
case "large_unary": |
||||
RunLargeUnary(client); |
||||
break; |
||||
case "client_streaming": |
||||
RunClientStreaming(client); |
||||
break; |
||||
case "server_streaming": |
||||
RunServerStreaming(client); |
||||
break; |
||||
case "ping_pong": |
||||
RunPingPong(client); |
||||
break; |
||||
case "empty_stream": |
||||
RunEmptyStream(client); |
||||
break; |
||||
default: |
||||
throw new ArgumentException("Unknown test case " + testCase); |
||||
} |
||||
} |
||||
|
||||
private void RunEmptyUnary(TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
Console.WriteLine("running empty_unary"); |
||||
var response = client.EmptyCall(Empty.DefaultInstance); |
||||
Assert.IsNotNull(response); |
||||
Console.WriteLine("Passed!"); |
||||
} |
||||
|
||||
private void RunLargeUnary(TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
Console.WriteLine("running large_unary"); |
||||
var request = SimpleRequest.CreateBuilder() |
||||
.SetResponseType(PayloadType.COMPRESSABLE) |
||||
.SetResponseSize(314159) |
||||
.SetPayload(CreateZerosPayload(271828)) |
||||
.Build(); |
||||
|
||||
var response = client.UnaryCall(request); |
||||
|
||||
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
||||
Assert.AreEqual(314159, response.Payload.Body.Length); |
||||
Console.WriteLine("Passed!"); |
||||
} |
||||
|
||||
private void RunClientStreaming(TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
Console.WriteLine("running client_streaming"); |
||||
|
||||
var bodySizes = new List<int>{27182, 8, 1828, 45904}; |
||||
|
||||
var context = client.StreamingInputCall(); |
||||
foreach (var size in bodySizes) |
||||
{ |
||||
context.Inputs.OnNext( |
||||
StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build()); |
||||
} |
||||
context.Inputs.OnCompleted(); |
||||
|
||||
var response = context.Task.Result; |
||||
Assert.AreEqual(74922, response.AggregatedPayloadSize); |
||||
Console.WriteLine("Passed!"); |
||||
} |
||||
|
||||
private void RunServerStreaming(TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
Console.WriteLine("running server_streaming"); |
||||
|
||||
var bodySizes = new List<int>{31415, 9, 2653, 58979}; |
||||
|
||||
var request = StreamingOutputCallRequest.CreateBuilder() |
||||
.SetResponseType(PayloadType.COMPRESSABLE) |
||||
.AddRangeResponseParameters(bodySizes.ConvertAll( |
||||
(size) => ResponseParameters.CreateBuilder().SetSize(size).Build())) |
||||
.Build(); |
||||
|
||||
var recorder = new RecordingObserver<StreamingOutputCallResponse>(); |
||||
client.StreamingOutputCall(request, recorder); |
||||
|
||||
var responseList = recorder.ToList().Result; |
||||
|
||||
foreach (var res in responseList) |
||||
{ |
||||
Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); |
||||
} |
||||
CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length)); |
||||
Console.WriteLine("Passed!"); |
||||
} |
||||
|
||||
private void RunPingPong(TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
Console.WriteLine("running ping_pong"); |
||||
|
||||
var recorder = new RecordingQueue<StreamingOutputCallResponse>(); |
||||
var inputs = client.FullDuplexCall(recorder); |
||||
|
||||
StreamingOutputCallResponse response; |
||||
|
||||
inputs.OnNext(StreamingOutputCallRequest.CreateBuilder() |
||||
.SetResponseType(PayloadType.COMPRESSABLE) |
||||
.AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) |
||||
.SetPayload(CreateZerosPayload(27182)).Build()); |
||||
|
||||
response = recorder.Queue.Take(); |
||||
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
||||
Assert.AreEqual(31415, response.Payload.Body.Length); |
||||
|
||||
inputs.OnNext(StreamingOutputCallRequest.CreateBuilder() |
||||
.SetResponseType(PayloadType.COMPRESSABLE) |
||||
.AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9)) |
||||
.SetPayload(CreateZerosPayload(8)).Build()); |
||||
|
||||
response = recorder.Queue.Take(); |
||||
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
||||
Assert.AreEqual(9, response.Payload.Body.Length); |
||||
|
||||
inputs.OnNext(StreamingOutputCallRequest.CreateBuilder() |
||||
.SetResponseType(PayloadType.COMPRESSABLE) |
||||
.AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2635)) |
||||
.SetPayload(CreateZerosPayload(1828)).Build()); |
||||
|
||||
response = recorder.Queue.Take(); |
||||
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
||||
Assert.AreEqual(2653, response.Payload.Body.Length); |
||||
|
||||
|
||||
inputs.OnNext(StreamingOutputCallRequest.CreateBuilder() |
||||
.SetResponseType(PayloadType.COMPRESSABLE) |
||||
.AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979)) |
||||
.SetPayload(CreateZerosPayload(45904)).Build()); |
||||
|
||||
response = recorder.Queue.Take(); |
||||
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
||||
Assert.AreEqual(58979, response.Payload.Body.Length); |
||||
|
||||
recorder.Finished.Wait(); |
||||
Assert.AreEqual(0, recorder.Queue.Count); |
||||
|
||||
Console.WriteLine("Passed!"); |
||||
} |
||||
|
||||
private void RunEmptyStream(TestServiceGrpc.ITestServiceClient client) |
||||
{ |
||||
Console.WriteLine("running empty_stream"); |
||||
|
||||
var recorder = new RecordingObserver<StreamingOutputCallResponse>(); |
||||
var inputs = client.FullDuplexCall(recorder); |
||||
inputs.OnCompleted(); |
||||
|
||||
var responseList = recorder.ToList().Result; |
||||
Assert.AreEqual(0, responseList.Count); |
||||
|
||||
Console.WriteLine("Passed!"); |
||||
} |
||||
|
||||
|
||||
private Payload CreateZerosPayload(int size) { |
||||
return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build(); |
||||
} |
||||
|
||||
private static ClientOptions ParseArguments(string[] args) |
||||
{ |
||||
var options = new ClientOptions(); |
||||
foreach(string arg in args) |
||||
{ |
||||
ParseArgument(arg, options); |
||||
if (options.help) |
||||
{ |
||||
break; |
||||
} |
||||
} |
||||
return options; |
||||
} |
||||
|
||||
private static void ParseArgument(string arg, ClientOptions options) |
||||
{ |
||||
Match match; |
||||
match = Regex.Match(arg, "--server_host=(.*)"); |
||||
if (match.Success) |
||||
{ |
||||
options.serverHost = match.Groups[1].Value.Trim(); |
||||
return; |
||||
} |
||||
|
||||
match = Regex.Match(arg, "--server_host_override=(.*)"); |
||||
if (match.Success) |
||||
{ |
||||
options.serverHostOverride = match.Groups[1].Value.Trim(); |
||||
return; |
||||
} |
||||
|
||||
match = Regex.Match(arg, "--server_port=(.*)"); |
||||
if (match.Success) |
||||
{ |
||||
options.serverPort = int.Parse(match.Groups[1].Value.Trim()); |
||||
return; |
||||
} |
||||
|
||||
match = Regex.Match(arg, "--test_case=(.*)"); |
||||
if (match.Success) |
||||
{ |
||||
options.testCase = match.Groups[1].Value.Trim(); |
||||
return; |
||||
} |
||||
|
||||
match = Regex.Match(arg, "--use_tls=(.*)"); |
||||
if (match.Success) |
||||
{ |
||||
options.useTls = bool.Parse(match.Groups[1].Value.Trim()); |
||||
return; |
||||
} |
||||
|
||||
match = Regex.Match(arg, "--use_test_ca=(.*)"); |
||||
if (match.Success) |
||||
{ |
||||
options.useTestCa = bool.Parse(match.Groups[1].Value.Trim()); |
||||
return; |
||||
} |
||||
|
||||
Console.WriteLine(string.Format("Unrecognized argument \"{0}\"", arg)); |
||||
options.help = true; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> |
||||
<ProductVersion>10.0.0</ProductVersion> |
||||
<SchemaVersion>2.0</SchemaVersion> |
||||
<ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid> |
||||
<OutputType>Exe</OutputType> |
||||
<RootNamespace>InteropClient</RootNamespace> |
||||
<AssemblyName>InteropClient</AssemblyName> |
||||
<StartupObject>Google.GRPC.Interop.Client</StartupObject> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Debug</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<PlatformTarget>x86</PlatformTarget> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>true</Optimize> |
||||
<OutputPath>bin\Release</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<PlatformTarget>x86</PlatformTarget> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="System" /> |
||||
<Reference Include="nunit.framework, Version=2.6.0.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77"> |
||||
<Private>False</Private> |
||||
</Reference> |
||||
<Reference Include="Google.ProtocolBuffers"> |
||||
<HintPath>..\lib\Google.ProtocolBuffers.dll</HintPath> |
||||
</Reference> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="Properties\AssemblyInfo.cs" /> |
||||
<Compile Include="Client.cs" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\GrpcCore\GrpcCore.csproj"> |
||||
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project> |
||||
<Name>GrpcCore</Name> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\GrpcApi\GrpcApi.csproj"> |
||||
<Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project> |
||||
<Name>GrpcApi</Name> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,22 @@ |
||||
using System.Reflection; |
||||
using System.Runtime.CompilerServices; |
||||
|
||||
// Information about this assembly is defined by the following attributes. |
||||
// Change them to the values specific to your project. |
||||
[assembly: AssemblyTitle("InteropClient")] |
||||
[assembly: AssemblyDescription("")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyCompany("")] |
||||
[assembly: AssemblyProduct("")] |
||||
[assembly: AssemblyCopyright("jtattermusch")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". |
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision, |
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision. |
||||
[assembly: AssemblyVersion("1.0.*")] |
||||
// The following attributes are used to specify the signing key for the assembly, |
||||
// if desired. See the Mono documentation for more information about signing. |
||||
//[assembly: AssemblyDelaySign(false)] |
||||
//[assembly: AssemblyKeyFile("")] |
||||
|
@ -0,0 +1 @@ |
||||
bin |
Loading…
Reference in new issue