Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 1 | # Copyright 2016, Google Inc. |
| 2 | # All rights reserved. |
| 3 | # |
| 4 | # Redistribution and use in source and binary forms, with or without |
| 5 | # modification, are permitted provided that the following conditions are |
| 6 | # met: |
| 7 | # |
| 8 | # * Redistributions of source code must retain the above copyright |
| 9 | # notice, this list of conditions and the following disclaimer. |
| 10 | # * Redistributions in binary form must reproduce the above |
| 11 | # copyright notice, this list of conditions and the following disclaimer |
| 12 | # in the documentation and/or other materials provided with the |
| 13 | # distribution. |
| 14 | # * Neither the name of Google Inc. nor the names of its |
| 15 | # contributors may be used to endorse or promote products derived from |
| 16 | # this software without specific prior written permission. |
| 17 | # |
| 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | |
| 30 | import collections |
| 31 | from concurrent import futures |
| 32 | import contextlib |
| 33 | import distutils.spawn |
| 34 | import errno |
| 35 | import importlib |
| 36 | import os |
| 37 | import os.path |
| 38 | import pkgutil |
| 39 | import shutil |
| 40 | import subprocess |
| 41 | import sys |
| 42 | import tempfile |
| 43 | import threading |
| 44 | import unittest |
| 45 | |
| 46 | import grpc |
Masood Malekghassemi | fb261bf | 2016-12-12 13:19:31 -0800 | [diff] [blame] | 47 | from grpc_tools import protoc |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 48 | from tests.unit.framework.common import test_constants |
| 49 | |
| 50 | _MESSAGES_IMPORT = b'import "messages.proto";' |
Ken Payson | dbf571e | 2017-02-09 14:10:03 -0800 | [diff] [blame^] | 51 | _SPLIT_NAMESPACE = b'package grpc_protoc_plugin.invocation_testing.split;' |
| 52 | _COMMON_NAMESPACE = b'package grpc_protoc_plugin.invocation_testing;' |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 53 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 54 | |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 55 | @contextlib.contextmanager |
| 56 | def _system_path(path): |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 57 | old_system_path = sys.path[:] |
| 58 | sys.path = sys.path[0:1] + path + sys.path[1:] |
| 59 | yield |
| 60 | sys.path = old_system_path |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 61 | |
| 62 | |
| 63 | class DummySplitServicer(object): |
| 64 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 65 | def __init__(self, request_class, response_class): |
| 66 | self.request_class = request_class |
| 67 | self.response_class = response_class |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 68 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 69 | def Call(self, request, context): |
| 70 | return self.response_class() |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 71 | |
| 72 | |
| 73 | class SeparateTestMixin(object): |
| 74 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 75 | def testImportAttributes(self): |
| 76 | with _system_path([self.python_out_directory]): |
| 77 | pb2 = importlib.import_module(self.pb2_import) |
| 78 | pb2.Request |
| 79 | pb2.Response |
| 80 | if self.should_find_services_in_pb2: |
| 81 | pb2.TestServiceServicer |
| 82 | else: |
| 83 | with self.assertRaises(AttributeError): |
| 84 | pb2.TestServiceServicer |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 85 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 86 | with _system_path([self.grpc_python_out_directory]): |
| 87 | pb2_grpc = importlib.import_module(self.pb2_grpc_import) |
| 88 | pb2_grpc.TestServiceServicer |
| 89 | with self.assertRaises(AttributeError): |
| 90 | pb2_grpc.Request |
| 91 | with self.assertRaises(AttributeError): |
| 92 | pb2_grpc.Response |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 93 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 94 | def testCall(self): |
| 95 | with _system_path([self.python_out_directory]): |
| 96 | pb2 = importlib.import_module(self.pb2_import) |
| 97 | with _system_path([self.grpc_python_out_directory]): |
| 98 | pb2_grpc = importlib.import_module(self.pb2_grpc_import) |
| 99 | server = grpc.server( |
| 100 | futures.ThreadPoolExecutor(max_workers=test_constants.POOL_SIZE)) |
| 101 | pb2_grpc.add_TestServiceServicer_to_server( |
| 102 | DummySplitServicer(pb2.Request, pb2.Response), server) |
| 103 | port = server.add_insecure_port('[::]:0') |
| 104 | server.start() |
| 105 | channel = grpc.insecure_channel('localhost:{}'.format(port)) |
| 106 | stub = pb2_grpc.TestServiceStub(channel) |
| 107 | request = pb2.Request() |
| 108 | expected_response = pb2.Response() |
| 109 | response = stub.Call(request) |
| 110 | self.assertEqual(expected_response, response) |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 111 | |
| 112 | |
| 113 | class CommonTestMixin(object): |
| 114 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 115 | def testImportAttributes(self): |
| 116 | with _system_path([self.python_out_directory]): |
| 117 | pb2 = importlib.import_module(self.pb2_import) |
| 118 | pb2.Request |
| 119 | pb2.Response |
| 120 | if self.should_find_services_in_pb2: |
| 121 | pb2.TestServiceServicer |
| 122 | else: |
| 123 | with self.assertRaises(AttributeError): |
| 124 | pb2.TestServiceServicer |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 125 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 126 | with _system_path([self.grpc_python_out_directory]): |
| 127 | pb2_grpc = importlib.import_module(self.pb2_grpc_import) |
| 128 | pb2_grpc.TestServiceServicer |
| 129 | with self.assertRaises(AttributeError): |
| 130 | pb2_grpc.Request |
| 131 | with self.assertRaises(AttributeError): |
| 132 | pb2_grpc.Response |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 133 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 134 | def testCall(self): |
| 135 | with _system_path([self.python_out_directory]): |
| 136 | pb2 = importlib.import_module(self.pb2_import) |
| 137 | with _system_path([self.grpc_python_out_directory]): |
| 138 | pb2_grpc = importlib.import_module(self.pb2_grpc_import) |
| 139 | server = grpc.server( |
| 140 | futures.ThreadPoolExecutor(max_workers=test_constants.POOL_SIZE)) |
| 141 | pb2_grpc.add_TestServiceServicer_to_server( |
| 142 | DummySplitServicer(pb2.Request, pb2.Response), server) |
| 143 | port = server.add_insecure_port('[::]:0') |
| 144 | server.start() |
| 145 | channel = grpc.insecure_channel('localhost:{}'.format(port)) |
| 146 | stub = pb2_grpc.TestServiceStub(channel) |
| 147 | request = pb2.Request() |
| 148 | expected_response = pb2.Response() |
| 149 | response = stub.Call(request) |
| 150 | self.assertEqual(expected_response, response) |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 151 | |
| 152 | |
| 153 | class SameSeparateTest(unittest.TestCase, SeparateTestMixin): |
| 154 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 155 | def setUp(self): |
| 156 | same_proto_contents = pkgutil.get_data( |
| 157 | 'tests.protoc_plugin.protos.invocation_testing', 'same.proto') |
| 158 | self.directory = tempfile.mkdtemp(suffix='same_separate', dir='.') |
| 159 | self.proto_directory = os.path.join(self.directory, 'proto_path') |
| 160 | self.python_out_directory = os.path.join(self.directory, 'python_out') |
| 161 | self.grpc_python_out_directory = os.path.join(self.directory, |
| 162 | 'grpc_python_out') |
| 163 | os.makedirs(self.proto_directory) |
| 164 | os.makedirs(self.python_out_directory) |
| 165 | os.makedirs(self.grpc_python_out_directory) |
| 166 | same_proto_file = os.path.join(self.proto_directory, |
| 167 | 'same_separate.proto') |
Ken Payson | dbf571e | 2017-02-09 14:10:03 -0800 | [diff] [blame^] | 168 | open(same_proto_file, 'wb').write( |
| 169 | same_proto_contents.replace( |
| 170 | _COMMON_NAMESPACE, |
| 171 | b'package grpc_protoc_plugin.invocation_testing.same_separate;')) |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 172 | protoc_result = protoc.main([ |
| 173 | '', |
| 174 | '--proto_path={}'.format(self.proto_directory), |
| 175 | '--python_out={}'.format(self.python_out_directory), |
| 176 | '--grpc_python_out=grpc_2_0:{}'.format( |
| 177 | self.grpc_python_out_directory), |
| 178 | same_proto_file, |
| 179 | ]) |
| 180 | if protoc_result != 0: |
| 181 | raise Exception("unexpected protoc error") |
| 182 | open(os.path.join(self.grpc_python_out_directory, '__init__.py'), |
| 183 | 'w').write('') |
| 184 | open(os.path.join(self.python_out_directory, '__init__.py'), |
| 185 | 'w').write('') |
| 186 | self.pb2_import = 'same_separate_pb2' |
| 187 | self.pb2_grpc_import = 'same_separate_pb2_grpc' |
| 188 | self.should_find_services_in_pb2 = False |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 189 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 190 | def tearDown(self): |
| 191 | shutil.rmtree(self.directory) |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 192 | |
| 193 | |
| 194 | class SameCommonTest(unittest.TestCase, CommonTestMixin): |
| 195 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 196 | def setUp(self): |
| 197 | same_proto_contents = pkgutil.get_data( |
| 198 | 'tests.protoc_plugin.protos.invocation_testing', 'same.proto') |
| 199 | self.directory = tempfile.mkdtemp(suffix='same_common', dir='.') |
| 200 | self.proto_directory = os.path.join(self.directory, 'proto_path') |
| 201 | self.python_out_directory = os.path.join(self.directory, 'python_out') |
| 202 | self.grpc_python_out_directory = self.python_out_directory |
| 203 | os.makedirs(self.proto_directory) |
| 204 | os.makedirs(self.python_out_directory) |
| 205 | same_proto_file = os.path.join(self.proto_directory, |
| 206 | 'same_common.proto') |
Ken Payson | dbf571e | 2017-02-09 14:10:03 -0800 | [diff] [blame^] | 207 | open(same_proto_file, 'wb').write( |
| 208 | same_proto_contents.replace( |
| 209 | _COMMON_NAMESPACE, |
| 210 | b'package grpc_protoc_plugin.invocation_testing.same_common;')) |
| 211 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 212 | protoc_result = protoc.main([ |
| 213 | '', |
| 214 | '--proto_path={}'.format(self.proto_directory), |
| 215 | '--python_out={}'.format(self.python_out_directory), |
| 216 | '--grpc_python_out={}'.format(self.grpc_python_out_directory), |
| 217 | same_proto_file, |
| 218 | ]) |
| 219 | if protoc_result != 0: |
| 220 | raise Exception("unexpected protoc error") |
| 221 | open(os.path.join(self.python_out_directory, '__init__.py'), |
| 222 | 'w').write('') |
| 223 | self.pb2_import = 'same_common_pb2' |
| 224 | self.pb2_grpc_import = 'same_common_pb2_grpc' |
| 225 | self.should_find_services_in_pb2 = True |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 226 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 227 | def tearDown(self): |
| 228 | shutil.rmtree(self.directory) |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 229 | |
| 230 | |
| 231 | class SplitCommonTest(unittest.TestCase, CommonTestMixin): |
| 232 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 233 | def setUp(self): |
| 234 | services_proto_contents = pkgutil.get_data( |
| 235 | 'tests.protoc_plugin.protos.invocation_testing.split_services', |
| 236 | 'services.proto') |
| 237 | messages_proto_contents = pkgutil.get_data( |
| 238 | 'tests.protoc_plugin.protos.invocation_testing.split_messages', |
| 239 | 'messages.proto') |
| 240 | self.directory = tempfile.mkdtemp(suffix='split_common', dir='.') |
| 241 | self.proto_directory = os.path.join(self.directory, 'proto_path') |
| 242 | self.python_out_directory = os.path.join(self.directory, 'python_out') |
| 243 | self.grpc_python_out_directory = self.python_out_directory |
| 244 | os.makedirs(self.proto_directory) |
| 245 | os.makedirs(self.python_out_directory) |
| 246 | services_proto_file = os.path.join(self.proto_directory, |
| 247 | 'split_common_services.proto') |
| 248 | messages_proto_file = os.path.join(self.proto_directory, |
| 249 | 'split_common_messages.proto') |
| 250 | open(services_proto_file, 'wb').write( |
| 251 | services_proto_contents.replace( |
Ken Payson | dbf571e | 2017-02-09 14:10:03 -0800 | [diff] [blame^] | 252 | _MESSAGES_IMPORT, b'import "split_common_messages.proto";') |
| 253 | .replace( |
| 254 | _SPLIT_NAMESPACE, |
| 255 | b'package grpc_protoc_plugin.invocation_testing.split_common;')) |
| 256 | open(messages_proto_file, 'wb').write( |
| 257 | messages_proto_contents.replace( |
| 258 | _SPLIT_NAMESPACE, |
| 259 | b'package grpc_protoc_plugin.invocation_testing.split_common;')) |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 260 | protoc_result = protoc.main([ |
| 261 | '', |
| 262 | '--proto_path={}'.format(self.proto_directory), |
| 263 | '--python_out={}'.format(self.python_out_directory), |
| 264 | '--grpc_python_out={}'.format(self.grpc_python_out_directory), |
| 265 | services_proto_file, |
| 266 | messages_proto_file, |
| 267 | ]) |
| 268 | if protoc_result != 0: |
| 269 | raise Exception("unexpected protoc error") |
| 270 | open(os.path.join(self.python_out_directory, '__init__.py'), |
| 271 | 'w').write('') |
| 272 | self.pb2_import = 'split_common_messages_pb2' |
| 273 | self.pb2_grpc_import = 'split_common_services_pb2_grpc' |
| 274 | self.should_find_services_in_pb2 = False |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 275 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 276 | def tearDown(self): |
| 277 | shutil.rmtree(self.directory) |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 278 | |
| 279 | |
| 280 | class SplitSeparateTest(unittest.TestCase, SeparateTestMixin): |
| 281 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 282 | def setUp(self): |
| 283 | services_proto_contents = pkgutil.get_data( |
| 284 | 'tests.protoc_plugin.protos.invocation_testing.split_services', |
| 285 | 'services.proto') |
| 286 | messages_proto_contents = pkgutil.get_data( |
| 287 | 'tests.protoc_plugin.protos.invocation_testing.split_messages', |
| 288 | 'messages.proto') |
| 289 | self.directory = tempfile.mkdtemp(suffix='split_separate', dir='.') |
| 290 | self.proto_directory = os.path.join(self.directory, 'proto_path') |
| 291 | self.python_out_directory = os.path.join(self.directory, 'python_out') |
| 292 | self.grpc_python_out_directory = os.path.join(self.directory, |
| 293 | 'grpc_python_out') |
| 294 | os.makedirs(self.proto_directory) |
| 295 | os.makedirs(self.python_out_directory) |
| 296 | os.makedirs(self.grpc_python_out_directory) |
| 297 | services_proto_file = os.path.join(self.proto_directory, |
| 298 | 'split_separate_services.proto') |
| 299 | messages_proto_file = os.path.join(self.proto_directory, |
| 300 | 'split_separate_messages.proto') |
| 301 | open(services_proto_file, 'wb').write( |
| 302 | services_proto_contents.replace( |
Ken Payson | dbf571e | 2017-02-09 14:10:03 -0800 | [diff] [blame^] | 303 | _MESSAGES_IMPORT, b'import "split_separate_messages.proto";') |
| 304 | .replace( |
| 305 | _SPLIT_NAMESPACE, |
| 306 | b'package grpc_protoc_plugin.invocation_testing.split_separate;' |
| 307 | )) |
| 308 | open(messages_proto_file, 'wb').write( |
| 309 | messages_proto_contents.replace( |
| 310 | _SPLIT_NAMESPACE, |
| 311 | b'package grpc_protoc_plugin.invocation_testing.split_separate;' |
| 312 | )) |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 313 | protoc_result = protoc.main([ |
| 314 | '', |
| 315 | '--proto_path={}'.format(self.proto_directory), |
| 316 | '--python_out={}'.format(self.python_out_directory), |
| 317 | '--grpc_python_out=grpc_2_0:{}'.format( |
| 318 | self.grpc_python_out_directory), |
| 319 | services_proto_file, |
| 320 | messages_proto_file, |
| 321 | ]) |
| 322 | if protoc_result != 0: |
| 323 | raise Exception("unexpected protoc error") |
| 324 | open(os.path.join(self.python_out_directory, '__init__.py'), |
| 325 | 'w').write('') |
| 326 | self.pb2_import = 'split_separate_messages_pb2' |
| 327 | self.pb2_grpc_import = 'split_separate_services_pb2_grpc' |
| 328 | self.should_find_services_in_pb2 = False |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 329 | |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 330 | def tearDown(self): |
| 331 | shutil.rmtree(self.directory) |
Masood Malekghassemi | d953959 | 2016-10-20 14:47:14 -0700 | [diff] [blame] | 332 | |
| 333 | |
| 334 | if __name__ == '__main__': |
Masood Malekghassemi | cc79370 | 2017-01-13 19:20:10 -0800 | [diff] [blame] | 335 | unittest.main(verbosity=2) |