diff options
Diffstat (limited to 'src/python/grpcio_test')
8 files changed, 331 insertions, 18 deletions
diff --git a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py b/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py index 72b1ae5642..7fa90fe35f 100644 --- a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py +++ b/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py @@ -27,7 +27,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Tests the RPC Framework Core's implementation of the Base interface.""" +"""Tests Base interface compliance of the core-over-gRPC-links stack.""" import collections import logging diff --git a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py new file mode 100644 index 0000000000..25b99cbbaf --- /dev/null +++ b/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py @@ -0,0 +1,160 @@ +# 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. + +"""Tests Face compliance of the crust-over-core-over-gRPC-links stack.""" + +import collections +import unittest + +from grpc._adapter import _intermediary_low +from grpc._links import invocation +from grpc._links import service +from grpc.framework.core import implementations as core_implementations +from grpc.framework.crust import implementations as crust_implementations +from grpc.framework.foundation import logging_pool +from grpc.framework.interfaces.links import utilities +from grpc_test import test_common +from grpc_test.framework.common import test_constants +from grpc_test.framework.interfaces.face import test_cases +from grpc_test.framework.interfaces.face import test_interfaces +from grpc_test.framework.interfaces.links import test_utilities + + +class _SerializationBehaviors( + collections.namedtuple( + '_SerializationBehaviors', + ('request_serializers', 'request_deserializers', 'response_serializers', + 'response_deserializers',))): + pass + + +def _serialization_behaviors_from_test_methods(test_methods): + request_serializers = {} + request_deserializers = {} + response_serializers = {} + response_deserializers = {} + for (group, method), test_method in test_methods.iteritems(): + request_serializers[group, method] = test_method.serialize_request + request_deserializers[group, method] = test_method.deserialize_request + response_serializers[group, method] = test_method.serialize_response + response_deserializers[group, method] = test_method.deserialize_response + return _SerializationBehaviors( + request_serializers, request_deserializers, response_serializers, + response_deserializers) + + +class _Implementation(test_interfaces.Implementation): + + def instantiate( + self, methods, method_implementations, multi_method_implementation): + pool = logging_pool.pool(test_constants.POOL_SIZE) + servicer = crust_implementations.servicer( + method_implementations, multi_method_implementation, pool) + serialization_behaviors = _serialization_behaviors_from_test_methods( + methods) + invocation_end_link = core_implementations.invocation_end_link() + service_end_link = core_implementations.service_end_link( + servicer, test_constants.DEFAULT_TIMEOUT, + test_constants.MAXIMUM_TIMEOUT) + service_grpc_link = service.service_link( + serialization_behaviors.request_deserializers, + serialization_behaviors.response_serializers) + port = service_grpc_link.add_port(0, None) + channel = _intermediary_low.Channel('localhost:%d' % port, None) + invocation_grpc_link = invocation.invocation_link( + channel, b'localhost', + serialization_behaviors.request_serializers, + serialization_behaviors.response_deserializers) + + invocation_end_link.join_link(invocation_grpc_link) + invocation_grpc_link.join_link(invocation_end_link) + service_grpc_link.join_link(service_end_link) + service_end_link.join_link(service_grpc_link) + service_end_link.start() + invocation_end_link.start() + invocation_grpc_link.start() + service_grpc_link.start() + + generic_stub = crust_implementations.generic_stub(invocation_end_link, pool) + # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. + group = next(iter(methods))[0] + # TODO(nathaniel): Add a "cardinalities_by_group" attribute to + # _digest.TestServiceDigest. + cardinalities = { + method: method_object.cardinality() + for (group, method), method_object in methods.iteritems()} + dynamic_stub = crust_implementations.dynamic_stub( + invocation_end_link, group, cardinalities, pool) + + return generic_stub, {group: dynamic_stub}, ( + invocation_end_link, invocation_grpc_link, service_grpc_link, + service_end_link, pool) + + def destantiate(self, memo): + (invocation_end_link, invocation_grpc_link, service_grpc_link, + service_end_link, pool) = memo + invocation_end_link.stop(0).wait() + invocation_grpc_link.stop() + service_grpc_link.stop_gracefully() + service_end_link.stop(0).wait() + invocation_end_link.join_link(utilities.NULL_LINK) + invocation_grpc_link.join_link(utilities.NULL_LINK) + service_grpc_link.join_link(utilities.NULL_LINK) + service_end_link.join_link(utilities.NULL_LINK) + pool.shutdown(wait=True) + + def invocation_metadata(self): + return test_common.INVOCATION_INITIAL_METADATA + + def initial_metadata(self): + return test_common.SERVICE_INITIAL_METADATA + + def terminal_metadata(self): + return test_common.SERVICE_TERMINAL_METADATA + + def code(self): + return _intermediary_low.Code.OK + + def details(self): + return test_common.DETAILS + + def metadata_transmitted(self, original_metadata, transmitted_metadata): + return original_metadata is None or grpc_test_common.metadata_transmitted( + original_metadata, transmitted_metadata) + + +def load_tests(loader, tests, pattern): + return unittest.TestSuite( + tests=tuple( + loader.loadTestsFromTestCase(test_case_class) + for test_case_class in test_cases.test_cases(_Implementation()))) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py new file mode 100644 index 0000000000..30bb85f6c3 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py @@ -0,0 +1,111 @@ +# 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. + +"""Tests Face interface compliance of the crust-over-core stack.""" + +import collections +import unittest + +from grpc.framework.core import implementations as core_implementations +from grpc.framework.crust import implementations as crust_implementations +from grpc.framework.foundation import logging_pool +from grpc.framework.interfaces.links import utilities +from grpc_test.framework.common import test_constants +from grpc_test.framework.interfaces.face import test_cases +from grpc_test.framework.interfaces.face import test_interfaces +from grpc_test.framework.interfaces.links import test_utilities + + +class _Implementation(test_interfaces.Implementation): + + def instantiate( + self, methods, method_implementations, multi_method_implementation): + pool = logging_pool.pool(test_constants.POOL_SIZE) + servicer = crust_implementations.servicer( + method_implementations, multi_method_implementation, pool) + + service_end_link = core_implementations.service_end_link( + servicer, test_constants.DEFAULT_TIMEOUT, + test_constants.MAXIMUM_TIMEOUT) + invocation_end_link = core_implementations.invocation_end_link() + invocation_end_link.join_link(service_end_link) + service_end_link.join_link(invocation_end_link) + service_end_link.start() + invocation_end_link.start() + + generic_stub = crust_implementations.generic_stub(invocation_end_link, pool) + # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. + group = next(iter(methods))[0] + # TODO(nathaniel): Add a "cardinalities_by_group" attribute to + # _digest.TestServiceDigest. + cardinalities = { + method: method_object.cardinality() + for (group, method), method_object in methods.iteritems()} + dynamic_stub = crust_implementations.dynamic_stub( + invocation_end_link, group, cardinalities, pool) + + return generic_stub, {group: dynamic_stub}, ( + invocation_end_link, service_end_link, pool) + + def destantiate(self, memo): + invocation_end_link, service_end_link, pool = memo + invocation_end_link.stop(0).wait() + service_end_link.stop(0).wait() + invocation_end_link.join_link(utilities.NULL_LINK) + service_end_link.join_link(utilities.NULL_LINK) + pool.shutdown(wait=True) + + def invocation_metadata(self): + return object() + + def initial_metadata(self): + return object() + + def terminal_metadata(self): + return object() + + def code(self): + return object() + + def details(self): + return object() + + def metadata_transmitted(self, original_metadata, transmitted_metadata): + return original_metadata is transmitted_metadata + + +def load_tests(loader, tests, pattern): + return unittest.TestSuite( + tests=tuple( + loader.loadTestsFromTestCase(test_case_class) + for test_case_class in test_cases.test_cases(_Implementation()))) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py new file mode 100644 index 0000000000..363d9ce8f1 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py @@ -0,0 +1,37 @@ +# 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. + +"""A test constant working around issue 3069.""" + +# test_constants is referenced from specification in this module. +from grpc_test.framework.common import test_constants # pylint: disable=unused-import + +# TODO(issue 3069): Replace uses of this constant with +# test_constants.SHORT_TIMEOUT. +REALLY_SHORT_TIMEOUT = 0.1 diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py index 857ad5cf3e..8804f3f223 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py @@ -37,6 +37,7 @@ from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage +from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import @@ -170,7 +171,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): self._invoker.blocking(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( @@ -181,7 +182,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): response_iterator = self._invoker.blocking(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): @@ -193,7 +194,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): self._invoker.blocking(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( @@ -204,7 +205,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): response_iterator = self._invoker.blocking(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py index ea5cdeaea3..5a78b4bed2 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py @@ -37,6 +37,7 @@ from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage +from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _receiver from grpc_test.framework.interfaces.face import _stock_service @@ -264,7 +265,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): self._invoker.event(group, method)( - request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + request, receiver, receiver.abort, + _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) @@ -278,7 +280,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): self._invoker.event(group, method)( - request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + request, receiver, receiver.abort, + _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) @@ -290,7 +293,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): receiver = _receiver.Receiver() self._invoker.event(group, method)( - receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) @@ -303,7 +306,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( - receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) for request in requests: call_consumer.consume(request) receiver.block_until_terminated() diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py index a649362cef..d1107e1576 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py @@ -40,6 +40,7 @@ from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage +from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import @@ -265,7 +266,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_future = self._invoker.future( - group, method)(request, test_constants.SHORT_TIMEOUT) + group, method)(request, _3069_test_constant.REALLY_SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): @@ -279,7 +280,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_iterator = self._invoker.future(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(response_iterator) @@ -291,7 +292,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_future = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): @@ -305,7 +306,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_iterator = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(response_iterator) @@ -317,7 +318,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.fail(): response_future = self._invoker.future(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is @@ -340,7 +341,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): # expiration of the RPC. with self._control.fail(), self.assertRaises(face.ExpirationError): response_iterator = self._invoker.future(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): @@ -351,7 +352,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.fail(): response_future = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is @@ -374,5 +375,5 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): # expiration of the RPC. with self._control.fail(), self.assertRaises(face.ExpirationError): response_iterator = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py index 1dd2ec3633..808e2c4e36 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py @@ -1,4 +1,4 @@ -B# Copyright 2015, Google Inc. +# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without |