protoc_test.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. # Copyright 2020 The gRPC authors.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Tests for protoc."""
  15. from __future__ import absolute_import
  16. from __future__ import division
  17. from __future__ import print_function
  18. import contextlib
  19. import functools
  20. import multiprocessing
  21. import sys
  22. import unittest
  23. # TODO(https://github.com/grpc/grpc/issues/23847): Deduplicate this mechanism with
  24. # the grpcio_tests module.
  25. def _wrap_in_subprocess(error_queue, fn):
  26. @functools.wraps(fn)
  27. def _wrapped():
  28. try:
  29. fn()
  30. except Exception as e:
  31. error_queue.put(e)
  32. raise
  33. return _wrapped
  34. def _run_in_subprocess(test_case):
  35. error_queue = multiprocessing.Queue()
  36. wrapped_case = _wrap_in_subprocess(error_queue, test_case)
  37. proc = multiprocessing.Process(target=wrapped_case)
  38. proc.start()
  39. proc.join()
  40. if not error_queue.empty():
  41. raise error_queue.get()
  42. assert proc.exitcode == 0, "Process exited with code {}".format(
  43. proc.exitcode)
  44. @contextlib.contextmanager
  45. def _augmented_syspath(new_paths):
  46. original_sys_path = sys.path
  47. if new_paths is not None:
  48. sys.path = list(new_paths) + sys.path
  49. try:
  50. yield
  51. finally:
  52. sys.path = original_sys_path
  53. def _test_import_protos():
  54. from grpc_tools import protoc
  55. with _augmented_syspath(
  56. ("tools/distrib/python/grpcio_tools/grpc_tools/test/",)):
  57. protos = protoc._protos("simple.proto")
  58. assert protos.SimpleMessage is not None
  59. def _test_import_services():
  60. from grpc_tools import protoc
  61. with _augmented_syspath(
  62. ("tools/distrib/python/grpcio_tools/grpc_tools/test/",)):
  63. protos = protoc._protos("simple.proto")
  64. services = protoc._services("simple.proto")
  65. assert services.SimpleMessageServiceStub is not None
  66. def _test_import_services_without_protos():
  67. from grpc_tools import protoc
  68. with _augmented_syspath(
  69. ("tools/distrib/python/grpcio_tools/grpc_tools/test/",)):
  70. services = protoc._services("simple.proto")
  71. assert services.SimpleMessageServiceStub is not None
  72. def _test_proto_module_imported_once():
  73. from grpc_tools import protoc
  74. with _augmented_syspath(
  75. ("tools/distrib/python/grpcio_tools/grpc_tools/test/",)):
  76. protos = protoc._protos("simple.proto")
  77. services = protoc._services("simple.proto")
  78. complicated_protos = protoc._protos("complicated.proto")
  79. simple_message = protos.SimpleMessage()
  80. complicated_message = complicated_protos.ComplicatedMessage()
  81. assert (simple_message.simpler_message.simplest_message.__class__ is
  82. complicated_message.simplest_message.__class__)
  83. def _test_static_dynamic_combo():
  84. with _augmented_syspath(
  85. ("tools/distrib/python/grpcio_tools/grpc_tools/test/",)):
  86. from grpc_tools import protoc # isort:skip
  87. import complicated_pb2
  88. protos = protoc._protos("simple.proto")
  89. static_message = complicated_pb2.ComplicatedMessage()
  90. dynamic_message = protos.SimpleMessage()
  91. assert (dynamic_message.simpler_message.simplest_message.__class__ is
  92. static_message.simplest_message.__class__)
  93. def _test_combined_import():
  94. from grpc_tools import protoc
  95. protos, services = protoc._protos_and_services("simple.proto")
  96. assert protos.SimpleMessage is not None
  97. assert services.SimpleMessageServiceStub is not None
  98. def _test_syntax_errors():
  99. from grpc_tools import protoc
  100. try:
  101. protos = protoc._protos("flawed.proto")
  102. except Exception as e:
  103. error_str = str(e)
  104. assert "flawed.proto" in error_str
  105. assert "17:23" in error_str
  106. assert "21:23" in error_str
  107. else:
  108. assert False, "Compile error expected. None occurred."
  109. class ProtocTest(unittest.TestCase):
  110. def test_import_protos(self):
  111. _run_in_subprocess(_test_import_protos)
  112. def test_import_services(self):
  113. _run_in_subprocess(_test_import_services)
  114. def test_import_services_without_protos(self):
  115. _run_in_subprocess(_test_import_services_without_protos)
  116. def test_proto_module_imported_once(self):
  117. _run_in_subprocess(_test_proto_module_imported_once)
  118. def test_static_dynamic_combo(self):
  119. _run_in_subprocess(_test_static_dynamic_combo)
  120. def test_combined_import(self):
  121. _run_in_subprocess(_test_combined_import)
  122. def test_syntax_errors(self):
  123. _run_in_subprocess(_test_syntax_errors)
  124. if __name__ == '__main__':
  125. unittest.main()