mirror of https://github.com/grpc/grpc.git
commit
5b73bb1142
230 changed files with 4393 additions and 2245 deletions
@ -0,0 +1,145 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Internal; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
namespace Grpc.Core.Tests |
||||
{ |
||||
public class PInvokeTest |
||||
{ |
||||
int counter; |
||||
|
||||
[DllImport("grpc_csharp_ext.dll")] |
||||
static extern GRPCCallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); |
||||
|
||||
[DllImport("grpc_csharp_ext.dll")] |
||||
static extern IntPtr grpcsharp_test_nop(IntPtr ptr); |
||||
|
||||
[TestFixtureSetUp] |
||||
public void Init() |
||||
{ |
||||
GrpcEnvironment.Initialize(); |
||||
} |
||||
|
||||
[TestFixtureTearDown] |
||||
public void Cleanup() |
||||
{ |
||||
GrpcEnvironment.Shutdown(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// (~1.26us .NET Windows) |
||||
/// </summary> |
||||
[Test] |
||||
public void CompletionQueueCreateDestroyBenchmark() |
||||
{ |
||||
BenchmarkUtil.RunBenchmark( |
||||
100000, 1000000, |
||||
() => { |
||||
CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create(); |
||||
cq.Dispose(); |
||||
} |
||||
); |
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// Approximate results: |
||||
/// (~80ns Mono Linux) |
||||
/// (~110ns .NET Windows) |
||||
/// </summary> |
||||
[Test] |
||||
public void NativeCallbackBenchmark() |
||||
{ |
||||
CompletionCallbackDelegate handler = Handler; |
||||
|
||||
counter = 0; |
||||
BenchmarkUtil.RunBenchmark( |
||||
1000000, 10000000, |
||||
() => { |
||||
grpcsharp_test_callback(handler); |
||||
} |
||||
); |
||||
Assert.AreNotEqual(0, counter); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Creating a new native-to-managed callback has significant overhead |
||||
/// compared to using an existing one. We need to be aware of this. |
||||
/// (~50us on Mono Linux!!!) |
||||
/// (~1.1us on .NET Windows) |
||||
/// </summary> |
||||
[Test] |
||||
public void NewNativeCallbackBenchmark() |
||||
{ |
||||
counter = 0; |
||||
BenchmarkUtil.RunBenchmark( |
||||
10000, 10000, |
||||
() => { |
||||
grpcsharp_test_callback(new CompletionCallbackDelegate(Handler)); |
||||
} |
||||
); |
||||
Assert.AreNotEqual(0, counter); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Tests overhead of a simple PInvoke call. |
||||
/// (~46ns .NET Windows) |
||||
/// </summary> |
||||
[Test] |
||||
public void NopPInvokeBenchmark() |
||||
{ |
||||
CompletionCallbackDelegate handler = Handler; |
||||
|
||||
BenchmarkUtil.RunBenchmark( |
||||
1000000, 100000000, |
||||
() => { |
||||
grpcsharp_test_nop(IntPtr.Zero); |
||||
} |
||||
); |
||||
} |
||||
|
||||
private void Handler(GRPCOpError op, IntPtr ptr) { |
||||
counter ++; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,94 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Concurrent; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using System.Runtime.InteropServices; |
||||
using System.Threading; |
||||
|
||||
namespace Grpc.Core.Internal |
||||
{ |
||||
internal delegate void GprLogDelegate(IntPtr fileStringPtr, Int32 line, UInt64 threadId, IntPtr severityStringPtr, IntPtr msgPtr); |
||||
|
||||
/// <summary> |
||||
/// Logs from gRPC C core library can get lost if your application is not a console app. |
||||
/// This class allows redirection of logs to arbitrary destination. |
||||
/// </summary> |
||||
internal static class GrpcLog |
||||
{ |
||||
static object staticLock = new object(); |
||||
static GprLogDelegate writeCallback; |
||||
static TextWriter dest; |
||||
|
||||
[DllImport("grpc_csharp_ext.dll")] |
||||
static extern void grpcsharp_redirect_log(GprLogDelegate callback); |
||||
|
||||
/// <summary> |
||||
/// Sets text writer as destination for logs from native gRPC C core library. |
||||
/// Only first invocation has effect. |
||||
/// </summary> |
||||
/// <param name="textWriter"></param> |
||||
public static void RedirectNativeLogs(TextWriter textWriter) |
||||
{ |
||||
lock (staticLock) |
||||
{ |
||||
if (writeCallback == null) |
||||
{ |
||||
writeCallback = new GprLogDelegate(HandleWrite); |
||||
dest = textWriter; |
||||
grpcsharp_redirect_log(writeCallback); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static void HandleWrite(IntPtr fileStringPtr, Int32 line, UInt64 threadId, IntPtr severityStringPtr, IntPtr msgPtr) |
||||
{ |
||||
try |
||||
{ |
||||
// TODO: DateTime format used here is different than in C core. |
||||
dest.WriteLine(string.Format("{0}{1} {2} {3}:{4}: {5}", |
||||
Marshal.PtrToStringAnsi(severityStringPtr), DateTime.Now, |
||||
threadId, |
||||
Marshal.PtrToStringAnsi(fileStringPtr), |
||||
line, |
||||
Marshal.PtrToStringAnsi(msgPtr))); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
Console.WriteLine("Caught exception in native callback " + e); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,68 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using System.Collections.Generic; |
||||
using System.Collections.Concurrent; |
||||
using System.Diagnostics; |
||||
|
||||
namespace Grpc.Core.Utils |
||||
{ |
||||
public static class BenchmarkUtil |
||||
{ |
||||
/// <summary> |
||||
/// Runs a simple benchmark preceded by warmup phase. |
||||
/// </summary> |
||||
public static void RunBenchmark(int warmupIterations, int benchmarkIterations, Action action) |
||||
{ |
||||
Console.WriteLine("Warmup iterations: " + warmupIterations); |
||||
for (int i = 0; i < warmupIterations; i++) |
||||
{ |
||||
action(); |
||||
} |
||||
|
||||
Console.WriteLine("Benchmark iterations: " + benchmarkIterations); |
||||
var stopwatch = new Stopwatch(); |
||||
stopwatch.Start(); |
||||
for (int i = 0; i < benchmarkIterations; i++) |
||||
{ |
||||
action(); |
||||
} |
||||
stopwatch.Stop(); |
||||
Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + "ms"); |
||||
Console.WriteLine("Ops per second: " + (int) ((double) benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds)); |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,57 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
|
||||
namespace Grpc.Core.Utils |
||||
{ |
||||
public static class ExceptionHelper |
||||
{ |
||||
/// <summary> |
||||
/// If inner exceptions contain RpcException, rethrows it. |
||||
/// Otherwise, rethrows the original aggregate exception. |
||||
/// Always throws, the exception return type is here only to make the. |
||||
/// </summary> |
||||
public static Exception UnwrapRpcException(AggregateException ae) { |
||||
foreach (var e in ae.InnerExceptions) |
||||
{ |
||||
if (e is RpcException) |
||||
{ |
||||
throw e; |
||||
} |
||||
} |
||||
throw ae; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,119 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Grpc.Core; |
||||
using Grpc.Core.Utils; |
||||
using NUnit.Framework; |
||||
using grpc.testing; |
||||
|
||||
namespace Grpc.IntegrationTesting |
||||
{ |
||||
/// <summary> |
||||
/// Runs interop tests in-process. |
||||
/// </summary> |
||||
public class InteropClientServerTest |
||||
{ |
||||
string host = "localhost"; |
||||
Server server; |
||||
Channel channel; |
||||
TestServiceGrpc.ITestServiceClient client; |
||||
|
||||
[TestFixtureSetUp] |
||||
public void Init() |
||||
{ |
||||
GrpcEnvironment.Initialize(); |
||||
|
||||
server = new Server(); |
||||
server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl())); |
||||
int port = server.AddPort(host + ":0"); |
||||
server.Start(); |
||||
channel = new Channel(host + ":" + port); |
||||
client = TestServiceGrpc.NewStub(channel); |
||||
} |
||||
|
||||
[TestFixtureTearDown] |
||||
public void Cleanup() |
||||
{ |
||||
channel.Dispose(); |
||||
|
||||
server.ShutdownAsync().Wait(); |
||||
GrpcEnvironment.Shutdown(); |
||||
} |
||||
|
||||
[Test] |
||||
public void EmptyUnary() |
||||
{ |
||||
Client.RunEmptyUnary(client); |
||||
} |
||||
|
||||
[Test] |
||||
public void LargeUnary() |
||||
{ |
||||
Client.RunEmptyUnary(client); |
||||
} |
||||
|
||||
[Test] |
||||
public void ClientStreaming() |
||||
{ |
||||
Client.RunClientStreaming(client); |
||||
} |
||||
|
||||
[Test] |
||||
public void ServerStreaming() |
||||
{ |
||||
Client.RunServerStreaming(client); |
||||
} |
||||
|
||||
[Test] |
||||
public void PingPong() |
||||
{ |
||||
Client.RunPingPong(client); |
||||
} |
||||
|
||||
[Test] |
||||
public void EmptyStream() |
||||
{ |
||||
Client.RunEmptyStream(client); |
||||
} |
||||
|
||||
// TODO: add cancel_after_begin |
||||
|
||||
// TODO: add cancel_after_first_response |
||||
|
||||
} |
||||
} |
||||
|
@ -0,0 +1,140 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Google.ProtocolBuffers; |
||||
using Grpc.Core.Utils; |
||||
|
||||
namespace grpc.testing |
||||
{ |
||||
/// <summary> |
||||
/// Implementation of TestService server |
||||
/// </summary> |
||||
public class TestServiceImpl : TestServiceGrpc.ITestService |
||||
{ |
||||
public void EmptyCall(Empty request, IObserver<Empty> responseObserver) |
||||
{ |
||||
responseObserver.OnNext(Empty.DefaultInstance); |
||||
responseObserver.OnCompleted(); |
||||
} |
||||
|
||||
public void UnaryCall(SimpleRequest request, IObserver<SimpleResponse> responseObserver) |
||||
{ |
||||
var response = SimpleResponse.CreateBuilder() |
||||
.SetPayload(CreateZerosPayload(request.ResponseSize)).Build(); |
||||
//TODO: check we support ReponseType |
||||
responseObserver.OnNext(response); |
||||
responseObserver.OnCompleted(); |
||||
} |
||||
|
||||
public void StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver) |
||||
{ |
||||
foreach(var responseParam in request.ResponseParametersList) |
||||
{ |
||||
var response = StreamingOutputCallResponse.CreateBuilder() |
||||
.SetPayload(CreateZerosPayload(responseParam.Size)).Build(); |
||||
responseObserver.OnNext(response); |
||||
} |
||||
responseObserver.OnCompleted(); |
||||
} |
||||
|
||||
public IObserver<StreamingInputCallRequest> StreamingInputCall(IObserver<StreamingInputCallResponse> responseObserver) |
||||
{ |
||||
var recorder = new RecordingObserver<StreamingInputCallRequest>(); |
||||
Task.Run(() => { |
||||
int sum = 0; |
||||
foreach(var req in recorder.ToList().Result) |
||||
{ |
||||
sum += req.Payload.Body.Length; |
||||
} |
||||
var response = StreamingInputCallResponse.CreateBuilder() |
||||
.SetAggregatedPayloadSize(sum).Build(); |
||||
responseObserver.OnNext(response); |
||||
responseObserver.OnCompleted(); |
||||
}); |
||||
return recorder; |
||||
} |
||||
|
||||
public IObserver<StreamingOutputCallRequest> FullDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver) |
||||
{ |
||||
return new FullDuplexObserver(responseObserver); |
||||
} |
||||
|
||||
public IObserver<StreamingOutputCallRequest> HalfDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
private class FullDuplexObserver : IObserver<StreamingOutputCallRequest> { |
||||
|
||||
readonly IObserver<StreamingOutputCallResponse> responseObserver; |
||||
|
||||
public FullDuplexObserver(IObserver<StreamingOutputCallResponse> responseObserver) |
||||
{ |
||||
this.responseObserver = responseObserver; |
||||
} |
||||
|
||||
public void OnCompleted() |
||||
{ |
||||
responseObserver.OnCompleted(); |
||||
} |
||||
|
||||
public void OnError(Exception error) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public void OnNext(StreamingOutputCallRequest value) |
||||
{ |
||||
// TODO: this is not in order!!! |
||||
//Task.Factory.StartNew(() => { |
||||
|
||||
foreach(var responseParam in value.ResponseParametersList) |
||||
{ |
||||
var response = StreamingOutputCallResponse.CreateBuilder() |
||||
.SetPayload(CreateZerosPayload(responseParam.Size)).Build(); |
||||
responseObserver.OnNext(response); |
||||
} |
||||
//}); |
||||
} |
||||
} |
||||
|
||||
private static Payload CreateZerosPayload(int size) { |
||||
return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build(); |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,86 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
"""The Python implementation of the GRPC interoperability test client.""" |
||||
|
||||
import argparse |
||||
|
||||
from grpc.early_adopter import implementations |
||||
|
||||
from interop import methods |
||||
from interop import resources |
||||
|
||||
_ONE_DAY_IN_SECONDS = 60 * 60 * 24 |
||||
|
||||
|
||||
def _args(): |
||||
parser = argparse.ArgumentParser() |
||||
parser.add_argument( |
||||
'--server_host', help='the host to which to connect', type=str) |
||||
parser.add_argument( |
||||
'--server_host_override', |
||||
help='the server host to which to claim to connect', type=str) |
||||
parser.add_argument( |
||||
'--server_port', help='the port to which to connect', type=int) |
||||
parser.add_argument( |
||||
'--test_case', help='the test case to execute', type=str) |
||||
parser.add_argument( |
||||
'--use_tls', help='require a secure connection', dest='use_tls', |
||||
action='store_true') |
||||
parser.add_argument( |
||||
'--use_test_ca', help='replace platform root CAs with ca.pem', |
||||
action='store_true') |
||||
return parser.parse_args() |
||||
|
||||
|
||||
def _stub(args): |
||||
if args.use_tls: |
||||
if args.use_test_ca: |
||||
root_certificates = resources.test_root_certificates() |
||||
else: |
||||
root_certificates = resources.prod_root_certificates() |
||||
# TODO(nathaniel): server host override. |
||||
|
||||
stub = implementations.secure_stub( |
||||
methods.CLIENT_METHODS, args.server_host, args.server_port, |
||||
root_certificates, None, None) |
||||
else: |
||||
stub = implementations.insecure_stub( |
||||
methods.CLIENT_METHODS, args.server_host, args.server_port) |
||||
return stub |
||||
|
||||
|
||||
def _test_interoperability(): |
||||
args = _args() |
||||
stub = _stub(args) |
||||
methods.test_interoperability(args.test_case, stub) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
_test_interoperability() |
@ -0,0 +1,15 @@ |
||||
-----BEGIN CERTIFICATE----- |
||||
MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV |
||||
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX |
||||
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla |
||||
Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 |
||||
YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT |
||||
BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 |
||||
+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu |
||||
g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd |
||||
Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV |
||||
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau |
||||
sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m |
||||
oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG |
||||
Dfcog5wrJytaQ6UA0wE= |
||||
-----END CERTIFICATE----- |
@ -0,0 +1,121 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "grpc/_adapter/_client_credentials.h" |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc_security.h> |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
static int pygrpc_client_credentials_init(ClientCredentials *self, |
||||
PyObject *args, PyObject *kwds) { |
||||
char *root_certificates; |
||||
grpc_ssl_pem_key_cert_pair key_certificate_pair; |
||||
static char *kwlist[] = {"root_certificates", "private_key", |
||||
"certificate_chain", NULL}; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "zzz:ClientCredentials", kwlist, |
||||
&root_certificates, |
||||
&key_certificate_pair.private_key, |
||||
&key_certificate_pair.cert_chain)) { |
||||
return -1; |
||||
} |
||||
|
||||
if (key_certificate_pair.private_key != NULL && key_certificate_pair.cert_chain != NULL) { |
||||
self->c_client_credentials = |
||||
grpc_ssl_credentials_create(root_certificates, &key_certificate_pair); |
||||
} else { |
||||
self->c_client_credentials = |
||||
grpc_ssl_credentials_create(root_certificates, NULL); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void pygrpc_client_credentials_dealloc(ClientCredentials *self) { |
||||
if (self->c_client_credentials != NULL) { |
||||
grpc_credentials_release(self->c_client_credentials); |
||||
} |
||||
self->ob_type->tp_free((PyObject *)self); |
||||
} |
||||
|
||||
PyTypeObject pygrpc_ClientCredentialsType = { |
||||
PyVarObject_HEAD_INIT(NULL, 0) |
||||
"_grpc.ClientCredencials", /*tp_name*/ |
||||
sizeof(ClientCredentials), /*tp_basicsize*/ |
||||
0, /*tp_itemsize*/ |
||||
(destructor)pygrpc_client_credentials_dealloc, /*tp_dealloc*/ |
||||
0, /*tp_print*/ |
||||
0, /*tp_getattr*/ |
||||
0, /*tp_setattr*/ |
||||
0, /*tp_compare*/ |
||||
0, /*tp_repr*/ |
||||
0, /*tp_as_number*/ |
||||
0, /*tp_as_sequence*/ |
||||
0, /*tp_as_mapping*/ |
||||
0, /*tp_hash */ |
||||
0, /*tp_call*/ |
||||
0, /*tp_str*/ |
||||
0, /*tp_getattro*/ |
||||
0, /*tp_setattro*/ |
||||
0, /*tp_as_buffer*/ |
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
||||
"Wrapping of grpc_credentials.", /* tp_doc */ |
||||
0, /* tp_traverse */ |
||||
0, /* tp_clear */ |
||||
0, /* tp_richcompare */ |
||||
0, /* tp_weaklistoffset */ |
||||
0, /* tp_iter */ |
||||
0, /* tp_iternext */ |
||||
0, /* tp_methods */ |
||||
0, /* tp_members */ |
||||
0, /* tp_getset */ |
||||
0, /* tp_base */ |
||||
0, /* tp_dict */ |
||||
0, /* tp_descr_get */ |
||||
0, /* tp_descr_set */ |
||||
0, /* tp_dictoffset */ |
||||
(initproc)pygrpc_client_credentials_init, /* tp_init */ |
||||
0, /* tp_alloc */ |
||||
PyType_GenericNew, /* tp_new */ |
||||
}; |
||||
|
||||
int pygrpc_add_client_credentials(PyObject *module) { |
||||
if (PyType_Ready(&pygrpc_ClientCredentialsType) < 0) { |
||||
return -1; |
||||
} |
||||
if (PyModule_AddObject(module, "ClientCredentials", |
||||
(PyObject *)&pygrpc_ClientCredentialsType) == -1) { |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
@ -0,0 +1,48 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _ADAPTER__CLIENT_CREDENTIALS_H_ |
||||
#define _ADAPTER__CLIENT_CREDENTIALS_H_ |
||||
|
||||
#include <Python.h> |
||||
#include <grpc/grpc_security.h> |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD grpc_credentials *c_client_credentials; |
||||
} ClientCredentials; |
||||
|
||||
PyTypeObject pygrpc_ClientCredentialsType; |
||||
|
||||
int pygrpc_add_client_credentials(PyObject *module); |
||||
|
||||
#endif /* _ADAPTER__CLIENT_CREDENTIALS_H_ */ |
@ -0,0 +1,168 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import abc |
||||
import collections |
||||
|
||||
# assembly_interfaces is referenced from specification in this module. |
||||
from grpc.framework.assembly import interfaces as assembly_interfaces # pylint: disable=unused-import |
||||
from grpc.framework.assembly import utilities as assembly_utilities |
||||
from grpc.early_adopter import _reexport |
||||
from grpc.early_adopter import interfaces |
||||
|
||||
|
||||
# TODO(issue 726): Kill the "implementations" attribute of this in favor |
||||
# of the same-information-less-bogusly-represented "cardinalities". |
||||
class InvocationBreakdown(object): |
||||
"""An intermediate representation of invocation-side views of RPC methods. |
||||
|
||||
Attributes: |
||||
cardinalities: A dictionary from RPC method name to interfaces.Cardinality |
||||
value. |
||||
implementations: A dictionary from RPC method name to |
||||
assembly_interfaces.MethodImplementation describing the method. |
||||
request_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing request values for the RPC. |
||||
response_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class _EasyInvocationBreakdown( |
||||
InvocationBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyInvocationBreakdown', |
||||
('cardinalities', 'implementations', 'request_serializers', |
||||
'response_deserializers'))): |
||||
pass |
||||
|
||||
|
||||
class ServiceBreakdown(object): |
||||
"""An intermediate representation of service-side views of RPC methods. |
||||
|
||||
Attributes: |
||||
implementations: A dictionary from RPC method name |
||||
assembly_interfaces.MethodImplementation implementing the RPC method. |
||||
request_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing request values for the RPC. |
||||
response_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class _EasyServiceBreakdown( |
||||
ServiceBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyServiceBreakdown', |
||||
('implementations', 'request_deserializers', 'response_serializers'))): |
||||
pass |
||||
|
||||
|
||||
def break_down_invocation(method_descriptions): |
||||
"""Derives an InvocationBreakdown from several RPC method descriptions. |
||||
|
||||
Args: |
||||
method_descriptions: A dictionary from RPC method name to |
||||
interfaces.RpcMethodInvocationDescription describing the RPCs. |
||||
|
||||
Returns: |
||||
An InvocationBreakdown corresponding to the given method descriptions. |
||||
""" |
||||
cardinalities = {} |
||||
implementations = {} |
||||
request_serializers = {} |
||||
response_deserializers = {} |
||||
for name, method_description in method_descriptions.iteritems(): |
||||
cardinality = method_description.cardinality() |
||||
cardinalities[name] = cardinality |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
implementations[name] = assembly_utilities.unary_unary_inline(None) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
implementations[name] = assembly_utilities.unary_stream_inline(None) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
implementations[name] = assembly_utilities.stream_unary_inline(None) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
implementations[name] = assembly_utilities.stream_stream_inline(None) |
||||
request_serializers[name] = method_description.serialize_request |
||||
response_deserializers[name] = method_description.deserialize_response |
||||
return _EasyInvocationBreakdown( |
||||
cardinalities, implementations, request_serializers, |
||||
response_deserializers) |
||||
|
||||
|
||||
def break_down_service(method_descriptions): |
||||
"""Derives a ServiceBreakdown from several RPC method descriptions. |
||||
|
||||
Args: |
||||
method_descriptions: A dictionary from RPC method name to |
||||
interfaces.RpcMethodServiceDescription describing the RPCs. |
||||
|
||||
Returns: |
||||
A ServiceBreakdown corresponding to the given method descriptions. |
||||
""" |
||||
implementations = {} |
||||
request_deserializers = {} |
||||
response_serializers = {} |
||||
for name, method_description in method_descriptions.iteritems(): |
||||
cardinality = method_description.cardinality() |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
def service( |
||||
request, face_rpc_context, |
||||
service_behavior=method_description.service_unary_unary): |
||||
return service_behavior( |
||||
request, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.unary_unary_inline(service) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
def service( |
||||
request, face_rpc_context, |
||||
service_behavior=method_description.service_unary_stream): |
||||
return service_behavior( |
||||
request, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.unary_stream_inline(service) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
def service( |
||||
request_iterator, face_rpc_context, |
||||
service_behavior=method_description.service_stream_unary): |
||||
return service_behavior( |
||||
request_iterator, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.stream_unary_inline(service) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
def service( |
||||
request_iterator, face_rpc_context, |
||||
service_behavior=method_description.service_stream_stream): |
||||
return service_behavior( |
||||
request_iterator, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.stream_stream_inline(service) |
||||
request_deserializers[name] = method_description.deserialize_request |
||||
response_serializers[name] = method_description.serialize_response |
||||
|
||||
return _EasyServiceBreakdown( |
||||
implementations, request_deserializers, response_serializers) |
@ -1,178 +0,0 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import abc |
||||
import collections |
||||
|
||||
from grpc.framework.face import interfaces as face_interfaces |
||||
|
||||
from grpc.early_adopter import interfaces |
||||
|
||||
|
||||
class _InlineUnaryUnaryMethod(face_interfaces.InlineValueInValueOutMethod): |
||||
|
||||
def __init__(self, unary_unary_server_rpc_method): |
||||
self._method = unary_unary_server_rpc_method |
||||
|
||||
def service(self, request, context): |
||||
"""See face_interfaces.InlineValueInValueOutMethod.service for spec.""" |
||||
return self._method.service_unary_unary(request) |
||||
|
||||
|
||||
class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod): |
||||
|
||||
def __init__(self, unary_stream_server_rpc_method): |
||||
self._method = unary_stream_server_rpc_method |
||||
|
||||
def service(self, request, context): |
||||
"""See face_interfaces.InlineValueInStreamOutMethod.service for spec.""" |
||||
return self._method.service_unary_stream(request) |
||||
|
||||
|
||||
class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod): |
||||
|
||||
def __init__(self, stream_unary_server_rpc_method): |
||||
self._method = stream_unary_server_rpc_method |
||||
|
||||
def service(self, request_iterator, context): |
||||
"""See face_interfaces.InlineStreamInValueOutMethod.service for spec.""" |
||||
return self._method.service_stream_unary(request_iterator) |
||||
|
||||
|
||||
class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod): |
||||
|
||||
def __init__(self, stream_stream_server_rpc_method): |
||||
self._method = stream_stream_server_rpc_method |
||||
|
||||
def service(self, request_iterator, context): |
||||
"""See face_interfaces.InlineStreamInStreamOutMethod.service for spec.""" |
||||
return self._method.service_stream_stream(request_iterator) |
||||
|
||||
|
||||
class ClientBreakdown(object): |
||||
"""An intermediate representation of invocation-side views of RPC methods. |
||||
|
||||
Attributes: |
||||
request_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing request values for the RPC. |
||||
response_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class _EasyClientBreakdown( |
||||
ClientBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyClientBreakdown', |
||||
('request_serializers', 'response_deserializers'))): |
||||
pass |
||||
|
||||
|
||||
class ServerBreakdown(object): |
||||
"""An intermediate representation of implementations of RPC methods. |
||||
|
||||
Attributes: |
||||
unary_unary_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for unary-unary RPC methods. |
||||
unary_stream_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for unary-stream RPC methods. |
||||
stream_unary_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for stream-unary RPC methods. |
||||
stream_stream_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for stream-stream RPC methods. |
||||
request_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing request values for the RPC. |
||||
response_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
|
||||
class _EasyServerBreakdown( |
||||
ServerBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyServerBreakdown', |
||||
('unary_unary_methods', 'unary_stream_methods', 'stream_unary_methods', |
||||
'stream_stream_methods', 'request_deserializers', |
||||
'response_serializers'))): |
||||
pass |
||||
|
||||
|
||||
def client_break_down(methods): |
||||
"""Derives a ClientBreakdown from several interfaces.ClientRpcMethods. |
||||
|
||||
Args: |
||||
methods: A dictionary from RPC mthod name to |
||||
interfaces.ClientRpcMethod object describing the RPCs. |
||||
|
||||
Returns: |
||||
A ClientBreakdown corresponding to the given methods. |
||||
""" |
||||
request_serializers = {} |
||||
response_deserializers = {} |
||||
for name, method in methods.iteritems(): |
||||
request_serializers[name] = method.serialize_request |
||||
response_deserializers[name] = method.deserialize_response |
||||
return _EasyClientBreakdown(request_serializers, response_deserializers) |
||||
|
||||
|
||||
def server_break_down(methods): |
||||
"""Derives a ServerBreakdown from several interfaces.ServerRpcMethods. |
||||
|
||||
Args: |
||||
methods: A dictionary from RPC mthod name to |
||||
interfaces.ServerRpcMethod object describing the RPCs. |
||||
|
||||
Returns: |
||||
A ServerBreakdown corresponding to the given methods. |
||||
""" |
||||
unary_unary = {} |
||||
unary_stream = {} |
||||
stream_unary = {} |
||||
stream_stream = {} |
||||
request_deserializers = {} |
||||
response_serializers = {} |
||||
for name, method in methods.iteritems(): |
||||
cardinality = method.cardinality() |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
unary_unary[name] = _InlineUnaryUnaryMethod(method) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
unary_stream[name] = _InlineUnaryStreamMethod(method) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
stream_unary[name] = _InlineStreamUnaryMethod(method) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
stream_stream[name] = _InlineStreamStreamMethod(method) |
||||
request_deserializers[name] = method.deserialize_request |
||||
response_serializers[name] = method.serialize_response |
||||
|
||||
return _EasyServerBreakdown( |
||||
unary_unary, unary_stream, stream_unary, stream_stream, |
||||
request_deserializers, response_serializers) |
@ -0,0 +1,212 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
from grpc.framework.face import exceptions as face_exceptions |
||||
from grpc.framework.face import interfaces as face_interfaces |
||||
from grpc.framework.foundation import future |
||||
from grpc.early_adopter import exceptions |
||||
from grpc.early_adopter import interfaces |
||||
|
||||
_ABORTION_REEXPORT = { |
||||
face_interfaces.Abortion.CANCELLED: interfaces.Abortion.CANCELLED, |
||||
face_interfaces.Abortion.EXPIRED: interfaces.Abortion.EXPIRED, |
||||
face_interfaces.Abortion.NETWORK_FAILURE: |
||||
interfaces.Abortion.NETWORK_FAILURE, |
||||
face_interfaces.Abortion.SERVICED_FAILURE: |
||||
interfaces.Abortion.SERVICED_FAILURE, |
||||
face_interfaces.Abortion.SERVICER_FAILURE: |
||||
interfaces.Abortion.SERVICER_FAILURE, |
||||
} |
||||
|
||||
|
||||
class _RpcError(exceptions.RpcError): |
||||
pass |
||||
|
||||
|
||||
def _reexport_error(face_rpc_error): |
||||
if isinstance(face_rpc_error, face_exceptions.CancellationError): |
||||
return exceptions.CancellationError() |
||||
elif isinstance(face_rpc_error, face_exceptions.ExpirationError): |
||||
return exceptions.ExpirationError() |
||||
else: |
||||
return _RpcError() |
||||
|
||||
|
||||
def _as_face_abortion_callback(abortion_callback): |
||||
def face_abortion_callback(face_abortion): |
||||
abortion_callback(_ABORTION_REEXPORT[face_abortion]) |
||||
return face_abortion_callback |
||||
|
||||
|
||||
class _ReexportedFuture(future.Future): |
||||
|
||||
def __init__(self, face_future): |
||||
self._face_future = face_future |
||||
|
||||
def cancel(self): |
||||
return self._face_future.cancel() |
||||
|
||||
def cancelled(self): |
||||
return self._face_future.cancelled() |
||||
|
||||
def running(self): |
||||
return self._face_future.running() |
||||
|
||||
def done(self): |
||||
return self._face_future.done() |
||||
|
||||
def result(self, timeout=None): |
||||
try: |
||||
return self._face_future.result(timeout=timeout) |
||||
except face_exceptions.RpcError as e: |
||||
raise _reexport_error(e) |
||||
|
||||
def exception(self, timeout=None): |
||||
face_error = self._face_future.exception(timeout=timeout) |
||||
return None if face_error is None else _reexport_error(face_error) |
||||
|
||||
def traceback(self, timeout=None): |
||||
return self._face_future.traceback(timeout=timeout) |
||||
|
||||
def add_done_callback(self, fn): |
||||
self._face_future.add_done_callback(lambda unused_face_future: fn(self)) |
||||
|
||||
|
||||
def _call_reexporting_errors(behavior, *args, **kwargs): |
||||
try: |
||||
return behavior(*args, **kwargs) |
||||
except face_exceptions.RpcError as e: |
||||
raise _reexport_error(e) |
||||
|
||||
|
||||
def _reexported_future(face_future): |
||||
return _ReexportedFuture(face_future) |
||||
|
||||
|
||||
class _CancellableIterator(interfaces.CancellableIterator): |
||||
|
||||
def __init__(self, face_cancellable_iterator): |
||||
self._face_cancellable_iterator = face_cancellable_iterator |
||||
|
||||
def __iter__(self): |
||||
return self |
||||
|
||||
def next(self): |
||||
return _call_reexporting_errors(self._face_cancellable_iterator.next) |
||||
|
||||
def cancel(self): |
||||
self._face_cancellable_iterator.cancel() |
||||
|
||||
|
||||
class _RpcContext(interfaces.RpcContext): |
||||
|
||||
def __init__(self, face_rpc_context): |
||||
self._face_rpc_context = face_rpc_context |
||||
|
||||
def is_active(self): |
||||
return self._face_rpc_context.is_active() |
||||
|
||||
def time_remaining(self): |
||||
return self._face_rpc_context.time_remaining() |
||||
|
||||
def add_abortion_callback(self, abortion_callback): |
||||
self._face_rpc_context.add_abortion_callback( |
||||
_as_face_abortion_callback(abortion_callback)) |
||||
|
||||
|
||||
class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync): |
||||
|
||||
def __init__(self, face_unary_unary_sync_async): |
||||
self._underlying = face_unary_unary_sync_async |
||||
|
||||
def __call__(self, request, timeout): |
||||
return _call_reexporting_errors( |
||||
self._underlying, request, timeout) |
||||
|
||||
def async(self, request, timeout): |
||||
return _ReexportedFuture(self._underlying.async(request, timeout)) |
||||
|
||||
|
||||
class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync): |
||||
|
||||
def __init__(self, face_stream_unary_sync_async): |
||||
self._underlying = face_stream_unary_sync_async |
||||
|
||||
def __call__(self, request_iterator, timeout): |
||||
return _call_reexporting_errors( |
||||
self._underlying, request_iterator, timeout) |
||||
|
||||
def async(self, request_iterator, timeout): |
||||
return _ReexportedFuture(self._underlying.async(request_iterator, timeout)) |
||||
|
||||
|
||||
class _Stub(interfaces.Stub): |
||||
|
||||
def __init__(self, assembly_stub, cardinalities): |
||||
self._assembly_stub = assembly_stub |
||||
self._cardinalities = cardinalities |
||||
|
||||
def __enter__(self): |
||||
self._assembly_stub.__enter__() |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): |
||||
self._assembly_stub.__exit__(exc_type, exc_val, exc_tb) |
||||
return False |
||||
|
||||
def __getattr__(self, attr): |
||||
underlying_attr = self._assembly_stub.__getattr__(attr) |
||||
cardinality = self._cardinalities.get(attr) |
||||
# TODO(nathaniel): unify this trick with its other occurrence in the code. |
||||
if cardinality is None: |
||||
for name, cardinality in self._cardinalities.iteritems(): |
||||
last_slash_index = name.rfind('/') |
||||
if 0 <= last_slash_index and name[last_slash_index + 1:] == attr: |
||||
break |
||||
else: |
||||
raise AttributeError(attr) |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
return _UnaryUnarySyncAsync(underlying_attr) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
return lambda request, timeout: _CancellableIterator( |
||||
underlying_attr(request, timeout)) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
return _StreamUnarySyncAsync(underlying_attr) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
return lambda request_iterator, timeout: _CancellableIterator( |
||||
underlying_attr(request_iterator, timeout)) |
||||
else: |
||||
raise AttributeError(attr) |
||||
|
||||
def rpc_context(face_rpc_context): |
||||
return _RpcContext(face_rpc_context) |
||||
|
||||
|
||||
def stub(assembly_stub, cardinalities): |
||||
return _Stub(assembly_stub, cardinalities) |
@ -0,0 +1,176 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
# TODO(nathaniel): Expand this test coverage. |
||||
|
||||
"""Test of the GRPC-backed ForeLink and RearLink.""" |
||||
|
||||
import unittest |
||||
|
||||
from grpc.early_adopter import implementations |
||||
from grpc.early_adopter import utilities |
||||
from grpc._junkdrawer import math_pb2 |
||||
|
||||
DIV = 'Div' |
||||
DIV_MANY = 'DivMany' |
||||
FIB = 'Fib' |
||||
SUM = 'Sum' |
||||
|
||||
def _fibbonacci(limit): |
||||
left, right = 0, 1 |
||||
for _ in xrange(limit): |
||||
yield left |
||||
left, right = right, left + right |
||||
|
||||
|
||||
def _div(request, unused_context): |
||||
return math_pb2.DivReply( |
||||
quotient=request.dividend / request.divisor, |
||||
remainder=request.dividend % request.divisor) |
||||
|
||||
|
||||
def _div_many(request_iterator, unused_context): |
||||
for request in request_iterator: |
||||
yield math_pb2.DivReply( |
||||
quotient=request.dividend / request.divisor, |
||||
remainder=request.dividend % request.divisor) |
||||
|
||||
|
||||
def _fib(request, unused_context): |
||||
for number in _fibbonacci(request.limit): |
||||
yield math_pb2.Num(num=number) |
||||
|
||||
|
||||
def _sum(request_iterator, unused_context): |
||||
accumulation = 0 |
||||
for request in request_iterator: |
||||
accumulation += request.num |
||||
return math_pb2.Num(num=accumulation) |
||||
|
||||
|
||||
_INVOCATION_DESCRIPTIONS = { |
||||
DIV: utilities.unary_unary_invocation_description( |
||||
math_pb2.DivArgs.SerializeToString, math_pb2.DivReply.FromString), |
||||
DIV_MANY: utilities.stream_stream_invocation_description( |
||||
math_pb2.DivArgs.SerializeToString, math_pb2.DivReply.FromString), |
||||
FIB: utilities.unary_stream_invocation_description( |
||||
math_pb2.FibArgs.SerializeToString, math_pb2.Num.FromString), |
||||
SUM: utilities.stream_unary_invocation_description( |
||||
math_pb2.Num.SerializeToString, math_pb2.Num.FromString), |
||||
} |
||||
|
||||
_SERVICE_DESCRIPTIONS = { |
||||
DIV: utilities.unary_unary_service_description( |
||||
_div, math_pb2.DivArgs.FromString, |
||||
math_pb2.DivReply.SerializeToString), |
||||
DIV_MANY: utilities.stream_stream_service_description( |
||||
_div_many, math_pb2.DivArgs.FromString, |
||||
math_pb2.DivReply.SerializeToString), |
||||
FIB: utilities.unary_stream_service_description( |
||||
_fib, math_pb2.FibArgs.FromString, math_pb2.Num.SerializeToString), |
||||
SUM: utilities.stream_unary_service_description( |
||||
_sum, math_pb2.Num.FromString, math_pb2.Num.SerializeToString), |
||||
} |
||||
|
||||
_TIMEOUT = 3 |
||||
|
||||
|
||||
class EarlyAdopterImplementationsTest(unittest.TestCase): |
||||
|
||||
def setUp(self): |
||||
self.server = implementations.insecure_server(_SERVICE_DESCRIPTIONS, 0) |
||||
self.server.start() |
||||
port = self.server.port() |
||||
self.stub = implementations.insecure_stub(_INVOCATION_DESCRIPTIONS, 'localhost', port) |
||||
|
||||
def tearDown(self): |
||||
self.server.stop() |
||||
|
||||
def testUpAndDown(self): |
||||
with self.stub: |
||||
pass |
||||
|
||||
def testUnaryUnary(self): |
||||
divisor = 59 |
||||
dividend = 973 |
||||
expected_quotient = dividend / divisor |
||||
expected_remainder = dividend % divisor |
||||
|
||||
with self.stub: |
||||
response = self.stub.Div( |
||||
math_pb2.DivArgs(divisor=divisor, dividend=dividend), _TIMEOUT) |
||||
self.assertEqual(expected_quotient, response.quotient) |
||||
self.assertEqual(expected_remainder, response.remainder) |
||||
|
||||
def testUnaryStream(self): |
||||
stream_length = 43 |
||||
|
||||
with self.stub: |
||||
response_iterator = self.stub.Fib( |
||||
math_pb2.FibArgs(limit=stream_length), _TIMEOUT) |
||||
numbers = tuple(response.num for response in response_iterator) |
||||
for early, middle, later in zip(numbers, numbers[:1], numbers[:2]): |
||||
self.assertEqual(early + middle, later) |
||||
self.assertEqual(stream_length, len(numbers)) |
||||
|
||||
def testStreamUnary(self): |
||||
stream_length = 127 |
||||
|
||||
with self.stub: |
||||
response_future = self.stub.Sum.async( |
||||
(math_pb2.Num(num=index) for index in range(stream_length)), |
||||
_TIMEOUT) |
||||
self.assertEqual( |
||||
(stream_length * (stream_length - 1)) / 2, |
||||
response_future.result().num) |
||||
|
||||
def testStreamStream(self): |
||||
stream_length = 179 |
||||
divisor_offset = 71 |
||||
dividend_offset = 1763 |
||||
|
||||
with self.stub: |
||||
response_iterator = self.stub.DivMany( |
||||
(math_pb2.DivArgs( |
||||
divisor=divisor_offset + index, |
||||
dividend=dividend_offset + index) |
||||
for index in range(stream_length)), |
||||
_TIMEOUT) |
||||
for index, response in enumerate(response_iterator): |
||||
self.assertEqual( |
||||
(dividend_offset + index) / (divisor_offset + index), |
||||
response.quotient) |
||||
self.assertEqual( |
||||
(dividend_offset + index) % (divisor_offset + index), |
||||
response.remainder) |
||||
self.assertEqual(stream_length, index + 1) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue