commit
29f1314282
209 changed files with 4129 additions and 2090 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() |
@ -1,67 +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. |
|
||||||
|
|
||||||
require 'faraday' |
|
||||||
require 'grpc/auth/signet' |
|
||||||
|
|
||||||
module GRPC |
|
||||||
# Module Auth provides classes that provide Google-specific authentication |
|
||||||
# used to access Google gRPC services. |
|
||||||
module Auth |
|
||||||
# Extends Signet::OAuth2::Client so that the auth token is obtained from |
|
||||||
# the GCE metadata server. |
|
||||||
class GCECredentials < Signet::OAuth2::Client |
|
||||||
COMPUTE_AUTH_TOKEN_URI = 'http://metadata/computeMetadata/v1/'\ |
|
||||||
'instance/service-accounts/default/token' |
|
||||||
COMPUTE_CHECK_URI = 'http://metadata.google.internal' |
|
||||||
|
|
||||||
# Detect if this appear to be a GCE instance, by checking if metadata |
|
||||||
# is available |
|
||||||
def self.on_gce?(options = {}) |
|
||||||
c = options[:connection] || Faraday.default_connection |
|
||||||
resp = c.get(COMPUTE_CHECK_URI) |
|
||||||
return false unless resp.status == 200 |
|
||||||
return false unless resp.headers.key?('Metadata-Flavor') |
|
||||||
return resp.headers['Metadata-Flavor'] == 'Google' |
|
||||||
rescue Faraday::ConnectionFailed |
|
||||||
return false |
|
||||||
end |
|
||||||
|
|
||||||
# Overrides the super class method to change how access tokens are |
|
||||||
# fetched. |
|
||||||
def fetch_access_token(options = {}) |
|
||||||
c = options[:connection] || Faraday.default_connection |
|
||||||
c.headers = { 'Metadata-Flavor' => 'Google' } |
|
||||||
resp = c.get(COMPUTE_AUTH_TOKEN_URI) |
|
||||||
Signet::OAuth2.parse_credentials(resp.body, |
|
||||||
resp.headers['content-type']) |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
@ -1,66 +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. |
|
||||||
|
|
||||||
require 'grpc/auth/signet' |
|
||||||
require 'multi_json' |
|
||||||
require 'openssl' |
|
||||||
|
|
||||||
# Reads the private key and client email fields from service account JSON key. |
|
||||||
def read_json_key(json_key_io) |
|
||||||
json_key = MultiJson.load(json_key_io.read) |
|
||||||
fail 'missing client_email' unless json_key.key?('client_email') |
|
||||||
fail 'missing private_key' unless json_key.key?('private_key') |
|
||||||
[json_key['private_key'], json_key['client_email']] |
|
||||||
end |
|
||||||
|
|
||||||
module GRPC |
|
||||||
# Module Auth provides classes that provide Google-specific authentication |
|
||||||
# used to access Google gRPC services. |
|
||||||
module Auth |
|
||||||
# Authenticates requests using Google's Service Account credentials. |
|
||||||
# (cf https://developers.google.com/accounts/docs/OAuth2ServiceAccount) |
|
||||||
class ServiceAccountCredentials < Signet::OAuth2::Client |
|
||||||
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token' |
|
||||||
AUDIENCE = TOKEN_CRED_URI |
|
||||||
|
|
||||||
# Initializes a ServiceAccountCredentials. |
|
||||||
# |
|
||||||
# @param scope [string|array] the scope(s) to access |
|
||||||
# @param json_key_io [IO] an IO from which the JSON key can be read |
|
||||||
def initialize(scope, json_key_io) |
|
||||||
private_key, client_email = read_json_key(json_key_io) |
|
||||||
super(token_credential_uri: TOKEN_CRED_URI, |
|
||||||
audience: AUDIENCE, |
|
||||||
scope: scope, |
|
||||||
issuer: client_email, |
|
||||||
signing_key: OpenSSL::PKey::RSA.new(private_key)) |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
@ -1,163 +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. |
|
||||||
|
|
||||||
spec_dir = File.expand_path(File.join(File.dirname(__FILE__))) |
|
||||||
$LOAD_PATH.unshift(spec_dir) |
|
||||||
$LOAD_PATH.uniq! |
|
||||||
|
|
||||||
require 'faraday' |
|
||||||
require 'spec_helper' |
|
||||||
|
|
||||||
def build_json_response(payload) |
|
||||||
[200, |
|
||||||
{ 'Content-Type' => 'application/json; charset=utf-8' }, |
|
||||||
MultiJson.dump(payload)] |
|
||||||
end |
|
||||||
|
|
||||||
WANTED_AUTH_KEY = :Authorization |
|
||||||
|
|
||||||
shared_examples 'apply/apply! are OK' do |
|
||||||
# tests that use these examples need to define |
|
||||||
# |
|
||||||
# @client which should be an auth client |
|
||||||
# |
|
||||||
# @make_auth_stubs, which should stub out the expected http behaviour of the |
|
||||||
# auth client |
|
||||||
describe '#fetch_access_token' do |
|
||||||
it 'should set access_token to the fetched value' do |
|
||||||
token = '1/abcdef1234567890' |
|
||||||
stubs = make_auth_stubs with_access_token: token |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
|
|
||||||
@client.fetch_access_token!(connection: c) |
|
||||||
expect(@client.access_token).to eq(token) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
describe '#apply!' do |
|
||||||
it 'should update the target hash with fetched access token' do |
|
||||||
token = '1/abcdef1234567890' |
|
||||||
stubs = make_auth_stubs with_access_token: token |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
|
|
||||||
md = { foo: 'bar' } |
|
||||||
@client.apply!(md, connection: c) |
|
||||||
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
|
||||||
expect(md).to eq(want) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
describe 'updater_proc' do |
|
||||||
it 'should provide a proc that updates a hash with the access token' do |
|
||||||
token = '1/abcdef1234567890' |
|
||||||
stubs = make_auth_stubs with_access_token: token |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
|
|
||||||
md = { foo: 'bar' } |
|
||||||
the_proc = @client.updater_proc |
|
||||||
got = the_proc.call(md, connection: c) |
|
||||||
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
|
||||||
expect(got).to eq(want) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
describe '#apply' do |
|
||||||
it 'should not update the original hash with the access token' do |
|
||||||
token = '1/abcdef1234567890' |
|
||||||
stubs = make_auth_stubs with_access_token: token |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
|
|
||||||
md = { foo: 'bar' } |
|
||||||
@client.apply(md, connection: c) |
|
||||||
want = { foo: 'bar' } |
|
||||||
expect(md).to eq(want) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
|
|
||||||
it 'should add the token to the returned hash' do |
|
||||||
token = '1/abcdef1234567890' |
|
||||||
stubs = make_auth_stubs with_access_token: token |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
|
|
||||||
md = { foo: 'bar' } |
|
||||||
got = @client.apply(md, connection: c) |
|
||||||
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
|
||||||
expect(got).to eq(want) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
|
|
||||||
it 'should not fetch a new token if the current is not expired' do |
|
||||||
token = '1/abcdef1234567890' |
|
||||||
stubs = make_auth_stubs with_access_token: token |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
|
|
||||||
n = 5 # arbitrary |
|
||||||
n.times do |_t| |
|
||||||
md = { foo: 'bar' } |
|
||||||
got = @client.apply(md, connection: c) |
|
||||||
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
|
||||||
expect(got).to eq(want) |
|
||||||
end |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
|
|
||||||
it 'should fetch a new token if the current one is expired' do |
|
||||||
token_1 = '1/abcdef1234567890' |
|
||||||
token_2 = '2/abcdef1234567890' |
|
||||||
|
|
||||||
[token_1, token_2].each do |t| |
|
||||||
stubs = make_auth_stubs with_access_token: t |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
md = { foo: 'bar' } |
|
||||||
got = @client.apply(md, connection: c) |
|
||||||
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{t}" } |
|
||||||
expect(got).to eq(want) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
@client.expires_at -= 3601 # default is to expire in 1hr |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
@ -1,108 +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. |
|
||||||
|
|
||||||
spec_dir = File.expand_path(File.join(File.dirname(__FILE__))) |
|
||||||
$LOAD_PATH.unshift(spec_dir) |
|
||||||
$LOAD_PATH.uniq! |
|
||||||
|
|
||||||
require 'apply_auth_examples' |
|
||||||
require 'faraday' |
|
||||||
require 'grpc/auth/compute_engine' |
|
||||||
require 'spec_helper' |
|
||||||
|
|
||||||
describe GRPC::Auth::GCECredentials do |
|
||||||
MD_URI = '/computeMetadata/v1/instance/service-accounts/default/token' |
|
||||||
GCECredentials = GRPC::Auth::GCECredentials |
|
||||||
|
|
||||||
before(:example) do |
|
||||||
@client = GCECredentials.new |
|
||||||
end |
|
||||||
|
|
||||||
def make_auth_stubs(with_access_token: '') |
|
||||||
Faraday::Adapter::Test::Stubs.new do |stub| |
|
||||||
stub.get(MD_URI) do |env| |
|
||||||
headers = env[:request_headers] |
|
||||||
expect(headers['Metadata-Flavor']).to eq('Google') |
|
||||||
build_json_response( |
|
||||||
'access_token' => with_access_token, |
|
||||||
'token_type' => 'Bearer', |
|
||||||
'expires_in' => 3600) |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
it_behaves_like 'apply/apply! are OK' |
|
||||||
|
|
||||||
describe '#on_gce?' do |
|
||||||
it 'should be true when Metadata-Flavor is Google' do |
|
||||||
stubs = Faraday::Adapter::Test::Stubs.new do |stub| |
|
||||||
stub.get('/') do |_env| |
|
||||||
[200, |
|
||||||
{ 'Metadata-Flavor' => 'Google' }, |
|
||||||
''] |
|
||||||
end |
|
||||||
end |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
expect(GCECredentials.on_gce?(connection: c)).to eq(true) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
|
|
||||||
it 'should be false when Metadata-Flavor is not Google' do |
|
||||||
stubs = Faraday::Adapter::Test::Stubs.new do |stub| |
|
||||||
stub.get('/') do |_env| |
|
||||||
[200, |
|
||||||
{ 'Metadata-Flavor' => 'NotGoogle' }, |
|
||||||
''] |
|
||||||
end |
|
||||||
end |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
expect(GCECredentials.on_gce?(connection: c)).to eq(false) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
|
|
||||||
it 'should be false if the response is not 200' do |
|
||||||
stubs = Faraday::Adapter::Test::Stubs.new do |stub| |
|
||||||
stub.get('/') do |_env| |
|
||||||
[404, |
|
||||||
{ 'Metadata-Flavor' => 'Google' }, |
|
||||||
''] |
|
||||||
end |
|
||||||
end |
|
||||||
c = Faraday.new do |b| |
|
||||||
b.adapter(:test, stubs) |
|
||||||
end |
|
||||||
expect(GCECredentials.on_gce?(connection: c)).to eq(false) |
|
||||||
stubs.verify_stubbed_calls |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue