From 208313895d768d6ca9cba940ce0c5d5c1943c4de Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 24 Feb 2015 14:16:04 -0800 Subject: [PATCH 01/12] Added interop server, interop unit tests and fixes to pingpong --- src/csharp/Grpc.Examples/MathServiceImpl.cs | 11 +- src/csharp/Grpc.IntegrationTesting/Client.cs | 20 +-- .../Grpc.IntegrationTesting.csproj | 2 + .../InteropClientServerTest.cs | 119 +++++++++++++++ .../TestServiceImpl.cs | 140 ++++++++++++++++++ 5 files changed, 274 insertions(+), 18 deletions(-) create mode 100644 src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs create mode 100644 src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs index 462fab4454f..76a08ce5186 100644 --- a/src/csharp/Grpc.Examples/MathServiceImpl.cs +++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs @@ -127,8 +127,7 @@ namespace math public void OnCompleted() { - Task.Factory.StartNew(() => - responseObserver.OnCompleted()); + responseObserver.OnCompleted(); } public void OnError(Exception error) @@ -138,13 +137,7 @@ namespace math public void OnNext(DivArgs value) { - // TODO: currently we need this indirection because - // responseObserver waits for write to finish, this - // callback is called from grpc threadpool which - // currently only has one thread. - // Same story for OnCompleted(). - Task.Factory.StartNew(() => - responseObserver.OnNext(DivInternal(value))); + responseObserver.OnNext(DivInternal(value)); } } } diff --git a/src/csharp/Grpc.IntegrationTesting/Client.cs b/src/csharp/Grpc.IntegrationTesting/Client.cs index 0c70744cea5..fa1c7cd051b 100644 --- a/src/csharp/Grpc.IntegrationTesting/Client.cs +++ b/src/csharp/Grpc.IntegrationTesting/Client.cs @@ -138,7 +138,7 @@ namespace Grpc.IntegrationTesting } } - private void RunEmptyUnary(TestServiceGrpc.ITestServiceClient client) + public static void RunEmptyUnary(TestServiceGrpc.ITestServiceClient client) { Console.WriteLine("running empty_unary"); var response = client.EmptyCall(Empty.DefaultInstance); @@ -146,7 +146,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - private void RunLargeUnary(TestServiceGrpc.ITestServiceClient client) + public static void RunLargeUnary(TestServiceGrpc.ITestServiceClient client) { Console.WriteLine("running large_unary"); var request = SimpleRequest.CreateBuilder() @@ -162,7 +162,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - private void RunClientStreaming(TestServiceGrpc.ITestServiceClient client) + public static void RunClientStreaming(TestServiceGrpc.ITestServiceClient client) { Console.WriteLine("running client_streaming"); @@ -181,7 +181,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - private void RunServerStreaming(TestServiceGrpc.ITestServiceClient client) + public static void RunServerStreaming(TestServiceGrpc.ITestServiceClient client) { Console.WriteLine("running server_streaming"); @@ -206,7 +206,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - private void RunPingPong(TestServiceGrpc.ITestServiceClient client) + public static void RunPingPong(TestServiceGrpc.ITestServiceClient client) { Console.WriteLine("running ping_pong"); @@ -235,7 +235,7 @@ namespace Grpc.IntegrationTesting inputs.OnNext(StreamingOutputCallRequest.CreateBuilder() .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2635)) + .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653)) .SetPayload(CreateZerosPayload(1828)).Build()); response = recorder.Queue.Take(); @@ -252,13 +252,15 @@ namespace Grpc.IntegrationTesting Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); Assert.AreEqual(58979, response.Payload.Body.Length); + inputs.OnCompleted(); + recorder.Finished.Wait(); Assert.AreEqual(0, recorder.Queue.Count); Console.WriteLine("Passed!"); } - private void RunEmptyStream(TestServiceGrpc.ITestServiceClient client) + public static void RunEmptyStream(TestServiceGrpc.ITestServiceClient client) { Console.WriteLine("running empty_stream"); @@ -273,13 +275,13 @@ namespace Grpc.IntegrationTesting } // This is not an official interop test, but it's useful. - private void RunBenchmarkEmptyUnary(TestServiceGrpc.ITestServiceClient client) + public static void RunBenchmarkEmptyUnary(TestServiceGrpc.ITestServiceClient client) { BenchmarkUtil.RunBenchmark(10000, 10000, () => { client.EmptyCall(Empty.DefaultInstance);}); } - private Payload CreateZerosPayload(int size) { + private static Payload CreateZerosPayload(int size) { return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build(); } diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 9b46a644bc1..e66f708a945 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -47,6 +47,8 @@ + + diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs new file mode 100644 index 00000000000..87d25b0a98c --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -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 +{ + /// + /// Runs interop tests in-process. + /// + 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 + + } +} + diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs new file mode 100644 index 00000000000..176843b1305 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs @@ -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 +{ + /// + /// Implementation of TestService server + /// + public class TestServiceImpl : TestServiceGrpc.ITestService + { + public void EmptyCall(Empty request, IObserver responseObserver) + { + responseObserver.OnNext(Empty.DefaultInstance); + responseObserver.OnCompleted(); + } + + public void UnaryCall(SimpleRequest request, IObserver 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 responseObserver) + { + foreach(var responseParam in request.ResponseParametersList) + { + var response = StreamingOutputCallResponse.CreateBuilder() + .SetPayload(CreateZerosPayload(responseParam.Size)).Build(); + responseObserver.OnNext(response); + } + responseObserver.OnCompleted(); + } + + public IObserver StreamingInputCall(IObserver responseObserver) + { + var recorder = new RecordingObserver(); + 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 FullDuplexCall(IObserver responseObserver) + { + return new FullDuplexObserver(responseObserver); + } + + public IObserver HalfDuplexCall(IObserver responseObserver) + { + throw new NotImplementedException(); + } + + private class FullDuplexObserver : IObserver { + + readonly IObserver responseObserver; + + public FullDuplexObserver(IObserver 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(); + } + } +} + From 0e1f527914a3b08ddb2dcb4a22b622f5a30d5215 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 24 Feb 2015 14:27:11 -0800 Subject: [PATCH 02/12] fix to make empty_stream pass against C++ server --- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index dadc9ab76cf..44f0b37b0ff 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -544,6 +544,8 @@ namespace Grpc.Core.Internal } observer = readObserver; status = finishedStatus; + + ReleaseResourcesIfPossible(); } // TODO: wrap deserialization... From 4788e78d10919a74437d228790c0837ad96fcf6b Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 24 Feb 2015 16:14:28 -0800 Subject: [PATCH 03/12] fixed server streaming --- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 44f0b37b0ff..6f37b059f75 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -181,6 +181,7 @@ namespace Grpc.Core.Internal { started = true; halfcloseRequested = true; + halfclosed = true; // halfclose not confirmed yet, but it will be once finishedHandler is called. this.readObserver = readObserver; From 60fcca5dec4973faf3d1f0f7d83dfb419f882614 Mon Sep 17 00:00:00 2001 From: Dan Ciruli Date: Wed, 25 Feb 2015 12:24:39 -0800 Subject: [PATCH 04/12] Update binding.gyp --- src/node/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/binding.gyp b/src/node/binding.gyp index fb4c779f8eb..5c34be24ff5 100644 --- a/src/node/binding.gyp +++ b/src/node/binding.gyp @@ -7,7 +7,7 @@ "targets" : [ { 'include_dirs': [ - " Date: Wed, 25 Feb 2015 12:30:26 -0800 Subject: [PATCH 05/12] Changing to use node instead of nodejs --- src/node/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/package.json b/src/node/package.json index 1c44b106fb4..24b4a6ead45 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -3,8 +3,8 @@ "version": "0.2.0", "description": "gRPC Library for Node", "scripts": { - "lint": "nodejs ./node_modules/jshint/bin/jshint src test examples interop index.js", - "test": "nodejs ./node_modules/mocha/bin/mocha && npm run-script lint" + "lint": "node ./node_modules/jshint/bin/jshint src test examples interop index.js", + "test": "node ./node_modules/mocha/bin/mocha && npm run-script lint" }, "dependencies": { "bindings": "^1.2.1", From de3c654bc991d3e0d58e9dc81b4ac6aad2965e6d Mon Sep 17 00:00:00 2001 From: Dan Ciruli Date: Wed, 25 Feb 2015 12:50:09 -0800 Subject: [PATCH 06/12] Clarify INSTALL Added better instructions (including the git instructions). --- INSTALL | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/INSTALL b/INSTALL index 2f5f29c788f..c12bea089fc 100644 --- a/INSTALL +++ b/INSTALL @@ -9,15 +9,16 @@ wiki pages: * If you are in a hurry * ************************* -A typical unix installation won't require any more steps than running: + $ git clone https://github.com/grpc/grpc.git + $ git submodule update --init - $ make - # make install + $ make + $ sudo make install You don't need anything else than GNU Make, gcc and autotools. Under a Debian or Ubuntu system, this should boil down to the following packages: - # apt-get install build-essential autoconf libtool + $ apt-get install build-essential autoconf libtool Building the python wrapper requires the following: From e6d72c2b4efc6eeb23e5a5141b4ac465d8629b8e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 25 Feb 2015 22:16:45 +0100 Subject: [PATCH 07/12] Removing emplace from python plugin. --- src/compiler/python_generator.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc index 34d5332d03f..a93b08c5ceb 100644 --- a/src/compiler/python_generator.cc +++ b/src/compiler/python_generator.cc @@ -245,8 +245,8 @@ bool PrintServerFactory(const ServiceDescriptor* service, Printer* out) { if (!GetModuleAndMessagePath(input_type, &module_and_message)) { return false; } - method_to_module_and_message.emplace( - meth->name(), module_and_message); + method_to_module_and_message.insert( + make_pair(meth->name(), module_and_message)); } out->Print("}\n"); // Ensure that we've imported all of the relevant messages. @@ -306,8 +306,8 @@ bool PrintStubFactory(const ServiceDescriptor* service, Printer* out) { if (!GetModuleAndMessagePath(output_type, &module_and_message)) { return false; } - method_to_module_and_message.emplace( - meth->name(), module_and_message); + method_to_module_and_message.insert( + make_pair(meth->name(), module_and_message)); } out->Print("}\n"); // Ensure that we've imported all of the relevant messages. From b189cbe7c0d8ef6077d262653fc462740d14f826 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Feb 2015 13:24:30 -0800 Subject: [PATCH 08/12] Add Debian nodejs-legacy instructions --- src/node/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/node/README.md b/src/node/README.md index 8880213e9a9..5b3de6b4f6e 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -4,6 +4,10 @@ Alpha : Ready for early adopters +## Prerequisites + +This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. + ## Installation First, clone this repository (NPM package coming soon). Then follow the instructions in the `INSTALL` file in the root of the repository to install the C core library that this package depends on. From 9e47368d8fcd2615f5e301364386f3427883ab88 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 25 Feb 2015 13:28:22 -0800 Subject: [PATCH 09/12] Bumped node version to 0.5.0 --- src/node/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/package.json b/src/node/package.json index 1c44b106fb4..57434a618ae 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "0.2.0", + "version": "0.5.0", "description": "gRPC Library for Node", "scripts": { "lint": "nodejs ./node_modules/jshint/bin/jshint src test examples interop index.js", From c6e42c8a868ca3b471cd1f4a7697bc7195efea06 Mon Sep 17 00:00:00 2001 From: Nathaniel Manista Date: Wed, 25 Feb 2015 21:30:24 +0000 Subject: [PATCH 10/12] Set Python version number to 0.4.0. --- src/python/src/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/src/setup.py b/src/python/src/setup.py index 23f128636e4..26121dcfab6 100644 --- a/src/python/src/setup.py +++ b/src/python/src/setup.py @@ -81,6 +81,6 @@ _PACKAGE_DIRECTORIES = { } _core.setup( - name='grpc-2015', version='0.0.1', + name='grpc-2015', version='0.4.0', ext_modules=[_EXTENSION_MODULE], packages=_PACKAGES, package_dir=_PACKAGE_DIRECTORIES) From ed3671e1800fd31fe95c152f04d357e8ef91d45a Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Wed, 25 Feb 2015 13:38:53 -0800 Subject: [PATCH 11/12] Synchronize initial package versions --- src/ruby/lib/grpc/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index d4eb0ed24f6..513a53724f3 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '0.0.1' + VERSION = '0.5.0' end From 1ffe4feb6fc30312da18d5bcf70097a8e0b62634 Mon Sep 17 00:00:00 2001 From: Nathaniel Manista Date: Wed, 25 Feb 2015 21:39:05 +0000 Subject: [PATCH 12/12] Sanitize a reference number. --- src/python/src/grpc/_adapter/_call.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/src/grpc/_adapter/_call.c b/src/python/src/grpc/_adapter/_call.c index 325d3d5bbd6..dca2e49373b 100644 --- a/src/python/src/grpc/_adapter/_call.c +++ b/src/python/src/grpc/_adapter/_call.c @@ -161,7 +161,7 @@ static const PyObject *pygrpc_call_accept(Call *self, PyObject *args) { } static const PyObject *pygrpc_call_premetadata(Call *self) { - /* TODO(b/18702680): Actually support metadata. */ + /* TODO(nathaniel): Metadata support. */ return pygrpc_translate_call_error( grpc_call_server_end_initial_metadata_old(self->c_call, 0)); }