Merge pull request #423 from jtattermusch/interop_testing

Adding interop client for C#
pull/436/head
Tim Emiola 10 years ago
commit d2785749f8
  1. 12
      src/csharp/Grpc.sln
  2. 282
      src/csharp/GrpcApi/Empty.cs
  3. 14
      src/csharp/GrpcApi/GrpcApi.csproj
  4. 2
      src/csharp/GrpcApi/MathExamples.cs
  5. 2922
      src/csharp/GrpcApi/Messages.cs
  6. 170
      src/csharp/GrpcApi/TestServiceGrpc.cs
  7. 13
      src/csharp/GrpcApi/proto/empty.proto
  8. 0
      src/csharp/GrpcApi/proto/math.proto
  9. 102
      src/csharp/GrpcApi/proto/messages.proto
  10. 42
      src/csharp/GrpcApi/proto/test.proto
  11. 1
      src/csharp/GrpcCore/GrpcCore.csproj
  12. 50
      src/csharp/GrpcCore/Utils/RecordingQueue.cs
  13. 0
      src/csharp/InteropClient/.gitignore
  14. 303
      src/csharp/InteropClient/Client.cs
  15. 59
      src/csharp/InteropClient/InteropClient.csproj
  16. 22
      src/csharp/InteropClient/Properties/AssemblyInfo.cs
  17. 1
      src/csharp/MathClient/.gitignore
  18. 14
      src/csharp/MathClient/MathClient.cs
  19. 2
      src/csharp/MathClient/MathClient.csproj
  20. 2
      src/csharp/MathClient/Properties/AssemblyInfo.cs
  21. 9
      src/csharp/README.md

@ -1,8 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcDemo", "GrpcDemo\GrpcDemo.csproj", "{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcApi", "GrpcApi\GrpcApi.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCore", "GrpcCore\GrpcCore.csproj", "{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}"
@ -11,6 +9,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCoreTests", "GrpcCoreTe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcApiTests", "GrpcApiTests\GrpcApiTests.csproj", "{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MathClient", "MathClient\MathClient.csproj", "{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropClient", "InteropClient\InteropClient.csproj", "{C61154BA-DD4A-4838-8420-0162A28925E0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@ -33,12 +35,16 @@ Global
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = GrpcDemo\GrpcDemo.csproj
StartupItem = InteropClient\InteropClient.csproj
EndGlobalSection
EndGlobal

@ -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

@ -47,10 +47,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Examples.cs" />
<Compile Include="Math.cs" />
<Compile Include="MathGrpc.cs" />
<Compile Include="MathServiceImpl.cs" />
<Compile Include="Empty.cs" />
<Compile Include="Messages.cs" />
<Compile Include="TestServiceGrpc.cs" />
<Compile Include="MathExamples.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -59,4 +62,13 @@
<Name>GrpcCore</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="proto\math.proto" />
<None Include="proto\empty.proto" />
<None Include="proto\messages.proto" />
<None Include="proto\test.proto" />
</ItemGroup>
<ItemGroup>
<Folder Include="proto\" />
</ItemGroup>
</Project>

@ -6,7 +6,7 @@ using Google.GRPC.Core.Utils;
namespace math
{
public class Examples
public static class MathExamples
{
public static void DivExample(MathGrpc.IMathServiceClient stub)
{

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);
}

@ -62,6 +62,7 @@
<Compile Include="ServerServiceDefinition.cs" />
<Compile Include="Utils\RecordingObserver.cs" />
<Compile Include="Utils\PortPicker.cs" />
<Compile Include="Utils\RecordingQueue.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

@ -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("")]

@ -2,25 +2,23 @@ using System;
using System.Runtime.InteropServices;
using Google.GRPC.Core;
using System.Threading;
using math;
namespace Google.GRPC.Demo
namespace math
{
class MainClass
class MathClient
{
public static void Main (string[] args)
{
using (Channel channel = new Channel("127.0.0.1:23456"))
{
MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
Examples.DivExample(stub);
MathExamples.DivExample(stub);
Examples.FibExample(stub);
MathExamples.FibExample(stub);
Examples.SumExample(stub);
MathExamples.SumExample(stub);
Examples.DivManyExample(stub);
MathExamples.DivManyExample(stub);
}
GrpcEnvironment.Shutdown();

@ -35,8 +35,8 @@
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MathClient.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

@ -3,7 +3,7 @@ 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 ("GrpcDemo")]
[assembly: AssemblyTitle ("MathClient")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]

@ -47,8 +47,11 @@ CONTENTS
- ext:
The extension library that wraps C API to be more digestible by C#.
- GrpcApi:
API examples for math.proto and testservice.proto
- GrpcCore:
The main gRPC C# library.
- GrpcApi:
API examples for math.proto.
- InteropClient:
Client for interop testing.
- MathClient:
An example client that sends some requests to math server.

Loading…
Cancel
Save