diff options
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/grpcio/.gitignore | 7 | ||||
-rw-r--r-- | src/python/grpcio/MANIFEST.in | 1 | ||||
-rw-r--r-- | src/python/grpcio/commands.py | 127 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/module.c | 67 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types.c | 61 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types.h | 286 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/call.c | 186 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c | 203 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/channel.c | 187 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c | 165 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c | 124 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/server.c | 196 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c | 137 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_c/utility.c | 524 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_implementations.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_c_test.py) | 33 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_intermediary_low.py | 45 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_low.py | 214 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_adapter/_types.py | 94 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/call.pyx | 28 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx | 31 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx | 11 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd | 23 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx | 82 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd | 59 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/records.pxd | 1 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/records.pyx | 82 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/_cygrpc/server.pyx | 2 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/adapter_low.py | 102 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_cython/cygrpc.pyx | 6 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_links/invocation.py | 12 | ||||
-rw-r--r-- | src/python/grpcio/grpc/_links/service.py | 6 | ||||
-rw-r--r-- | src/python/grpcio/grpc/beta/_server.py | 175 | ||||
-rw-r--r-- | src/python/grpcio/grpc/beta/_stub.py | 124 | ||||
-rw-r--r-- | src/python/grpcio/grpc/beta/implementations.py | 96 | ||||
-rw-r--r-- | src/python/grpcio/grpc/beta/interfaces.py | 49 | ||||
-rw-r--r-- | src/python/grpcio/grpc/framework/core/_end.py | 60 | ||||
-rw-r--r-- | src/python/grpcio/requirements.txt | 1 | ||||
-rw-r--r-- | src/python/grpcio/setup.cfg | 6 | ||||
-rw-r--r-- | src/python/grpcio/setup.py | 129 | ||||
-rw-r--r-- | src/python/grpcio/tests/__init__.py (renamed from src/python/grpcio_test/setup.py) | 68 | ||||
-rw-r--r-- | src/python/grpcio/tests/_loader.py | 119 | ||||
-rw-r--r-- | src/python/grpcio/tests/_result.py | 451 | ||||
-rw-r--r-- | src/python/grpcio/tests/_runner.py | 224 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/__init__.py (renamed from src/python/grpcio_test/grpc_interop/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/_insecure_interop_test.py (renamed from src/python/grpcio_test/grpc_interop/_insecure_interop_test.py) | 8 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/_interop_test_case.py (renamed from src/python/grpcio_test/grpc_interop/_interop_test_case.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/_secure_interop_test.py (renamed from src/python/grpcio_test/grpc_interop/_secure_interop_test.py) | 12 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/client.py (renamed from src/python/grpcio_test/grpc_interop/client.py) | 15 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/credentials/README (renamed from src/python/grpcio_test/grpc_interop/credentials/README) | 0 | ||||
-rwxr-xr-x | src/python/grpcio/tests/interop/credentials/ca.pem (renamed from src/python/grpcio_test/grpc_interop/credentials/ca.pem) | 0 | ||||
-rwxr-xr-x | src/python/grpcio/tests/interop/credentials/server1.key (renamed from src/python/grpcio_test/grpc_interop/credentials/server1.key) | 0 | ||||
-rwxr-xr-x | src/python/grpcio/tests/interop/credentials/server1.pem (renamed from src/python/grpcio_test/grpc_interop/credentials/server1.pem) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/empty.proto (renamed from src/python/grpcio_test/grpc_interop/empty.proto) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/messages.proto (renamed from src/python/grpcio_test/grpc_interop/messages.proto) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/methods.py (renamed from src/python/grpcio_test/grpc_interop/methods.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/resources.py (renamed from src/python/grpcio_test/grpc_interop/resources.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/server.py (renamed from src/python/grpcio_test/grpc_interop/server.py) | 8 | ||||
-rw-r--r-- | src/python/grpcio/tests/interop/test.proto (renamed from src/python/grpcio_test/grpc_interop/test.proto) | 4 | ||||
-rw-r--r-- | src/python/grpcio/tests/protoc_plugin/__init__.py (renamed from src/python/grpcio_test/grpc_protoc_plugin/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py (renamed from src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py) | 73 | ||||
-rw-r--r-- | src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto (renamed from src/python/grpcio_test/grpc_protoc_plugin/test.proto) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/__init__.py (renamed from src/python/grpcio_test/grpc_test/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_adapter/.gitignore (renamed from src/python/grpcio_test/grpc_test/_adapter/.gitignore) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_adapter/__init__.py (renamed from src/python/grpcio_test/grpc_test/_adapter/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py) | 14 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_adapter/_low_test.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_low_test.py) | 10 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py (renamed from src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py) | 8 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py (renamed from src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py) | 8 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_cython/.gitignore (renamed from src/python/grpcio_test/grpc_test/_cython/.gitignore) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_cython/__init__.py (renamed from src/python/grpcio_test/grpc_test/_cython/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_cython/cygrpc_test.py (renamed from src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py) | 194 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_cython/test_utilities.py (renamed from src/python/grpcio_test/grpc_test/_cython/test_utilities.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_junkdrawer/__init__.py (renamed from src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py (renamed from src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py (renamed from src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_links/__init__.py (renamed from src/python/grpcio_test/grpc_test/_links/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py (renamed from src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_links/_proto_scenarios.py (renamed from src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py) | 4 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/_links/_transmission_test.py (renamed from src/python/grpcio_test/grpc_test/_links/_transmission_test.py) | 10 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/__init__.py (renamed from src/python/grpcio_test/grpc_test/beta/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/_beta_features_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_beta_features_test.py) | 133 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/_face_interface_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_face_interface_test.py) | 16 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/_not_found_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_not_found_test.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/_utilities_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_utilities_test.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/beta/test_utilities.py (renamed from src/python/grpcio_test/grpc_test/beta/test_utilities.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/credentials/README (renamed from src/python/grpcio_test/grpc_test/credentials/README) | 0 | ||||
-rwxr-xr-x | src/python/grpcio/tests/unit/credentials/ca.pem (renamed from src/python/grpcio_test/grpc_test/credentials/ca.pem) | 0 | ||||
-rwxr-xr-x | src/python/grpcio/tests/unit/credentials/server1.key (renamed from src/python/grpcio_test/grpc_test/credentials/server1.key) | 0 | ||||
-rwxr-xr-x | src/python/grpcio/tests/unit/credentials/server1.pem (renamed from src/python/grpcio_test/grpc_test/credentials/server1.pem) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py (renamed from src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py) | 8 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/common/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/common/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/common/test_constants.py (renamed from src/python/grpcio_test/grpc_test/framework/common/test_constants.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/common/test_control.py (renamed from src/python/grpcio_test/grpc_test/framework/common/test_control.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/common/test_coverage.py (renamed from src/python/grpcio_test/grpc_test/framework/common/test_coverage.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/core/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/core/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/core/_base_interface_test.py (renamed from src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/face/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/base_util.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py) | 12 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/callback.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/callback.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/control.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/control.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/coverage.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/digest.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/digest.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py) | 14 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py) | 12 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/interfaces.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/service.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/service.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/stock_service.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py) | 4 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/face/testing/test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/foundation/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/foundation/_later_test.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/foundation/stream_testing.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/base/_control.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py) | 8 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/base/_state.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py) | 7 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py) | 14 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py) | 16 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py) | 14 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py) | 2 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py) | 6 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py) | 14 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py) | 4 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/resources.py (renamed from src/python/grpcio_test/grpc_test/resources.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tests/unit/test_common.py (renamed from src/python/grpcio_test/grpc_test/test_common.py) | 0 | ||||
-rw-r--r-- | src/python/grpcio/tox.ini | 19 | ||||
-rw-r--r-- | src/python/grpcio_test/.gitignore | 12 | ||||
-rw-r--r-- | src/python/grpcio_test/MANIFEST.in | 4 | ||||
-rw-r--r-- | src/python/grpcio_test/commands.py | 106 | ||||
-rw-r--r-- | src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py | 187 | ||||
-rw-r--r-- | src/python/grpcio_test/grpc_test/conftest.py | 60 | ||||
-rw-r--r-- | src/python/grpcio_test/requirements.txt | 6 | ||||
-rw-r--r-- | src/python/grpcio_test/setup.cfg | 2 |
149 files changed, 2470 insertions, 3238 deletions
diff --git a/src/python/grpcio/.gitignore b/src/python/grpcio/.gitignore index 4c02b8d14d..95b96f7c1e 100644 --- a/src/python/grpcio/.gitignore +++ b/src/python/grpcio/.gitignore @@ -5,5 +5,12 @@ dist/ *.egg *.egg/ *.eggs/ +*_pb2.py +.coverage +.coverage.* +.cache/ +.tox/ +nosetests.xml doc/ _grpcio_metadata.py +htmlcov/ diff --git a/src/python/grpcio/MANIFEST.in b/src/python/grpcio/MANIFEST.in index 9583dc7768..407eeabc17 100644 --- a/src/python/grpcio/MANIFEST.in +++ b/src/python/grpcio/MANIFEST.in @@ -1,3 +1,4 @@ graft grpc +graft tests include commands.py include requirements.txt diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py index 8a2f2d6283..d9fd023b21 100644 --- a/src/python/grpcio/commands.py +++ b/src/python/grpcio/commands.py @@ -29,14 +29,18 @@ """Provides distutils command classes for the GRPC Python setup process.""" +import distutils import os import os.path +import re +import subprocess import sys import setuptools from setuptools.command import build_py +from setuptools.command import test -_CONF_PY_ADDENDUM = """ +CONF_PY_ADDENDUM = """ extensions.append('sphinx.ext.napoleon') napoleon_google_docstring = True napoleon_numpy_docstring = True @@ -48,7 +52,7 @@ html_theme = 'sphinx_rtd_theme' class SphinxDocumentation(setuptools.Command): """Command to generate documentation via sphinx.""" - description = '' + description = 'generate sphinx documentation' user_options = [] def initialize_options(self): @@ -72,14 +76,61 @@ class SphinxDocumentation(setuptools.Command): '-o', os.path.join('doc', 'src'), src_dir]) conf_filepath = os.path.join('doc', 'src', 'conf.py') with open(conf_filepath, 'a') as conf_file: - conf_file.write(_CONF_PY_ADDENDUM) + conf_file.write(CONF_PY_ADDENDUM) sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')]) +class BuildProtoModules(setuptools.Command): + """Command to generate project *_pb2.py modules from proto files.""" + + description = 'build protobuf modules' + user_options = [ + ('include=', None, 'path patterns to include in protobuf generation'), + ('exclude=', None, 'path patterns to exclude from protobuf generation') + ] + + def initialize_options(self): + self.exclude = None + self.include = r'.*\.proto$' + self.protoc_command = None + self.grpc_python_plugin_command = None + + def finalize_options(self): + self.protoc_command = distutils.spawn.find_executable('protoc') + self.grpc_python_plugin_command = distutils.spawn.find_executable( + 'grpc_python_plugin') + + def run(self): + include_regex = re.compile(self.include) + exclude_regex = re.compile(self.exclude) if self.exclude else None + paths = [] + root_directory = os.getcwd() + for walk_root, directories, filenames in os.walk(root_directory): + for filename in filenames: + path = os.path.join(walk_root, filename) + if include_regex.match(path) and not ( + exclude_regex and exclude_regex.match(path)): + paths.append(path) + command = [ + self.protoc_command, + '--plugin=protoc-gen-python-grpc={}'.format( + self.grpc_python_plugin_command), + '-I {}'.format(root_directory), + '--python_out={}'.format(root_directory), + '--python-grpc_out={}'.format(root_directory), + ] + paths + try: + subprocess.check_output(' '.join(command), cwd=root_directory, shell=True, + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + raise Exception('Command:\n{}\nMessage:\n{}\nOutput:\n{}'.format( + command, e.message, e.output)) + + class BuildProjectMetadata(setuptools.Command): """Command to generate project metadata in a module.""" - description = '' + description = 'build grpcio project metadata files' user_options = [] def initialize_options(self): @@ -98,5 +149,73 @@ class BuildPy(build_py.build_py): """Custom project build command.""" def run(self): + self.run_command('build_proto_modules') self.run_command('build_project_metadata') build_py.build_py.run(self) + + +class Gather(setuptools.Command): + """Command to gather project dependencies.""" + + description = 'gather dependencies for grpcio' + user_options = [ + ('test', 't', 'flag indicating to gather test dependencies'), + ('install', 'i', 'flag indicating to gather install dependencies') + ] + + def initialize_options(self): + self.test = False + self.install = False + + def finalize_options(self): + # distutils requires this override. + pass + + def run(self): + if self.install and self.distribution.install_requires: + self.distribution.fetch_build_eggs(self.distribution.install_requires) + if self.test and self.distribution.tests_require: + self.distribution.fetch_build_eggs(self.distribution.tests_require) + + +class RunInterop(test.test): + + description = 'run interop test client/server' + user_options = [ + ('args=', 'a', 'pass-thru arguments for the client/server'), + ('client', 'c', 'flag indicating to run the client'), + ('server', 's', 'flag indicating to run the server') + ] + + def initialize_options(self): + self.args = '' + self.client = False + self.server = False + + def finalize_options(self): + if self.client and self.server: + raise DistutilsOptionError('you may only specify one of client or server') + + def run(self): + if self.distribution.install_requires: + self.distribution.fetch_build_eggs(self.distribution.install_requires) + if self.distribution.tests_require: + self.distribution.fetch_build_eggs(self.distribution.tests_require) + if self.client: + self.run_client() + elif self.server: + self.run_server() + + def run_server(self): + # We import here to ensure that our setuptools parent has had a chance to + # edit the Python system path. + from tests.interop import server + sys.argv[1:] = self.args.split() + server.serve() + + def run_client(self): + # We import here to ensure that our setuptools parent has had a chance to + # edit the Python system path. + from tests.interop import client + sys.argv[1:] = self.args.split() + client.test_interoperability() diff --git a/src/python/grpcio/grpc/_adapter/_c/module.c b/src/python/grpcio/grpc/_adapter/_c/module.c deleted file mode 100644 index 9b93b051f6..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/module.c +++ /dev/null @@ -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. - * - */ - -#include <stdlib.h> - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> - -#include "grpc/_adapter/_c/types.h" - -static PyMethodDef c_methods[] = { - {NULL} -}; - -PyMODINIT_FUNC init_c(void) { - PyObject *module; - - module = Py_InitModule3("_c", c_methods, - "Wrappings of C structures and functions."); - - if (pygrpc_module_add_types(module) < 0) { - return; - } - - if (PyModule_AddStringConstant( - module, "PRIMARY_USER_AGENT_KEY", - GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) { - return; - } - - /* GRPC maintains an internal counter of how many times it has been - initialized and handles multiple pairs of grpc_init()/grpc_shutdown() - invocations accordingly. */ - grpc_init(); - atexit(&grpc_shutdown); -} diff --git a/src/python/grpcio/grpc/_adapter/_c/types.c b/src/python/grpcio/grpc/_adapter/_c/types.c deleted file mode 100644 index 8dedf5902b..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types.c +++ /dev/null @@ -1,61 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> - -int pygrpc_module_add_types(PyObject *module) { - int i; - PyTypeObject *types[] = { - &pygrpc_CallCredentials_type, - &pygrpc_ChannelCredentials_type, - &pygrpc_ServerCredentials_type, - &pygrpc_CompletionQueue_type, - &pygrpc_Call_type, - &pygrpc_Channel_type, - &pygrpc_Server_type - }; - for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) { - if (PyType_Ready(types[i]) < 0) { - return -1; - } - } - for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) { - Py_INCREF(types[i]); - PyModule_AddObject(module, types[i]->tp_name, (PyObject *)types[i]); - } - return 0; -} diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h deleted file mode 100644 index 9ab415d216..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types.h +++ /dev/null @@ -1,286 +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. - * - */ - -#ifndef GRPC__ADAPTER__C_TYPES_H_ -#define GRPC__ADAPTER__C_TYPES_H_ - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/grpc_security.h> - - -/*=========================*/ -/* Client-side credentials */ -/*=========================*/ - -typedef struct ChannelCredentials { - PyObject_HEAD - grpc_channel_credentials *c_creds; -} ChannelCredentials; -void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self); -ChannelCredentials *pygrpc_ChannelCredentials_google_default( - PyTypeObject *type, PyObject *ignored); -ChannelCredentials *pygrpc_ChannelCredentials_ssl( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -ChannelCredentials *pygrpc_ChannelCredentials_composite( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -extern PyTypeObject pygrpc_ChannelCredentials_type; - -typedef struct CallCredentials { - PyObject_HEAD - grpc_call_credentials *c_creds; -} CallCredentials; -void pygrpc_CallCredentials_dealloc(CallCredentials *self); -CallCredentials *pygrpc_CallCredentials_composite( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -CallCredentials *pygrpc_CallCredentials_compute_engine( - PyTypeObject *type, PyObject *ignored); -CallCredentials *pygrpc_CallCredentials_jwt( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -CallCredentials *pygrpc_CallCredentials_refresh_token( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -CallCredentials *pygrpc_CallCredentials_iam( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -extern PyTypeObject pygrpc_CallCredentials_type; - -/*=========================*/ -/* Server-side credentials */ -/*=========================*/ - -typedef struct ServerCredentials { - PyObject_HEAD - grpc_server_credentials *c_creds; -} ServerCredentials; -void pygrpc_ServerCredentials_dealloc(ServerCredentials *self); -ServerCredentials *pygrpc_ServerCredentials_ssl( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -extern PyTypeObject pygrpc_ServerCredentials_type; - - -/*==================*/ -/* Completion queue */ -/*==================*/ - -typedef struct CompletionQueue { - PyObject_HEAD - grpc_completion_queue *c_cq; -} CompletionQueue; -CompletionQueue *pygrpc_CompletionQueue_new( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -void pygrpc_CompletionQueue_dealloc(CompletionQueue *self); -PyObject *pygrpc_CompletionQueue_next( - CompletionQueue *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_CompletionQueue_shutdown( - CompletionQueue *self, PyObject *ignored); -extern PyTypeObject pygrpc_CompletionQueue_type; - - -/*======*/ -/* Call */ -/*======*/ - -typedef struct Call { - PyObject_HEAD - grpc_call *c_call; - CompletionQueue *cq; -} Call; -Call *pygrpc_Call_new_empty(CompletionQueue *cq); -void pygrpc_Call_dealloc(Call *self); -PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_Call_peer(Call *self); -PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args, - PyObject *kwargs); -extern PyTypeObject pygrpc_Call_type; - - -/*=========*/ -/* Channel */ -/*=========*/ - -typedef struct Channel { - PyObject_HEAD - grpc_channel *c_chan; -} Channel; -Channel *pygrpc_Channel_new( - PyTypeObject *type, PyObject *args, PyObject *kwargs); -void pygrpc_Channel_dealloc(Channel *self); -Call *pygrpc_Channel_create_call( - Channel *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_Channel_check_connectivity_state(Channel *self, PyObject *args, - PyObject *kwargs); -PyObject *pygrpc_Channel_watch_connectivity_state(Channel *self, PyObject *args, - PyObject *kwargs); -PyObject *pygrpc_Channel_target(Channel *self); -extern PyTypeObject pygrpc_Channel_type; - - -/*========*/ -/* Server */ -/*========*/ - -typedef struct Server { - PyObject_HEAD - grpc_server *c_serv; - CompletionQueue *cq; - int shutdown_called; -} Server; -Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs); -void pygrpc_Server_dealloc(Server *self); -PyObject *pygrpc_Server_request_call( - Server *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_Server_add_http2_port( - Server *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_Server_start(Server *self, PyObject *ignored); -PyObject *pygrpc_Server_shutdown( - Server *self, PyObject *args, PyObject *kwargs); -PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused); -extern PyTypeObject pygrpc_Server_type; - -/*=========*/ -/* Utility */ -/*=========*/ - -/* Every tag that passes from Python GRPC to GRPC core is of this type. */ -typedef struct pygrpc_tag { - PyObject *user_tag; - Call *call; - grpc_call_details request_call_details; - grpc_metadata_array request_metadata; - grpc_op *ops; - size_t nops; - int is_new_call; -} pygrpc_tag; - -/* Construct a tag associated with a batch call. Does not take ownership of the - resources in the elements of ops. */ -pygrpc_tag *pygrpc_produce_batch_tag(PyObject *user_tag, Call *call, - grpc_op *ops, size_t nops); - - -/* Construct a tag associated with a server request. The calling code should - use the appropriate fields of the produced tag in the invocation of - grpc_server_request_call. */ -pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call); - -/* Construct a tag associated with a server shutdown. */ -pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag); - -/* Construct a tag associated with a channel state change. */ -pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag); - -/* Frees all resources owned by the tag and the tag itself. */ -void pygrpc_discard_tag(pygrpc_tag *tag); - -/* Consumes an event and its associated tag, providing a Python tuple of the - form `(type, tag, call, call_details, results)` (where type is an integer - corresponding to a grpc_completion_type, tag is an arbitrary PyObject, call - is the call object associated with the event [if any], call_details is a - tuple of form `(method, host, deadline)` [if such details are available], - and resultd is a list of tuples of form `(type, metadata, message, status, - cancelled)` [where type corresponds to a grpc_op_type, metadata is a - sequence of 2-sequences of strings, message is a byte string, and status is - a 2-tuple of an integer corresponding to grpc_status_code and a string of - status details]). - - Frees all resources associated with the event tag. */ -PyObject *pygrpc_consume_event(grpc_event event); - -/* Transliterate the Python tuple of form `(type, metadata, message, - status)` (where type is an integer corresponding to a grpc_op_type, metadata - is a sequence of 2-sequences of strings, message is a byte string, and - status is 2-tuple of an integer corresponding to grpc_status_code and a - string of status details) to a grpc_op suitable for use in a - grpc_call_start_batch invocation. The grpc_op is a 'directory' of resources - that must be freed after GRPC core is done with them. - - Calls gpr_malloc (or the appropriate type-specific grpc_*_create function) - to populate the appropriate union-discriminated members of the op. - - Returns true on success, false on failure. */ -int pygrpc_produce_op(PyObject *op, grpc_op *result); - -/* Discards all resources associated with the passed in op that was produced by - pygrpc_produce_op. */ -void pygrpc_discard_op(grpc_op op); - -/* Transliterate the grpc_ops (which have been sent through a - grpc_call_start_batch invocation and whose corresponding event has appeared - on a completion queue) to a Python tuple of form `(type, metadata, message, - status, cancelled)` (where type is an integer corresponding to a - grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a - byte string, and status is 2-tuple of an integer corresponding to - grpc_status_code and a string of status details). - - Calls gpr_free (or the appropriate type-specific grpc_*_destroy function) on - the appropriate union-discriminated populated members of the ops. */ -PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops); - -/* Transliterate from a gpr_timespec to a double (in units of seconds, either - from the epoch if interpreted absolutely or as a delta otherwise). */ -double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec); - -/* Transliterate from a double (in units of seconds from the epoch if - interpreted absolutely or as a delta otherwise) to a gpr_timespec. */ -gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds); - -/* Returns true on success, false on failure. */ -int pygrpc_cast_pyseq_to_send_metadata( - PyObject *pyseq, grpc_metadata **metadata, size_t *count); -/* Returns a metadata array as a Python object on success, else NULL. */ -PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata); - -/* Transliterate from a list of python channel arguments (2-tuples of string - and string|integer|None) to a grpc_channel_args object. The strings placed - in the grpc_channel_args object's grpc_arg elements are views of the Python - object. The Python object must live long enough for the grpc_channel_args - to be used. Arguments set to None are silently ignored. Returns true on - success, false on failure. */ -int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args); -void pygrpc_discard_channel_args(grpc_channel_args args); - -/* Read the bytes from grpc_byte_buffer to a gpr_malloc'd array of bytes; - output to result and result_size. */ -void pygrpc_byte_buffer_to_bytes( - grpc_byte_buffer *buffer, char **result, size_t *result_size); - - -/*========*/ -/* Module */ -/*========*/ - -/* Returns 0 on success, -1 on failure. */ -int pygrpc_module_add_types(PyObject *module); - -#endif /* GRPC__ADAPTER__C_TYPES_H_ */ diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c deleted file mode 100644 index 04ec871880..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/call.c +++ /dev/null @@ -1,186 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/support/alloc.h> - - -PyMethodDef pygrpc_Call_methods[] = { - {"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""}, - {"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""}, - {"peer", (PyCFunction)pygrpc_Call_peer, METH_NOARGS, ""}, - {"set_credentials", (PyCFunction)pygrpc_Call_set_credentials, METH_KEYWORDS, - ""}, - {NULL} -}; -const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call."; -PyTypeObject pygrpc_Call_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "Call", /* tp_name */ - sizeof(Call), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_Call_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_Call_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_Call_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0 /* tp_new */ -}; - -Call *pygrpc_Call_new_empty(CompletionQueue *cq) { - Call *call = (Call *)pygrpc_Call_type.tp_alloc(&pygrpc_Call_type, 0); - call->c_call = NULL; - call->cq = cq; - Py_XINCREF(call->cq); - return call; -} -void pygrpc_Call_dealloc(Call *self) { - if (self->c_call) { - grpc_call_destroy(self->c_call); - } - Py_XDECREF(self->cq); - self->ob_type->tp_free((PyObject *)self); -} -PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs) { - PyObject *op_list; - PyObject *user_tag; - grpc_op *ops; - size_t nops; - size_t i; - size_t j; - pygrpc_tag *tag; - grpc_call_error errcode; - static char *keywords[] = {"ops", "tag", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:start_batch", keywords, - &op_list, &user_tag)) { - return NULL; - } - if (!PyList_Check(op_list)) { - PyErr_SetString(PyExc_TypeError, "expected a list of OpArgs"); - return NULL; - } - nops = PyList_Size(op_list); - ops = gpr_malloc(sizeof(grpc_op) * nops); - for (i = 0; i < nops; ++i) { - PyObject *item = PyList_GET_ITEM(op_list, i); - if (!pygrpc_produce_op(item, &ops[i])) { - for (j = 0; j < i; ++j) { - pygrpc_discard_op(ops[j]); - } - return NULL; - } - } - tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops); - errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag, NULL); - gpr_free(ops); - return PyInt_FromLong(errcode); -} -PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) { - PyObject *py_code = NULL; - grpc_call_error errcode; - int code; - char *details = NULL; - static char *keywords[] = {"code", "details", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:start_batch", keywords, - &py_code, &details)) { - return NULL; - } - if (py_code != NULL && details != NULL) { - if (!PyInt_Check(py_code)) { - PyErr_SetString(PyExc_TypeError, "expected integer code"); - return NULL; - } - code = PyInt_AsLong(py_code); - errcode = grpc_call_cancel_with_status(self->c_call, code, details, NULL); - } else if (py_code != NULL || details != NULL) { - PyErr_SetString(PyExc_ValueError, - "if `code` is specified, so must `details`"); - return NULL; - } else { - errcode = grpc_call_cancel(self->c_call, NULL); - } - return PyInt_FromLong(errcode); -} - -PyObject *pygrpc_Call_peer(Call *self) { - char *peer = grpc_call_get_peer(self->c_call); - PyObject *py_peer = PyString_FromString(peer); - gpr_free(peer); - return py_peer; -} -PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args, - PyObject *kwargs) { - CallCredentials *creds; - grpc_call_error errcode; - static char *keywords[] = {"creds", NULL}; - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "O!:set_credentials", keywords, - &pygrpc_CallCredentials_type, &creds)) { - return NULL; - } - errcode = grpc_call_set_credentials(self->c_call, creds->c_creds); - return PyInt_FromLong(errcode); -} diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c deleted file mode 100644 index 5a15a6e17d..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c +++ /dev/null @@ -1,203 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/grpc_security.h> - - -PyMethodDef pygrpc_CallCredentials_methods[] = { - {"composite", (PyCFunction)pygrpc_CallCredentials_composite, - METH_CLASS|METH_KEYWORDS, ""}, - {"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine, - METH_CLASS|METH_NOARGS, ""}, - {"jwt", (PyCFunction)pygrpc_CallCredentials_jwt, - METH_CLASS|METH_KEYWORDS, ""}, - {"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token, - METH_CLASS|METH_KEYWORDS, ""}, - {"iam", (PyCFunction)pygrpc_CallCredentials_iam, - METH_CLASS|METH_KEYWORDS, ""}, - {NULL} -}; - -const char pygrpc_CallCredentials_doc[] = ""; -PyTypeObject pygrpc_CallCredentials_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "CallCredentials", /* tp_name */ - sizeof(CallCredentials), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_CallCredentials_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_CallCredentials_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_CallCredentials_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0 /* tp_new */ -}; - -void pygrpc_CallCredentials_dealloc(CallCredentials *self) { - grpc_call_credentials_release(self->c_creds); - self->ob_type->tp_free((PyObject *)self); -} - -CallCredentials *pygrpc_CallCredentials_composite( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - CallCredentials *self; - CallCredentials *creds1; - CallCredentials *creds2; - static char *keywords[] = {"creds1", "creds2", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords, - &pygrpc_CallCredentials_type, &creds1, - &pygrpc_CallCredentials_type, &creds2)) { - return NULL; - } - self = (CallCredentials *)type->tp_alloc(type, 0); - self->c_creds = - grpc_composite_call_credentials_create( - creds1->c_creds, creds2->c_creds, NULL); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials"); - return NULL; - } - return self; -} - -CallCredentials *pygrpc_CallCredentials_compute_engine( - PyTypeObject *type, PyObject *ignored) { - CallCredentials *self = (CallCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_google_compute_engine_credentials_create(NULL); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, - "couldn't create compute engine credentials"); - return NULL; - } - return self; -} - -/* TODO: Rename this credentials to something like service_account_jwt_access */ -CallCredentials *pygrpc_CallCredentials_jwt( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - CallCredentials *self; - const char *json_key; - double lifetime; - static char *keywords[] = {"json_key", "token_lifetime", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd:jwt", keywords, - &json_key, &lifetime)) { - return NULL; - } - self = (CallCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_service_account_jwt_access_credentials_create( - json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials"); - return NULL; - } - return self; -} - -CallCredentials *pygrpc_CallCredentials_refresh_token( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - CallCredentials *self; - const char *json_refresh_token; - static char *keywords[] = {"json_refresh_token", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords, - &json_refresh_token)) { - return NULL; - } - self = (CallCredentials *)type->tp_alloc(type, 0); - self->c_creds = - grpc_google_refresh_token_credentials_create(json_refresh_token, NULL); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, - "couldn't create credentials from refresh token"); - return NULL; - } - return self; -} - -CallCredentials *pygrpc_CallCredentials_iam( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - CallCredentials *self; - const char *authorization_token; - const char *authority_selector; - static char *keywords[] = {"authorization_token", "authority_selector", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:iam", keywords, - &authorization_token, &authority_selector)) { - return NULL; - } - self = (CallCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_google_iam_credentials_create(authorization_token, - authority_selector, NULL); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials"); - return NULL; - } - return self; -} - diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c deleted file mode 100644 index c4db2a0dfd..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c +++ /dev/null @@ -1,187 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/support/alloc.h> - - -PyMethodDef pygrpc_Channel_methods[] = { - {"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""}, - {"check_connectivity_state", (PyCFunction)pygrpc_Channel_check_connectivity_state, METH_KEYWORDS, ""}, - {"watch_connectivity_state", (PyCFunction)pygrpc_Channel_watch_connectivity_state, METH_KEYWORDS, ""}, - {"target", (PyCFunction)pygrpc_Channel_target, METH_NOARGS, ""}, - {NULL} -}; -const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel."; -PyTypeObject pygrpc_Channel_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "Channel", /* tp_name */ - sizeof(Channel), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_Channel_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_Channel_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_Channel_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - (newfunc)pygrpc_Channel_new /* tp_new */ -}; - -Channel *pygrpc_Channel_new( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - Channel *self; - const char *target; - PyObject *py_args; - ChannelCredentials *creds = NULL; - grpc_channel_args c_args; - char *keywords[] = {"target", "args", "creds", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords, - &target, &py_args, &pygrpc_ChannelCredentials_type, &creds)) { - return NULL; - } - if (!pygrpc_produce_channel_args(py_args, &c_args)) { - return NULL; - } - self = (Channel *)type->tp_alloc(type, 0); - if (creds) { - self->c_chan = - grpc_secure_channel_create(creds->c_creds, target, &c_args, NULL); - } else { - self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL); - } - pygrpc_discard_channel_args(c_args); - return self; -} -void pygrpc_Channel_dealloc(Channel *self) { - grpc_channel_destroy(self->c_chan); - self->ob_type->tp_free((PyObject *)self); -} - -Call *pygrpc_Channel_create_call( - Channel *self, PyObject *args, PyObject *kwargs) { - Call *call; - CompletionQueue *cq; - const char *method; - const char *host; - double deadline; - char *keywords[] = {"cq", "method", "host", "deadline", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!szd:create_call", keywords, - &pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) { - return NULL; - } - call = pygrpc_Call_new_empty(cq); - call->c_call = grpc_channel_create_call( - self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host, - pygrpc_cast_double_to_gpr_timespec(deadline), NULL); - return call; -} - -PyObject *pygrpc_Channel_check_connectivity_state( - Channel *self, PyObject *args, PyObject *kwargs) { - PyObject *py_try_to_connect; - int try_to_connect; - char *keywords[] = {"try_to_connect", NULL}; - grpc_connectivity_state state; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:connectivity_state", keywords, - &py_try_to_connect)) { - return NULL; - } - if (!PyBool_Check(py_try_to_connect)) { - Py_XDECREF(py_try_to_connect); - return NULL; - } - try_to_connect = Py_True == py_try_to_connect; - Py_DECREF(py_try_to_connect); - state = grpc_channel_check_connectivity_state(self->c_chan, try_to_connect); - return PyInt_FromLong(state); -} - -PyObject *pygrpc_Channel_watch_connectivity_state( - Channel *self, PyObject *args, PyObject *kwargs) { - PyObject *tag; - double deadline; - int last_observed_state; - CompletionQueue *completion_queue; - char *keywords[] = {"last_observed_state", "deadline", - "completion_queue", "tag", NULL}; - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "idO!O:watch_connectivity_state", keywords, - &last_observed_state, &deadline, &pygrpc_CompletionQueue_type, - &completion_queue, &tag)) { - return NULL; - } - grpc_channel_watch_connectivity_state( - self->c_chan, (grpc_connectivity_state)last_observed_state, - pygrpc_cast_double_to_gpr_timespec(deadline), completion_queue->c_cq, - pygrpc_produce_channel_state_change_tag(tag)); - Py_RETURN_NONE; -} - -PyObject *pygrpc_Channel_target(Channel *self) { - char *target = grpc_channel_get_target(self->c_chan); - PyObject *py_target = PyString_FromString(target); - gpr_free(target); - return py_target; -} diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c deleted file mode 100644 index 83b1fc0406..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c +++ /dev/null @@ -1,165 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/grpc_security.h> - - -PyMethodDef pygrpc_ChannelCredentials_methods[] = { - {"google_default", (PyCFunction)pygrpc_ChannelCredentials_google_default, - METH_CLASS|METH_NOARGS, ""}, - {"ssl", (PyCFunction)pygrpc_ChannelCredentials_ssl, - METH_CLASS|METH_KEYWORDS, ""}, - {"composite", (PyCFunction)pygrpc_ChannelCredentials_composite, - METH_CLASS|METH_KEYWORDS, ""}, - {NULL} -}; - -const char pygrpc_ChannelCredentials_doc[] = ""; -PyTypeObject pygrpc_ChannelCredentials_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "ChannelCredentials", /* tp_name */ - sizeof(ChannelCredentials), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_ChannelCredentials_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_ChannelCredentials_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_ChannelCredentials_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0 /* tp_new */ -}; - -void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self) { - grpc_channel_credentials_release(self->c_creds); - self->ob_type->tp_free((PyObject *)self); -} - -ChannelCredentials *pygrpc_ChannelCredentials_google_default( - PyTypeObject *type, PyObject *ignored) { - ChannelCredentials *self = (ChannelCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_google_default_credentials_create(); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, - "couldn't create Google default credentials"); - return NULL; - } - return self; -} - -ChannelCredentials *pygrpc_ChannelCredentials_ssl( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ChannelCredentials *self; - const char *root_certs; - const char *private_key = NULL; - const char *cert_chain = NULL; - grpc_ssl_pem_key_cert_pair key_cert_pair; - static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords, - &root_certs, &private_key, &cert_chain)) { - return NULL; - } - self = (ChannelCredentials *)type->tp_alloc(type, 0); - if (private_key && cert_chain) { - key_cert_pair.private_key = private_key; - key_cert_pair.cert_chain = cert_chain; - self->c_creds = - grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL); - } else { - self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL); - } - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials"); - return NULL; - } - return self; -} - -ChannelCredentials *pygrpc_ChannelCredentials_composite( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ChannelCredentials *self; - ChannelCredentials *creds1; - CallCredentials *creds2; - static char *keywords[] = {"creds1", "creds2", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords, - &pygrpc_ChannelCredentials_type, &creds1, - &pygrpc_CallCredentials_type, &creds2)) { - return NULL; - } - self = (ChannelCredentials *)type->tp_alloc(type, 0); - self->c_creds = - grpc_composite_channel_credentials_create( - creds1->c_creds, creds2->c_creds, NULL); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString( - PyExc_RuntimeError, "couldn't create composite credentials"); - return NULL; - } - return self; -} - diff --git a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c deleted file mode 100644 index d8bb89ca4b..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c +++ /dev/null @@ -1,124 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> - - -PyMethodDef pygrpc_CompletionQueue_methods[] = { - {"next", (PyCFunction)pygrpc_CompletionQueue_next, METH_KEYWORDS, ""}, - {"shutdown", (PyCFunction)pygrpc_CompletionQueue_shutdown, METH_NOARGS, ""}, - {NULL} -}; -const char pygrpc_CompletionQueue_doc[] = - "See grpc._adapter._types.CompletionQueue."; -PyTypeObject pygrpc_CompletionQueue_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "CompletionQueue", /* tp_name */ - sizeof(CompletionQueue), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_CompletionQueue_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_CompletionQueue_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_CompletionQueue_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - (newfunc)pygrpc_CompletionQueue_new /* tp_new */ -}; - -CompletionQueue *pygrpc_CompletionQueue_new( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0); - self->c_cq = grpc_completion_queue_create(NULL); - return self; -} - -void pygrpc_CompletionQueue_dealloc(CompletionQueue *self) { - grpc_completion_queue_destroy(self->c_cq); - self->ob_type->tp_free((PyObject *)self); -} - -PyObject *pygrpc_CompletionQueue_next( - CompletionQueue *self, PyObject *args, PyObject *kwargs) { - double deadline; - grpc_event event; - PyObject *transliterated_event; - static char *keywords[] = {"deadline", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:next", keywords, - &deadline)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS; - event = grpc_completion_queue_next( - self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline), NULL); - Py_END_ALLOW_THREADS; - transliterated_event = pygrpc_consume_event(event); - return transliterated_event; -} - -PyObject *pygrpc_CompletionQueue_shutdown( - CompletionQueue *self, PyObject *ignored) { - grpc_completion_queue_shutdown(self->c_cq); - Py_RETURN_NONE; -} diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server.c b/src/python/grpcio/grpc/_adapter/_c/types/server.c deleted file mode 100644 index 8feab8aab1..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/server.c +++ /dev/null @@ -1,196 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> - - -PyMethodDef pygrpc_Server_methods[] = { - {"request_call", (PyCFunction)pygrpc_Server_request_call, - METH_KEYWORDS, ""}, - {"add_http2_port", (PyCFunction)pygrpc_Server_add_http2_port, - METH_KEYWORDS, ""}, - {"start", (PyCFunction)pygrpc_Server_start, METH_NOARGS, ""}, - {"shutdown", (PyCFunction)pygrpc_Server_shutdown, METH_KEYWORDS, ""}, - {"cancel_all_calls", (PyCFunction)pygrpc_Server_cancel_all_calls, - METH_NOARGS, ""}, - {NULL} -}; -const char pygrpc_Server_doc[] = "See grpc._adapter._types.Server."; -PyTypeObject pygrpc_Server_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "Server", /* tp_name */ - sizeof(Server), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_Server_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_Server_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_Server_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - (newfunc)pygrpc_Server_new /* tp_new */ -}; - -Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - Server *self; - CompletionQueue *cq; - PyObject *py_args; - grpc_channel_args c_args; - char *keywords[] = {"cq", "args", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Server", keywords, - &pygrpc_CompletionQueue_type, &cq, &py_args)) { - return NULL; - } - if (!pygrpc_produce_channel_args(py_args, &c_args)) { - return NULL; - } - self = (Server *)type->tp_alloc(type, 0); - self->c_serv = grpc_server_create(&c_args, NULL); - grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL); - pygrpc_discard_channel_args(c_args); - self->cq = cq; - Py_INCREF(self->cq); - self->shutdown_called = 0; - return self; -} - -void pygrpc_Server_dealloc(Server *self) { - grpc_server_destroy(self->c_serv); - Py_XDECREF(self->cq); - self->ob_type->tp_free((PyObject *)self); -} - -PyObject *pygrpc_Server_request_call( - Server *self, PyObject *args, PyObject *kwargs) { - CompletionQueue *cq; - PyObject *user_tag; - pygrpc_tag *tag; - Call *empty_call; - grpc_call_error errcode; - static char *keywords[] = {"cq", "tag", NULL}; - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "O!O", keywords, - &pygrpc_CompletionQueue_type, &cq, &user_tag)) { - return NULL; - } - empty_call = pygrpc_Call_new_empty(cq); - tag = pygrpc_produce_request_tag(user_tag, empty_call); - errcode = grpc_server_request_call( - self->c_serv, &tag->call->c_call, &tag->request_call_details, - &tag->request_metadata, tag->call->cq->c_cq, self->cq->c_cq, tag); - Py_DECREF(empty_call); - return PyInt_FromLong(errcode); -} - -PyObject *pygrpc_Server_add_http2_port( - Server *self, PyObject *args, PyObject *kwargs) { - const char *addr; - ServerCredentials *creds = NULL; - int port; - static char *keywords[] = {"addr", "creds", NULL}; - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "s|O!:add_http2_port", keywords, - &addr, &pygrpc_ServerCredentials_type, &creds)) { - return NULL; - } - if (creds) { - port = grpc_server_add_secure_http2_port( - self->c_serv, addr, creds->c_creds); - } else { - port = grpc_server_add_insecure_http2_port(self->c_serv, addr); - } - return PyInt_FromLong(port); - -} - -PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) { - grpc_server_start(self->c_serv); - self->shutdown_called = 0; - Py_RETURN_NONE; -} - -PyObject *pygrpc_Server_shutdown( - Server *self, PyObject *args, PyObject *kwargs) { - PyObject *user_tag; - pygrpc_tag *tag; - static char *keywords[] = {"tag", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &user_tag)) { - return NULL; - } - tag = pygrpc_produce_server_shutdown_tag(user_tag); - grpc_server_shutdown_and_notify(self->c_serv, self->cq->c_cq, tag); - self->shutdown_called = 1; - Py_RETURN_NONE; -} - -PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused) { - if (!self->shutdown_called) { - PyErr_SetString( - PyExc_RuntimeError, - "shutdown must have been called prior to calling cancel_all_calls!"); - return NULL; - } - grpc_server_cancel_all_calls(self->c_serv); - Py_RETURN_NONE; -} diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c deleted file mode 100644 index df51a99b6a..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c +++ /dev/null @@ -1,137 +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. - * - */ - -#include "grpc/_adapter/_c/types.h" - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/grpc_security.h> -#include <grpc/support/alloc.h> - - -PyMethodDef pygrpc_ServerCredentials_methods[] = { - {"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl, - METH_CLASS|METH_KEYWORDS, ""}, - {NULL} -}; -const char pygrpc_ServerCredentials_doc[] = ""; -PyTypeObject pygrpc_ServerCredentials_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "ServerCredentials", /* tp_name */ - sizeof(ServerCredentials), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pygrpc_ServerCredentials_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_ServerCredentials_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pygrpc_ServerCredentials_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0 /* tp_new */ -}; - -void pygrpc_ServerCredentials_dealloc(ServerCredentials *self) { - grpc_server_credentials_release(self->c_creds); - self->ob_type->tp_free((PyObject *)self); -} - -ServerCredentials *pygrpc_ServerCredentials_ssl( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ServerCredentials *self; - const char *root_certs; - PyObject *py_key_cert_pairs; - grpc_ssl_pem_key_cert_pair *key_cert_pairs; - int force_client_auth; - size_t num_key_cert_pairs; - size_t i; - static char *keywords[] = { - "root_certs", "key_cert_pairs", "force_client_auth", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zOi:ssl", keywords, - &root_certs, &py_key_cert_pairs, &force_client_auth)) { - return NULL; - } - if (!PyList_Check(py_key_cert_pairs)) { - PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings"); - return NULL; - } - num_key_cert_pairs = PyList_Size(py_key_cert_pairs); - key_cert_pairs = - gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs); - for (i = 0; i < num_key_cert_pairs; ++i) { - PyObject *item = PyList_GET_ITEM(py_key_cert_pairs, i); - const char *key; - const char *cert; - if (!PyArg_ParseTuple(item, "zz", &key, &cert)) { - gpr_free(key_cert_pairs); - PyErr_SetString(PyExc_TypeError, - "expected a list of 2-tuples of strings"); - return NULL; - } - key_cert_pairs[i].private_key = key; - key_cert_pairs[i].cert_chain = cert; - } - - self = (ServerCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_ssl_server_credentials_create( - root_certs, key_cert_pairs, num_key_cert_pairs, force_client_auth, NULL); - gpr_free(key_cert_pairs); - return self; -} diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c deleted file mode 100644 index 590f7e013a..0000000000 --- a/src/python/grpcio/grpc/_adapter/_c/utility.c +++ /dev/null @@ -1,524 +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. - * - */ - -#include <math.h> -#include <string.h> - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <grpc/grpc.h> -#include <grpc/byte_buffer_reader.h> -#include <grpc/support/alloc.h> -#include <grpc/support/slice.h> -#include <grpc/support/time.h> -#include <grpc/support/string_util.h> - -#include "grpc/_adapter/_c/types.h" - -pygrpc_tag *pygrpc_produce_batch_tag( - PyObject *user_tag, Call *call, grpc_op *ops, size_t nops) { - pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); - tag->user_tag = user_tag; - Py_XINCREF(tag->user_tag); - tag->call = call; - Py_XINCREF(tag->call); - tag->ops = gpr_malloc(sizeof(grpc_op)*nops); - memcpy(tag->ops, ops, sizeof(grpc_op)*nops); - tag->nops = nops; - grpc_call_details_init(&tag->request_call_details); - grpc_metadata_array_init(&tag->request_metadata); - tag->is_new_call = 0; - return tag; -} - -pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call) { - pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); - tag->user_tag = user_tag; - Py_XINCREF(tag->user_tag); - tag->call = empty_call; - Py_XINCREF(tag->call); - tag->ops = NULL; - tag->nops = 0; - grpc_call_details_init(&tag->request_call_details); - grpc_metadata_array_init(&tag->request_metadata); - tag->is_new_call = 1; - return tag; -} - -pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag) { - pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); - tag->user_tag = user_tag; - Py_XINCREF(tag->user_tag); - tag->call = NULL; - tag->ops = NULL; - tag->nops = 0; - grpc_call_details_init(&tag->request_call_details); - grpc_metadata_array_init(&tag->request_metadata); - tag->is_new_call = 0; - return tag; -} - -pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag) { - pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); - tag->user_tag = user_tag; - Py_XINCREF(tag->user_tag); - tag->call = NULL; - tag->ops = NULL; - tag->nops = 0; - grpc_call_details_init(&tag->request_call_details); - grpc_metadata_array_init(&tag->request_metadata); - tag->is_new_call = 0; - return tag; -} - -void pygrpc_discard_tag(pygrpc_tag *tag) { - if (!tag) { - return; - } - Py_XDECREF(tag->user_tag); - Py_XDECREF(tag->call); - gpr_free(tag->ops); - grpc_call_details_destroy(&tag->request_call_details); - grpc_metadata_array_destroy(&tag->request_metadata); - gpr_free(tag); -} - -PyObject *pygrpc_consume_event(grpc_event event) { - pygrpc_tag *tag; - PyObject *result; - if (event.type == GRPC_QUEUE_TIMEOUT) { - Py_RETURN_NONE; - } - tag = event.tag; - switch (event.type) { - case GRPC_QUEUE_SHUTDOWN: - result = Py_BuildValue("iOOOOO", GRPC_QUEUE_SHUTDOWN, - Py_None, Py_None, Py_None, Py_None, Py_True); - break; - case GRPC_OP_COMPLETE: - if (tag->is_new_call) { - result = Py_BuildValue( - "iOO(ssd)[(iNOOOO)]O", GRPC_OP_COMPLETE, tag->user_tag, tag->call, - tag->request_call_details.method, tag->request_call_details.host, - pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline), - GRPC_OP_RECV_INITIAL_METADATA, - pygrpc_cast_metadata_array_to_pyseq(tag->request_metadata), Py_None, - Py_None, Py_None, Py_None, - event.success ? Py_True : Py_False); - } else { - result = Py_BuildValue("iOOONO", GRPC_OP_COMPLETE, tag->user_tag, - tag->call ? (PyObject*)tag->call : Py_None, Py_None, - pygrpc_consume_ops(tag->ops, tag->nops), - event.success ? Py_True : Py_False); - } - break; - default: - PyErr_SetString(PyExc_ValueError, - "unknown completion type; could not translate event"); - return NULL; - } - pygrpc_discard_tag(tag); - return result; -} - -int pygrpc_produce_op(PyObject *op, grpc_op *result) { - static const int OP_TUPLE_SIZE = 6; - static const int STATUS_TUPLE_SIZE = 2; - static const int TYPE_INDEX = 0; - static const int INITIAL_METADATA_INDEX = 1; - static const int TRAILING_METADATA_INDEX = 2; - static const int MESSAGE_INDEX = 3; - static const int STATUS_INDEX = 4; - static const int STATUS_CODE_INDEX = 0; - static const int STATUS_DETAILS_INDEX = 1; - static const int WRITE_FLAGS_INDEX = 5; - int type; - Py_ssize_t message_size; - char *message; - char *status_details; - gpr_slice message_slice; - grpc_op c_op; - if (!PyTuple_Check(op)) { - PyErr_SetString(PyExc_TypeError, "expected tuple op"); - return 0; - } - if (PyTuple_Size(op) != OP_TUPLE_SIZE) { - char *buf; - gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE); - PyErr_SetString(PyExc_ValueError, buf); - gpr_free(buf); - return 0; - } - type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX)); - if (PyErr_Occurred()) { - return 0; - } - c_op.op = type; - c_op.reserved = NULL; - c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX)); - if (PyErr_Occurred()) { - return 0; - } - switch (type) { - case GRPC_OP_SEND_INITIAL_METADATA: - if (!pygrpc_cast_pyseq_to_send_metadata( - PyTuple_GetItem(op, INITIAL_METADATA_INDEX), - &c_op.data.send_initial_metadata.metadata, - &c_op.data.send_initial_metadata.count)) { - return 0; - } - break; - case GRPC_OP_SEND_MESSAGE: - PyString_AsStringAndSize( - PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size); - message_slice = gpr_slice_from_copied_buffer(message, message_size); - c_op.data.send_message = grpc_raw_byte_buffer_create(&message_slice, 1); - gpr_slice_unref(message_slice); - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - /* Don't need to fill in any other fields. */ - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - if (!pygrpc_cast_pyseq_to_send_metadata( - PyTuple_GetItem(op, TRAILING_METADATA_INDEX), - &c_op.data.send_status_from_server.trailing_metadata, - &c_op.data.send_status_from_server.trailing_metadata_count)) { - return 0; - } - if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) { - char *buf; - gpr_asprintf(&buf, "expected tuple status in op of length %d", - STATUS_TUPLE_SIZE); - PyErr_SetString(PyExc_ValueError, buf); - gpr_free(buf); - return 0; - } - c_op.data.send_status_from_server.status = PyInt_AsLong( - PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX)); - status_details = PyString_AsString( - PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX)); - if (PyErr_Occurred()) { - return 0; - } - c_op.data.send_status_from_server.status_details = - gpr_malloc(strlen(status_details) + 1); - strcpy((char *)c_op.data.send_status_from_server.status_details, - status_details); - break; - case GRPC_OP_RECV_INITIAL_METADATA: - c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array)); - grpc_metadata_array_init(c_op.data.recv_initial_metadata); - break; - case GRPC_OP_RECV_MESSAGE: - c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *)); - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - c_op.data.recv_status_on_client.trailing_metadata = - gpr_malloc(sizeof(grpc_metadata_array)); - grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata); - c_op.data.recv_status_on_client.status = - gpr_malloc(sizeof(grpc_status_code *)); - c_op.data.recv_status_on_client.status_details = - gpr_malloc(sizeof(char *)); - *c_op.data.recv_status_on_client.status_details = NULL; - c_op.data.recv_status_on_client.status_details_capacity = - gpr_malloc(sizeof(size_t)); - *c_op.data.recv_status_on_client.status_details_capacity = 0; - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int)); - break; - default: - return 0; - } - *result = c_op; - return 1; -} - -void pygrpc_discard_op(grpc_op op) { - size_t i; - switch(op.op) { - case GRPC_OP_SEND_INITIAL_METADATA: - /* Whenever we produce send-metadata, we allocate new strings (to handle - arbitrary sequence input as opposed to just lists or just tuples). We - thus must free those elements. */ - for (i = 0; i < op.data.send_initial_metadata.count; ++i) { - gpr_free((void *)op.data.send_initial_metadata.metadata[i].key); - gpr_free((void *)op.data.send_initial_metadata.metadata[i].value); - } - gpr_free(op.data.send_initial_metadata.metadata); - break; - case GRPC_OP_SEND_MESSAGE: - grpc_byte_buffer_destroy(op.data.send_message); - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - /* Don't need to free any fields. */ - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - /* Whenever we produce send-metadata, we allocate new strings (to handle - arbitrary sequence input as opposed to just lists or just tuples). We - thus must free those elements. */ - for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count; - ++i) { - gpr_free( - (void *)op.data.send_status_from_server.trailing_metadata[i].key); - gpr_free( - (void *)op.data.send_status_from_server.trailing_metadata[i].value); - } - gpr_free(op.data.send_status_from_server.trailing_metadata); - gpr_free((char *)op.data.send_status_from_server.status_details); - break; - case GRPC_OP_RECV_INITIAL_METADATA: - grpc_metadata_array_destroy(op.data.recv_initial_metadata); - gpr_free(op.data.recv_initial_metadata); - break; - case GRPC_OP_RECV_MESSAGE: - grpc_byte_buffer_destroy(*op.data.recv_message); - gpr_free(op.data.recv_message); - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - grpc_metadata_array_destroy(op.data.recv_status_on_client.trailing_metadata); - gpr_free(op.data.recv_status_on_client.trailing_metadata); - gpr_free(op.data.recv_status_on_client.status); - gpr_free(*op.data.recv_status_on_client.status_details); - gpr_free(op.data.recv_status_on_client.status_details); - gpr_free(op.data.recv_status_on_client.status_details_capacity); - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - gpr_free(op.data.recv_close_on_server.cancelled); - break; - } -} - -PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) { - static const int TYPE_INDEX = 0; - static const int INITIAL_METADATA_INDEX = 1; - static const int TRAILING_METADATA_INDEX = 2; - static const int MESSAGE_INDEX = 3; - static const int STATUS_INDEX = 4; - static const int CANCELLED_INDEX = 5; - static const int OPRESULT_LENGTH = 6; - PyObject *list; - size_t i; - size_t j; - char *bytes; - size_t bytes_size; - PyObject *results = PyList_New(nops); - if (!results) { - return NULL; - } - for (i = 0; i < nops; ++i) { - PyObject *result = PyTuple_Pack(OPRESULT_LENGTH, Py_None, Py_None, Py_None, - Py_None, Py_None, Py_None); - PyTuple_SetItem(result, TYPE_INDEX, PyInt_FromLong(op[i].op)); - switch(op[i].op) { - case GRPC_OP_RECV_INITIAL_METADATA: - PyTuple_SetItem(result, INITIAL_METADATA_INDEX, - list=PyList_New(op[i].data.recv_initial_metadata->count)); - for (j = 0; j < op[i].data.recv_initial_metadata->count; ++j) { - grpc_metadata md = op[i].data.recv_initial_metadata->metadata[j]; - PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value, - (Py_ssize_t)md.value_length)); - } - break; - case GRPC_OP_RECV_MESSAGE: - if (*op[i].data.recv_message) { - pygrpc_byte_buffer_to_bytes( - *op[i].data.recv_message, &bytes, &bytes_size); - PyTuple_SetItem(result, MESSAGE_INDEX, - PyString_FromStringAndSize(bytes, bytes_size)); - gpr_free(bytes); - } else { - PyTuple_SetItem(result, MESSAGE_INDEX, Py_BuildValue("")); - } - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - PyTuple_SetItem( - result, TRAILING_METADATA_INDEX, - list = PyList_New(op[i].data.recv_status_on_client.trailing_metadata->count)); - for (j = 0; j < op[i].data.recv_status_on_client.trailing_metadata->count; ++j) { - grpc_metadata md = - op[i].data.recv_status_on_client.trailing_metadata->metadata[j]; - PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value, - (Py_ssize_t)md.value_length)); - } - PyTuple_SetItem( - result, STATUS_INDEX, Py_BuildValue( - "is", *op[i].data.recv_status_on_client.status, - *op[i].data.recv_status_on_client.status_details)); - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - PyTuple_SetItem( - result, CANCELLED_INDEX, - PyBool_FromLong(*op[i].data.recv_close_on_server.cancelled)); - break; - default: - break; - } - pygrpc_discard_op(op[i]); - PyList_SetItem(results, i, result); - } - return results; -} - -double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) { - timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME); - return timespec.tv_sec + 1e-9*timespec.tv_nsec; -} - -/* Because C89 doesn't have a way to check for infinity... */ -static int pygrpc_isinf(double x) { - return x * 0 != 0; -} - -gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) { - gpr_timespec result; - if (pygrpc_isinf(seconds)) { - result = seconds > 0.0 ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_inf_past(GPR_CLOCK_REALTIME); - } else { - result.tv_sec = (time_t)seconds; - result.tv_nsec = ((seconds - result.tv_sec) * 1e9); - result.clock_type = GPR_CLOCK_REALTIME; - } - return result; -} - -int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args) { - size_t num_args = PyList_Size(py_args); - size_t i; - grpc_channel_args args; - args.num_args = num_args; - args.args = gpr_malloc(sizeof(grpc_arg) * num_args); - for (i = 0; i < args.num_args; ++i) { - char *key; - PyObject *value; - if (!PyArg_ParseTuple(PyList_GetItem(py_args, i), "zO", &key, &value)) { - gpr_free(args.args); - args.num_args = 0; - args.args = NULL; - PyErr_SetString(PyExc_TypeError, - "expected a list of 2-tuple of str and str|int|None"); - return 0; - } - args.args[i].key = key; - if (PyInt_Check(value)) { - args.args[i].type = GRPC_ARG_INTEGER; - args.args[i].value.integer = PyInt_AsLong(value); - } else if (PyString_Check(value)) { - args.args[i].type = GRPC_ARG_STRING; - args.args[i].value.string = PyString_AsString(value); - } else if (value == Py_None) { - --args.num_args; - --i; - continue; - } else { - gpr_free(args.args); - args.num_args = 0; - args.args = NULL; - PyErr_SetString(PyExc_TypeError, - "expected a list of 2-tuple of str and str|int|None"); - return 0; - } - } - *c_args = args; - return 1; -} - -void pygrpc_discard_channel_args(grpc_channel_args args) { - gpr_free(args.args); -} - -int pygrpc_cast_pyseq_to_send_metadata( - PyObject *pyseq, grpc_metadata **metadata, size_t *count) { - size_t i; - Py_ssize_t value_length; - char *key; - char *value; - if (!PySequence_Check(pyseq)) { - return 0; - } - *count = PySequence_Size(pyseq); - *metadata = gpr_malloc(sizeof(grpc_metadata) * *count); - for (i = 0; i < *count; ++i) { - PyObject *item = PySequence_GetItem(pyseq, i); - if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) { - Py_DECREF(item); - gpr_free(*metadata); - *count = 0; - *metadata = NULL; - return 0; - } else { - (*metadata)[i].key = gpr_strdup(key); - (*metadata)[i].value = gpr_malloc(value_length); - memcpy((void *)(*metadata)[i].value, value, value_length); - Py_DECREF(item); - } - (*metadata)[i].value_length = value_length; - } - return 1; -} - -PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) { - PyObject *result = PyTuple_New(metadata.count); - size_t i; - for (i = 0; i < metadata.count; ++i) { - PyTuple_SetItem( - result, i, Py_BuildValue( - "ss#", metadata.metadata[i].key, metadata.metadata[i].value, - (Py_ssize_t)metadata.metadata[i].value_length)); - if (PyErr_Occurred()) { - Py_DECREF(result); - return NULL; - } - } - return result; -} - -void pygrpc_byte_buffer_to_bytes( - grpc_byte_buffer *buffer, char **result, size_t *result_size) { - grpc_byte_buffer_reader reader; - gpr_slice slice; - char *read_result = NULL; - size_t size = 0; - grpc_byte_buffer_reader_init(&reader, buffer); - while (grpc_byte_buffer_reader_next(&reader, &slice)) { - read_result = gpr_realloc(read_result, size + GPR_SLICE_LENGTH(slice)); - memcpy(read_result + size, GPR_SLICE_START_PTR(slice), - GPR_SLICE_LENGTH(slice)); - size = size + GPR_SLICE_LENGTH(slice); - gpr_slice_unref(slice); - } - *result_size = size; - *result = read_result; -} diff --git a/src/python/grpcio_test/grpc_test/_adapter/_c_test.py b/src/python/grpcio/grpc/_adapter/_implementations.py index fe020e2a9c..b85f228bf6 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/_c_test.py +++ b/src/python/grpcio/grpc/_adapter/_implementations.py @@ -27,29 +27,22 @@ # (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 time -import unittest +import collections -from grpc._adapter import _c -from grpc._adapter import _types +from grpc.beta import interfaces +class AuthMetadataContext(collections.namedtuple( + 'AuthMetadataContext', [ + 'service_url', + 'method_name' + ]), interfaces.GRPCAuthMetadataContext): + pass -class CTypeSmokeTest(unittest.TestCase): - def testCompletionQueueUpDown(self): - completion_queue = _c.CompletionQueue() - del completion_queue +class AuthMetadataPluginCallback(interfaces.GRPCAuthMetadataContext): - def testServerUpDown(self): - completion_queue = _c.CompletionQueue() - serv = _c.Server(completion_queue, []) - del serv - del completion_queue + def __init__(self, callback): + self._callback = callback - def testChannelUpDown(self): - channel = _c.Channel('[::]:0', []) - del channel - - -if __name__ == '__main__': - unittest.main(verbosity=2) + def __call__(self, metadata, error): + self._callback(metadata, error) diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py index 5634c2024d..9698ffeabf 100644 --- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py +++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py @@ -115,16 +115,20 @@ class Call(object): return call def invoke(self, completion_queue, metadata_tag, finish_tag): - err0 = self._internal.start_batch([ + err = self._internal.start_batch([ _types.OpArgs.send_initial_metadata(self._metadata) ], _IGNORE_ME_TAG) - err1 = self._internal.start_batch([ + if err != _types.CallError.OK: + return err + err = self._internal.start_batch([ _types.OpArgs.recv_initial_metadata() ], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED)) - err2 = self._internal.start_batch([ + if err != _types.CallError.OK: + return err + err = self._internal.start_batch([ _types.OpArgs.recv_status_on_client() ], _TagAdapter(finish_tag, Event.Kind.FINISH)) - return err0 if err0 != _types.CallError.OK else err1 if err1 != _types.CallError.OK else err2 if err2 != _types.CallError.OK else _types.CallError.OK + return err def write(self, message, tag, flags): return self._internal.start_batch([ @@ -158,7 +162,8 @@ class Call(object): def status(self, status, tag): return self._internal.start_batch([ - _types.OpArgs.send_status_from_server(self._metadata, status.code, status.details) + _types.OpArgs.send_status_from_server( + self._metadata, status.code, status.details) ], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED)) def cancel(self): @@ -168,20 +173,17 @@ class Call(object): return self._internal.peer() def set_credentials(self, creds): - return self._internal.set_credentials(creds._internal) + return self._internal.set_credentials(creds) class Channel(object): """Adapter from old _low.Channel interface to new _low.Channel.""" - def __init__(self, hostport, client_credentials, server_host_override=None): + def __init__(self, hostport, channel_credentials, server_host_override=None): args = [] if server_host_override: args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override)) - creds = None - if client_credentials: - creds = client_credentials._internal - self._internal = _low.Channel(hostport, args, creds) + self._internal = _low.Channel(hostport, args, channel_credentials) class CompletionQueue(object): @@ -192,7 +194,7 @@ class CompletionQueue(object): def get(self, deadline=None): if deadline is None: - ev = self._internal.next() + ev = self._internal.next(float('+inf')) else: ev = self._internal.next(deadline) if ev is None: @@ -240,7 +242,7 @@ class Server(object): if server_credentials is None: return self._internal.add_http2_port(addr, None) else: - return self._internal.add_http2_port(addr, server_credentials._internal) + return self._internal.add_http2_port(addr, server_credentials) def start(self): return self._internal.start() @@ -248,20 +250,9 @@ class Server(object): def service(self, tag): return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED)) + def cancel_all_calls(self): + self._internal.cancel_all_calls() + def stop(self): return self._internal.shutdown(_TagAdapter(None, Event.Kind.STOP)) - -class ClientCredentials(object): - """Adapter from old _low.ClientCredentials interface to new _low.ChannelCredentials.""" - - def __init__(self, root_certificates, private_key, certificate_chain): - self._internal = _low.ChannelCredentials.ssl(root_certificates, private_key, certificate_chain) - - -class ServerCredentials(object): - """Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials.""" - - def __init__(self, root_credentials, pair_sequence, force_client_auth): - self._internal = _low.ServerCredentials.ssl( - root_credentials, list(pair_sequence), force_client_auth) diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py index 57146aaefe..b13d8dd9dd 100644 --- a/src/python/grpcio/grpc/_adapter/_low.py +++ b/src/python/grpcio/grpc/_adapter/_low.py @@ -27,36 +27,157 @@ # (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 threading + from grpc import _grpcio_metadata -from grpc._adapter import _c +from grpc._cython import cygrpc +from grpc._adapter import _implementations from grpc._adapter import _types _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__) -ChannelCredentials = _c.ChannelCredentials -CallCredentials = _c.CallCredentials -ServerCredentials = _c.ServerCredentials +ChannelCredentials = cygrpc.ChannelCredentials +CallCredentials = cygrpc.CallCredentials +ServerCredentials = cygrpc.ServerCredentials + +channel_credentials_composite = cygrpc.channel_credentials_composite +call_credentials_composite = cygrpc.call_credentials_composite + +def server_credentials_ssl(root_credentials, pair_sequence, force_client_auth): + return cygrpc.server_credentials_ssl( + root_credentials, + [cygrpc.SslPemKeyCertPair(key, pem) for key, pem in pair_sequence], + force_client_auth) + +def channel_credentials_ssl( + root_certificates, private_key, certificate_chain): + pair = None + if private_key is not None or certificate_chain is not None: + pair = cygrpc.SslPemKeyCertPair(private_key, certificate_chain) + return cygrpc.channel_credentials_ssl(root_certificates, pair) + + +class _WrappedCygrpcCallback(object): + + def __init__(self, cygrpc_callback): + self.is_called = False + self.error = None + self.is_called_lock = threading.Lock() + self.cygrpc_callback = cygrpc_callback + + def _invoke_failure(self, error): + # TODO(atash) translate different Exception superclasses into different + # status codes. + self.cygrpc_callback( + cygrpc.Metadata([]), cygrpc.StatusCode.internal, error.message) + + def _invoke_success(self, metadata): + try: + cygrpc_metadata = cygrpc.Metadata( + cygrpc.Metadatum(key, value) + for key, value in metadata) + except Exception as error: + self._invoke_failure(error) + return + self.cygrpc_callback(cygrpc_metadata, cygrpc.StatusCode.ok, '') + + def __call__(self, metadata, error): + with self.is_called_lock: + if self.is_called: + raise RuntimeError('callback should only ever be invoked once') + if self.error: + self._invoke_failure(self.error) + return + self.is_called = True + if error is None: + self._invoke_success(metadata) + else: + self._invoke_failure(error) + + def notify_failure(self, error): + with self.is_called_lock: + if not self.is_called: + self.error = error + + +class _WrappedPlugin(object): + + def __init__(self, plugin): + self.plugin = plugin + + def __call__(self, context, cygrpc_callback): + wrapped_cygrpc_callback = _WrappedCygrpcCallback(cygrpc_callback) + wrapped_context = _implementations.AuthMetadataContext(context.service_url, + context.method_name) + try: + self.plugin( + wrapped_context, + _implementations.AuthMetadataPluginCallback(wrapped_cygrpc_callback)) + except Exception as error: + wrapped_cygrpc_callback.notify_failure(error) + raise + + +def call_credentials_metadata_plugin(plugin, name): + """ + Args: + plugin: A callable accepting a _types.AuthMetadataContext + object and a callback (itself accepting a list of metadata key/value + 2-tuples and a None-able exception value). The callback must be eventually + called, but need not be called in plugin's invocation. + plugin's invocation must be non-blocking. + """ + return cygrpc.call_credentials_metadata_plugin( + cygrpc.CredentialsMetadataPlugin(_WrappedPlugin(plugin), name)) class CompletionQueue(_types.CompletionQueue): def __init__(self): - self.completion_queue = _c.CompletionQueue() + self.completion_queue = cygrpc.CompletionQueue() def next(self, deadline=float('+inf')): - raw_event = self.completion_queue.next(deadline) - if raw_event is None: + raw_event = self.completion_queue.poll(cygrpc.Timespec(deadline)) + if raw_event.type == cygrpc.CompletionType.queue_timeout: return None - event = _types.Event(*raw_event) - if event.call is not None: - event = event._replace(call=Call(event.call)) - if event.call_details is not None: - event = event._replace(call_details=_types.CallDetails(*event.call_details)) - if event.results is not None: - new_results = [_types.OpResult(*r) for r in event.results] - new_results = [r if r.status is None else r._replace(status=_types.Status(_types.StatusCode(r.status[0]), r.status[1])) for r in new_results] - event = event._replace(results=new_results) - return event + event_type = raw_event.type + event_tag = raw_event.tag + event_call = Call(raw_event.operation_call) + if raw_event.request_call_details: + event_call_details = _types.CallDetails( + raw_event.request_call_details.method, + raw_event.request_call_details.host, + float(raw_event.request_call_details.deadline)) + else: + event_call_details = None + event_success = raw_event.success + event_results = [] + if raw_event.is_new_request: + event_results.append(_types.OpResult( + _types.OpType.RECV_INITIAL_METADATA, raw_event.request_metadata, + None, None, None, None)) + else: + if raw_event.batch_operations: + for operation in raw_event.batch_operations: + result_type = operation.type + result_initial_metadata = operation.received_metadata_or_none + result_trailing_metadata = operation.received_metadata_or_none + result_message = operation.received_message_or_none + if result_message is not None: + result_message = result_message.bytes() + result_cancelled = operation.received_cancelled_or_none + if operation.has_status: + result_status = _types.Status( + operation.received_status_code_or_none, + operation.received_status_details_or_none) + else: + result_status = None + event_results.append( + _types.OpResult(result_type, result_initial_metadata, + result_trailing_metadata, result_message, + result_status, result_cancelled)) + return _types.Event(event_type, event_tag, event_call, event_call_details, + event_results, event_success) def shutdown(self): self.completion_queue.shutdown() @@ -68,7 +189,36 @@ class Call(_types.Call): self.call = call def start_batch(self, ops, tag): - return self.call.start_batch(ops, tag) + translated_ops = [] + for op in ops: + if op.type == _types.OpType.SEND_INITIAL_METADATA: + translated_op = cygrpc.operation_send_initial_metadata( + cygrpc.Metadata( + cygrpc.Metadatum(key, value) + for key, value in op.initial_metadata)) + elif op.type == _types.OpType.SEND_MESSAGE: + translated_op = cygrpc.operation_send_message(op.message) + elif op.type == _types.OpType.SEND_CLOSE_FROM_CLIENT: + translated_op = cygrpc.operation_send_close_from_client() + elif op.type == _types.OpType.SEND_STATUS_FROM_SERVER: + translated_op = cygrpc.operation_send_status_from_server( + cygrpc.Metadata( + cygrpc.Metadatum(key, value) + for key, value in op.trailing_metadata), + op.status.code, + op.status.details) + elif op.type == _types.OpType.RECV_INITIAL_METADATA: + translated_op = cygrpc.operation_receive_initial_metadata() + elif op.type == _types.OpType.RECV_MESSAGE: + translated_op = cygrpc.operation_receive_message() + elif op.type == _types.OpType.RECV_STATUS_ON_CLIENT: + translated_op = cygrpc.operation_receive_status_on_client() + elif op.type == _types.OpType.RECV_CLOSE_ON_SERVER: + translated_op = cygrpc.operation_receive_close_on_server() + else: + raise ValueError('unexpected operation type {}'.format(op.type)) + translated_ops.append(translated_op) + return self.call.start_batch(cygrpc.Operations(translated_ops), tag) def cancel(self, code=None, details=None): if code is None and details is None: @@ -86,14 +236,20 @@ class Call(_types.Call): class Channel(_types.Channel): def __init__(self, target, args, creds=None): - args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)] + args = list(args) + [ + (cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT)] + args = cygrpc.ChannelArgs( + cygrpc.ChannelArg(key, value) for key, value in args) if creds is None: - self.channel = _c.Channel(target, args) + self.channel = cygrpc.Channel(target, args) else: - self.channel = _c.Channel(target, args, creds) + self.channel = cygrpc.Channel(target, args, creds) def create_call(self, completion_queue, method, host, deadline=None): - return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline)) + internal_call = self.channel.create_call( + None, 0, completion_queue.completion_queue, method, host, + cygrpc.Timespec(deadline)) + return Call(internal_call) def check_connectivity_state(self, try_to_connect): return self.channel.check_connectivity_state(try_to_connect) @@ -101,7 +257,8 @@ class Channel(_types.Channel): def watch_connectivity_state(self, last_observed_state, deadline, completion_queue, tag): self.channel.watch_connectivity_state( - last_observed_state, deadline, completion_queue.completion_queue, tag) + last_observed_state, cygrpc.Timespec(deadline), + completion_queue.completion_queue, tag) def target(self): return self.channel.target() @@ -112,7 +269,11 @@ _NO_TAG = object() class Server(_types.Server): def __init__(self, completion_queue, args): - self.server = _c.Server(completion_queue.completion_queue, args) + args = cygrpc.ChannelArgs( + cygrpc.ChannelArg(key, value) for key, value in args) + self.server = cygrpc.Server(args) + self.server.register_completion_queue(completion_queue.completion_queue) + self.server_queue = completion_queue def add_http2_port(self, addr, creds=None): if creds is None: @@ -124,10 +285,11 @@ class Server(_types.Server): return self.server.start() def shutdown(self, tag=None): - return self.server.shutdown(tag) + return self.server.shutdown(self.server_queue.completion_queue, tag) def request_call(self, completion_queue, tag): - return self.server.request_call(completion_queue.completion_queue, tag) + return self.server.request_call(completion_queue.completion_queue, + self.server_queue.completion_queue, tag) def cancel_all_calls(self): return self.server.cancel_all_calls() diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py index ca0fa066bc..3d5ab33d00 100644 --- a/src/python/grpcio/grpc/_adapter/_types.py +++ b/src/python/grpcio/grpc/_adapter/_types.py @@ -31,6 +31,8 @@ import abc import collections import enum +from grpc._cython import cygrpc + class GrpcChannelArgumentKeys(enum.Enum): """Mirrors keys used in grpc_channel_args for GRPC-specific arguments.""" @@ -40,77 +42,77 @@ class GrpcChannelArgumentKeys(enum.Enum): @enum.unique class CallError(enum.IntEnum): """Mirrors grpc_call_error in the C core.""" - OK = 0 - ERROR = 1 - ERROR_NOT_ON_SERVER = 2 - ERROR_NOT_ON_CLIENT = 3 - ERROR_ALREADY_ACCEPTED = 4 - ERROR_ALREADY_INVOKED = 5 - ERROR_NOT_INVOKED = 6 - ERROR_ALREADY_FINISHED = 7 - ERROR_TOO_MANY_OPERATIONS = 8 - ERROR_INVALID_FLAGS = 9 - ERROR_INVALID_METADATA = 10 + OK = cygrpc.CallError.ok + ERROR = cygrpc.CallError.error + ERROR_NOT_ON_SERVER = cygrpc.CallError.not_on_server + ERROR_NOT_ON_CLIENT = cygrpc.CallError.not_on_client + ERROR_ALREADY_ACCEPTED = cygrpc.CallError.already_accepted + ERROR_ALREADY_INVOKED = cygrpc.CallError.already_invoked + ERROR_NOT_INVOKED = cygrpc.CallError.not_invoked + ERROR_ALREADY_FINISHED = cygrpc.CallError.already_finished + ERROR_TOO_MANY_OPERATIONS = cygrpc.CallError.too_many_operations + ERROR_INVALID_FLAGS = cygrpc.CallError.invalid_flags + ERROR_INVALID_METADATA = cygrpc.CallError.invalid_metadata @enum.unique class StatusCode(enum.IntEnum): """Mirrors grpc_status_code in the C core.""" - OK = 0 - CANCELLED = 1 - UNKNOWN = 2 - INVALID_ARGUMENT = 3 - DEADLINE_EXCEEDED = 4 - NOT_FOUND = 5 - ALREADY_EXISTS = 6 - PERMISSION_DENIED = 7 - RESOURCE_EXHAUSTED = 8 - FAILED_PRECONDITION = 9 - ABORTED = 10 - OUT_OF_RANGE = 11 - UNIMPLEMENTED = 12 - INTERNAL = 13 - UNAVAILABLE = 14 - DATA_LOSS = 15 - UNAUTHENTICATED = 16 + OK = cygrpc.StatusCode.ok + CANCELLED = cygrpc.StatusCode.cancelled + UNKNOWN = cygrpc.StatusCode.unknown + INVALID_ARGUMENT = cygrpc.StatusCode.invalid_argument + DEADLINE_EXCEEDED = cygrpc.StatusCode.deadline_exceeded + NOT_FOUND = cygrpc.StatusCode.not_found + ALREADY_EXISTS = cygrpc.StatusCode.already_exists + PERMISSION_DENIED = cygrpc.StatusCode.permission_denied + RESOURCE_EXHAUSTED = cygrpc.StatusCode.resource_exhausted + FAILED_PRECONDITION = cygrpc.StatusCode.failed_precondition + ABORTED = cygrpc.StatusCode.aborted + OUT_OF_RANGE = cygrpc.StatusCode.out_of_range + UNIMPLEMENTED = cygrpc.StatusCode.unimplemented + INTERNAL = cygrpc.StatusCode.internal + UNAVAILABLE = cygrpc.StatusCode.unavailable + DATA_LOSS = cygrpc.StatusCode.data_loss + UNAUTHENTICATED = cygrpc.StatusCode.unauthenticated @enum.unique class OpWriteFlags(enum.IntEnum): """Mirrors defined write-flag constants in the C core.""" - WRITE_BUFFER_HINT = 1 - WRITE_NO_COMPRESS = 2 + WRITE_BUFFER_HINT = cygrpc.WriteFlag.buffer_hint + WRITE_NO_COMPRESS = cygrpc.WriteFlag.no_compress @enum.unique class OpType(enum.IntEnum): """Mirrors grpc_op_type in the C core.""" - SEND_INITIAL_METADATA = 0 - SEND_MESSAGE = 1 - SEND_CLOSE_FROM_CLIENT = 2 - SEND_STATUS_FROM_SERVER = 3 - RECV_INITIAL_METADATA = 4 - RECV_MESSAGE = 5 - RECV_STATUS_ON_CLIENT = 6 - RECV_CLOSE_ON_SERVER = 7 + SEND_INITIAL_METADATA = cygrpc.OperationType.send_initial_metadata + SEND_MESSAGE = cygrpc.OperationType.send_message + SEND_CLOSE_FROM_CLIENT = cygrpc.OperationType.send_close_from_client + SEND_STATUS_FROM_SERVER = cygrpc.OperationType.send_status_from_server + RECV_INITIAL_METADATA = cygrpc.OperationType.receive_initial_metadata + RECV_MESSAGE = cygrpc.OperationType.receive_message + RECV_STATUS_ON_CLIENT = cygrpc.OperationType.receive_status_on_client + RECV_CLOSE_ON_SERVER = cygrpc.OperationType.receive_close_on_server @enum.unique class EventType(enum.IntEnum): """Mirrors grpc_completion_type in the C core.""" - QUEUE_SHUTDOWN = 0 - QUEUE_TIMEOUT = 1 # if seen on the Python side, something went horridly wrong - OP_COMPLETE = 2 + QUEUE_SHUTDOWN = cygrpc.CompletionType.queue_shutdown + QUEUE_TIMEOUT = cygrpc.CompletionType.queue_timeout + OP_COMPLETE = cygrpc.CompletionType.operation_complete @enum.unique class ConnectivityState(enum.IntEnum): """Mirrors grpc_connectivity_state in the C core.""" - IDLE = 0 - CONNECTING = 1 - READY = 2 - TRANSIENT_FAILURE = 3 - FATAL_FAILURE = 4 + IDLE = cygrpc.ConnectivityState.idle + CONNECTING = cygrpc.ConnectivityState.connecting + READY = cygrpc.ConnectivityState.ready + TRANSIENT_FAILURE = cygrpc.ConnectivityState.transient_failure + FATAL_FAILURE = cygrpc.ConnectivityState.fatal_failure class Status(collections.namedtuple( diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx index 51c4668138..1c07f9f4f4 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx @@ -53,24 +53,24 @@ cdef class Call: self.c_call, cy_operations.c_ops, cy_operations.c_nops, <cpython.PyObject *>operation_tag, NULL) - def cancel(self, - grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE, - details=None): + def cancel( + self, grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE, + details=None): if not self.is_valid: raise ValueError("invalid call object cannot be used from Python") if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE): raise ValueError("if error_code is specified, so must details " "(and vice-versa)") - if isinstance(details, bytes): - pass - elif isinstance(details, basestring): - details = details.encode() - else: - raise TypeError("expected details to be str or bytes") if error_code != grpc.GRPC_STATUS__DO_NOT_USE: + if isinstance(details, bytes): + pass + elif isinstance(details, basestring): + details = details.encode() + else: + raise TypeError("expected details to be str or bytes") self.references.append(details) - return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details, - NULL) + return grpc.grpc_call_cancel_with_status( + self.c_call, error_code, details, NULL) else: return grpc.grpc_call_cancel(self.c_call, NULL) @@ -79,6 +79,12 @@ cdef class Call: return grpc.grpc_call_set_credentials( self.c_call, call_credentials.c_credentials) + def peer(self): + cdef char *peer = grpc.grpc_call_get_peer(self.c_call) + result = <bytes>peer + grpc.gpr_free(peer) + return result + def __dealloc__(self): if self.c_call != NULL: grpc.grpc_call_destroy(self.c_call) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx index e25db3e2a4..a944a83576 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx @@ -27,6 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +cimport cpython + from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport completion_queue from grpc._cython._cygrpc cimport credentials @@ -70,12 +72,16 @@ cdef class Channel: method = method.encode() else: raise TypeError("expected method to be str or bytes") - if isinstance(host, bytes): + cdef char *host_c_string = NULL + if host is None: pass + elif isinstance(host, bytes): + host_c_string = host elif isinstance(host, basestring): host = host.encode() + host_c_string = host else: - raise TypeError("expected host to be str or bytes") + raise TypeError("expected host to be str, bytes, or None") cdef call.Call operation_call = call.Call() operation_call.references = [self, method, host, queue] cdef grpc.grpc_call *parent_call = NULL @@ -83,10 +89,29 @@ cdef class Channel: parent_call = parent.c_call operation_call.c_call = grpc.grpc_channel_create_call( self.c_channel, parent_call, flags, - queue.c_completion_queue, method, host, deadline.c_time, + queue.c_completion_queue, method, host_c_string, deadline.c_time, NULL) return operation_call + def check_connectivity_state(self, bint try_to_connect): + return grpc.grpc_channel_check_connectivity_state(self.c_channel, + try_to_connect) + + def watch_connectivity_state( + self, last_observed_state, records.Timespec deadline not None, + completion_queue.CompletionQueue queue not None, tag): + cdef records.OperationTag operation_tag = records.OperationTag(tag) + cpython.Py_INCREF(operation_tag) + grpc.grpc_channel_watch_connectivity_state( + self.c_channel, last_observed_state, deadline.c_time, + queue.c_completion_queue, <cpython.PyObject *>operation_tag) + + def target(self): + cdef char * target = grpc.grpc_channel_get_target(self.c_channel) + result = <bytes>target + grpc.gpr_free(target) + return result + def __dealloc__(self): if self.c_channel != NULL: grpc.grpc_channel_destroy(self.c_channel) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx index a7a265eab7..2cf49707b4 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx @@ -62,6 +62,8 @@ cdef class CompletionQueue: cdef grpc.grpc_event event # Poll within a critical section + # TODO consider making queue polling contention a hard error to enable + # easier bug discovery with self.poll_condition: while self.is_polling: self.poll_condition.wait(float(deadline) - time.time()) @@ -74,10 +76,12 @@ cdef class CompletionQueue: self.poll_condition.notify() if event.type == grpc.GRPC_QUEUE_TIMEOUT: - return records.Event(event.type, False, None, None, None, None, None) + return records.Event( + event.type, False, None, None, None, None, False, None) elif event.type == grpc.GRPC_QUEUE_SHUTDOWN: self.is_shutdown = True - return records.Event(event.type, True, None, None, None, None, None) + return records.Event( + event.type, True, None, None, None, None, False, None) else: if event.tag != NULL: tag = <records.OperationTag>event.tag @@ -97,7 +101,8 @@ cdef class CompletionQueue: operation_call.references.extend(tag.references) return records.Event( event.type, event.success, user_tag, operation_call, - request_call_details, request_metadata, batch_operations) + request_call_details, request_metadata, tag.is_new_request, + batch_operations) def shutdown(self): grpc.grpc_completion_queue_shutdown(self.c_completion_queue) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd index 7a9fa7b76d..db9f8ddec9 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd +++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd @@ -27,7 +27,10 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +cimport cpython + from grpc._cython._cygrpc cimport grpc +from grpc._cython._cygrpc cimport records cdef class ChannelCredentials: @@ -49,3 +52,23 @@ cdef class ServerCredentials: cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs cdef size_t c_ssl_pem_key_cert_pairs_count cdef list references + + +cdef class CredentialsMetadataPlugin: + + cdef object plugin_callback + cdef str plugin_name + + cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self) + + +cdef class AuthMetadataContext: + + cdef grpc.grpc_auth_metadata_context context + + +cdef void plugin_get_metadata( + void *state, grpc.grpc_auth_metadata_context context, + grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil + +cdef void plugin_destroy_c_plugin_state(void *state) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx index e9836fec2c..a968894967 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx @@ -27,6 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +cimport cpython + from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport records @@ -71,19 +73,80 @@ cdef class ServerCredentials: def __cinit__(self): self.c_credentials = NULL + self.references = [] def __dealloc__(self): if self.c_credentials != NULL: grpc.grpc_server_credentials_release(self.c_credentials) +cdef class CredentialsMetadataPlugin: + + def __cinit__(self, object plugin_callback, str name): + """ + Args: + plugin_callback (callable): Callback accepting a service URL (str/bytes) + and callback object (accepting a records.Metadata, + grpc.grpc_status_code, and a str/bytes error message). This argument + when called should be non-blocking and eventually call the callback + object with the appropriate status code/details and metadata (if + successful). + name (str): Plugin name. + """ + if not callable(plugin_callback): + raise ValueError('expected callable plugin_callback') + self.plugin_callback = plugin_callback + self.plugin_name = name + + @staticmethod + cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self): + cdef grpc.grpc_metadata_credentials_plugin result + result.get_metadata = plugin_get_metadata + result.destroy = plugin_destroy_c_plugin_state + result.state = <void *>self + result.type = self.plugin_name + cpython.Py_INCREF(self) + return result + + +cdef class AuthMetadataContext: + + def __cinit__(self): + self.context.service_url = NULL + self.context.method_name = NULL + + @property + def service_url(self): + return self.context.service_url + + @property + def method_name(self): + return self.context.method_name + + +cdef void plugin_get_metadata( + void *state, grpc.grpc_auth_metadata_context context, + grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil: + def python_callback( + records.Metadata metadata, grpc.grpc_status_code status, + const char *error_details): + cb(user_data, metadata.c_metadata_array.metadata, + metadata.c_metadata_array.count, status, error_details) + cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state + cdef AuthMetadataContext cy_context = AuthMetadataContext() + cy_context.context = context + self.plugin_callback(cy_context, python_callback) + +cdef void plugin_destroy_c_plugin_state(void *state): + cpython.Py_DECREF(<CredentialsMetadataPlugin>state) + def channel_credentials_google_default(): cdef ChannelCredentials credentials = ChannelCredentials(); credentials.c_credentials = grpc.grpc_google_default_credentials_create() return credentials def channel_credentials_ssl(pem_root_certificates, - records.SslPemKeyCertPair ssl_pem_key_cert_pair): + records.SslPemKeyCertPair ssl_pem_key_cert_pair): if pem_root_certificates is None: pass elif isinstance(pem_root_certificates, bytes): @@ -104,6 +167,7 @@ def channel_credentials_ssl(pem_root_certificates, else: credentials.c_credentials = grpc.grpc_ssl_credentials_create( c_pem_root_certificates, NULL, NULL) + return credentials def channel_credentials_composite( ChannelCredentials credentials_1 not None, @@ -135,7 +199,6 @@ def call_credentials_google_compute_engine(): grpc.grpc_google_compute_engine_credentials_create(NULL)) return credentials -#TODO rename to something like client_credentials_service_account_jwt_access. def call_credentials_service_account_jwt_access( json_key, records.Timespec token_lifetime not None): if isinstance(json_key, bytes): @@ -184,14 +247,25 @@ def call_credentials_google_iam(authorization_token, authority_selector): credentials.references.append(authority_selector) return credentials +def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin): + cdef CallCredentials credentials = CallCredentials() + credentials.c_credentials = ( + grpc.grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(), + NULL)) + # TODO(atash): the following held reference is *probably* never necessary + credentials.references.append(plugin) + return credentials + def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs, bint force_client_auth): + cdef char *c_pem_root_certs = NULL if pem_root_certs is None: pass elif isinstance(pem_root_certs, bytes): - pass + c_pem_root_certs = pem_root_certs elif isinstance(pem_root_certs, basestring): pem_root_certs = pem_root_certs.encode() + c_pem_root_certs = pem_root_certs else: raise TypeError("expected pem_root_certs to be str or bytes") pem_key_cert_pairs = list(pem_key_cert_pairs) @@ -212,7 +286,7 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs, credentials.c_ssl_pem_key_cert_pairs[i] = ( (<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair) credentials.c_credentials = grpc.grpc_ssl_server_credentials_create( - pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, + c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL) return credentials diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd index 36aea81a6c..10c948cd0a 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd @@ -132,6 +132,20 @@ cdef extern from "grpc/byte_buffer.h": cdef extern from "grpc/grpc.h": + const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING + const char *GRPC_ARG_ENABLE_CENSUS + const char *GRPC_ARG_MAX_CONCURRENT_STREAMS + const char *GRPC_ARG_MAX_MESSAGE_LENGTH + const char *GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER + const char *GRPC_ARG_DEFAULT_AUTHORITY + const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING + const char *GRPC_ARG_SECONDARY_USER_AGENT_STRING + const char *GRPC_SSL_TARGET_NAME_OVERRIDE_ARG + + const int GRPC_WRITE_BUFFER_HINT + const int GRPC_WRITE_NO_COMPRESS + const int GRPC_WRITE_USED_MASK + ctypedef struct grpc_completion_queue: # We don't care about the internals (and in fact don't know them) pass @@ -149,9 +163,9 @@ cdef extern from "grpc/grpc.h": pass ctypedef enum grpc_arg_type: - grpc_arg_string "GRPC_ARG_STRING" - grpc_arg_integer "GRPC_ARG_INTEGER" - grpc_arg_pointer "GRPC_ARG_POINTER" + GRPC_ARG_STRING + GRPC_ARG_INTEGER + GRPC_ARG_POINTER ctypedef struct grpc_arg_value_pointer: void *address "p" @@ -185,6 +199,13 @@ cdef extern from "grpc/grpc.h": GRPC_CALL_ERROR_INVALID_FLAGS GRPC_CALL_ERROR_INVALID_METADATA + ctypedef enum grpc_connectivity_state: + GRPC_CHANNEL_IDLE + GRPC_CHANNEL_CONNECTING + GRPC_CHANNEL_READY + GRPC_CHANNEL_TRANSIENT_FAILURE + GRPC_CHANNEL_FATAL_FAILURE + ctypedef struct grpc_metadata: const char *key const char *value @@ -279,9 +300,9 @@ cdef extern from "grpc/grpc.h": grpc_status_code status, const char *description, void *reserved) + char *grpc_call_get_peer(grpc_call *call) void grpc_call_destroy(grpc_call *call) - grpc_channel *grpc_insecure_channel_create(const char *target, const grpc_channel_args *args, void *reserved) @@ -291,6 +312,12 @@ cdef extern from "grpc/grpc.h": grpc_completion_queue *completion_queue, const char *method, const char *host, gpr_timespec deadline, void *reserved) + grpc_connectivity_state grpc_channel_check_connectivity_state( + grpc_channel *channel, int try_to_connect) + void grpc_channel_watch_connectivity_state( + grpc_channel *channel, grpc_connectivity_state last_observed_state, + gpr_timespec deadline, grpc_completion_queue *cq, void *tag) + char *grpc_channel_get_target(grpc_channel *channel) void grpc_channel_destroy(grpc_channel *channel) grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) @@ -367,3 +394,27 @@ cdef extern from "grpc/grpc_security.h": grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_call_credentials *creds) + + ctypedef struct grpc_auth_context: + # We don't care about the internals (and in fact don't know them) + pass + + ctypedef struct grpc_auth_metadata_context: + const char *service_url + const char *method_name + const grpc_auth_context *channel_auth_context + + ctypedef void (*grpc_credentials_plugin_metadata_cb)( + void *user_data, const grpc_metadata *creds_md, size_t num_creds_md, + grpc_status_code status, const char *error_details) + + ctypedef struct grpc_metadata_credentials_plugin: + void (*get_metadata)( + void *state, grpc_auth_metadata_context context, + grpc_credentials_plugin_metadata_cb cb, void *user_data) + void (*destroy)(void *state) + void *state + const char *type + + grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( + grpc_metadata_credentials_plugin plugin, void *reserved) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd index 9ee487882a..4c844e4cb6 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd +++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd @@ -66,6 +66,7 @@ cdef class Event: cdef readonly call.Call operation_call # For Server.request_call + cdef readonly bint is_new_request cdef readonly CallDetails request_call_details cdef readonly Metadata request_metadata diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx index 8edee09c2d..79a7f8f563 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx @@ -32,6 +32,30 @@ from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport server +class ConnectivityState: + idle = grpc.GRPC_CHANNEL_IDLE + connecting = grpc.GRPC_CHANNEL_CONNECTING + ready = grpc.GRPC_CHANNEL_READY + transient_failure = grpc.GRPC_CHANNEL_TRANSIENT_FAILURE + fatal_failure = grpc.GRPC_CHANNEL_FATAL_FAILURE + + +class ChannelArgKey: + enable_census = grpc.GRPC_ARG_ENABLE_CENSUS + max_concurrent_streams = grpc.GRPC_ARG_MAX_CONCURRENT_STREAMS + max_message_length = grpc.GRPC_ARG_MAX_MESSAGE_LENGTH + http2_initial_sequence_number = grpc.GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER + default_authority = grpc.GRPC_ARG_DEFAULT_AUTHORITY + primary_user_agent_string = grpc.GRPC_ARG_PRIMARY_USER_AGENT_STRING + secondary_user_agent_string = grpc.GRPC_ARG_SECONDARY_USER_AGENT_STRING + ssl_target_name_override = grpc.GRPC_SSL_TARGET_NAME_OVERRIDE_ARG + + +class WriteFlag: + buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT + no_compress = grpc.GRPC_WRITE_NO_COMPRESS + + class StatusCode: ok = grpc.GRPC_STATUS_OK cancelled = grpc.GRPC_STATUS_CANCELLED @@ -88,7 +112,10 @@ cdef class Timespec: def __cinit__(self, time): if time is None: self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME) - elif isinstance(time, float): + return + if isinstance(time, int): + time = float(time) + if isinstance(time, float): if time == float("+inf"): self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME) elif time == float("-inf"): @@ -97,8 +124,11 @@ cdef class Timespec: self.c_time.seconds = time self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9 self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME + elif isinstance(time, Timespec): + self.c_time = (<Timespec>time).c_time else: - raise TypeError("expected time to be float") + raise TypeError("expected time to be float, int, or Timespec, not {}" + .format(type(time))) @property def seconds(self): @@ -166,6 +196,7 @@ cdef class Event: object tag, call.Call operation_call, CallDetails request_call_details, Metadata request_metadata, + bint is_new_request, Operations batch_operations): self.type = type self.success = success @@ -174,6 +205,7 @@ cdef class Event: self.request_call_details = request_call_details self.request_metadata = request_metadata self.batch_operations = batch_operations + self.is_new_request = is_new_request cdef class ByteBuffer: @@ -186,8 +218,14 @@ cdef class ByteBuffer: pass elif isinstance(data, basestring): data = data.encode() + elif isinstance(data, ByteBuffer): + data = (<ByteBuffer>data).bytes() + if data is None: + self.c_byte_buffer = NULL + return else: - raise TypeError("expected value to be of type str or bytes") + raise TypeError("expected value to be of type str, bytes, or " + "ByteBuffer, not {}".format(type(data))) cdef char *c_data = data data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data)) @@ -410,12 +448,22 @@ cdef class Operation: return self.c_op.type @property + def has_status(self): + return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT + + @property def received_message(self): if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE: raise TypeError("self must be an operation receiving a message") return self._received_message @property + def received_message_or_none(self): + if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE: + return None + return self._received_message + + @property def received_metadata(self): if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT): @@ -423,12 +471,25 @@ cdef class Operation: return self._received_metadata @property + def received_metadata_or_none(self): + if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and + self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT): + return None + return self._received_metadata + + @property def received_status_code(self): if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: raise TypeError("self must be an operation receiving a status code") return self._received_status_code @property + def received_status_code_or_none(self): + if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: + return None + return self._received_status_code + + @property def received_status_details(self): if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: raise TypeError("self must be an operation receiving status details") @@ -438,12 +499,27 @@ cdef class Operation: return None @property + def received_status_details_or_none(self): + if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: + return None + if self._received_status_details: + return self._received_status_details + else: + return None + + @property def received_cancelled(self): if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER: raise TypeError("self must be an operation receiving cancellation " "information") return False if self._received_cancelled == 0 else True + @property + def received_cancelled_or_none(self): + if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER: + return None + return False if self._received_cancelled == 0 else True + def __dealloc__(self): # We *almost* don't need to do anything; most of the objects are handled by # Python. The remaining one(s) are primitive fields filled in by GRPC core. diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx index 6d20d2910c..46df8bf77f 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx @@ -132,7 +132,7 @@ cdef class Server: def cancel_all_calls(self): if not self.is_shutting_down: - raise ValueError("the server must be shutting down to cancel all calls") + raise RuntimeError("the server must be shutting down to cancel all calls") elif self.is_shutdown: return else: diff --git a/src/python/grpcio/grpc/_cython/adapter_low.py b/src/python/grpcio/grpc/_cython/adapter_low.py deleted file mode 100644 index 4f24da330f..0000000000 --- a/src/python/grpcio/grpc/_cython/adapter_low.py +++ /dev/null @@ -1,102 +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. - - -# Adapter from grpc._cython.types to the surface expected by -# grpc._adapter._intermediary_low. -# -# TODO(atash): Once this is plugged into grpc._adapter._intermediary_low, remove -# both grpc._adapter._intermediary_low and this file. The fore and rear links in -# grpc._adapter should be able to use grpc._cython.types directly. - -from grpc._adapter import _types as type_interfaces -from grpc._cython import cygrpc - - -class ClientCredentials(object): - def __init__(self): - raise NotImplementedError() - - @staticmethod - def google_default(): - raise NotImplementedError() - - @staticmethod - def ssl(): - raise NotImplementedError() - - @staticmethod - def composite(): - raise NotImplementedError() - - @staticmethod - def compute_engine(): - raise NotImplementedError() - - @staticmethod - def jwt(): - raise NotImplementedError() - - @staticmethod - def refresh_token(): - raise NotImplementedError() - - @staticmethod - def iam(): - raise NotImplementedError() - - -class ServerCredentials(object): - def __init__(self): - raise NotImplementedError() - - @staticmethod - def ssl(): - raise NotImplementedError() - - -class CompletionQueue(type_interfaces.CompletionQueue): - def __init__(self): - raise NotImplementedError() - - -class Call(type_interfaces.Call): - def __init__(self): - raise NotImplementedError() - - -class Channel(type_interfaces.Channel): - def __init__(self): - raise NotImplementedError() - - -class Server(type_interfaces.Server): - def __init__(self): - raise NotImplementedError() - diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx index b20dda8a95..16ec12dac0 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pyx +++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx @@ -44,6 +44,9 @@ from grpc._cython._cygrpc import completion_queue from grpc._cython._cygrpc import records from grpc._cython._cygrpc import server +ConnectivityState = records.ConnectivityState +ChannelArgKey = records.ChannelArgKey +WriteFlag = records.WriteFlag StatusCode = records.StatusCode CallError = records.CallError CompletionType = records.CompletionType @@ -73,6 +76,8 @@ Operations = records.Operations CallCredentials = credentials.CallCredentials ChannelCredentials = credentials.ChannelCredentials ServerCredentials = credentials.ServerCredentials +CredentialsMetadataPlugin = credentials.CredentialsMetadataPlugin +AuthMetadataContext = credentials.AuthMetadataContext channel_credentials_google_default = ( credentials.channel_credentials_google_default) @@ -88,6 +93,7 @@ call_credentials_jwt_access = ( call_credentials_refresh_token = ( credentials.call_credentials_google_refresh_token) call_credentials_google_iam = credentials.call_credentials_google_iam +call_credentials_metadata_plugin = credentials.call_credentials_metadata_plugin server_credentials_ssl = credentials.server_credentials_ssl CompletionQueue = completion_queue.CompletionQueue diff --git a/src/python/grpcio/grpc/_links/invocation.py b/src/python/grpcio/grpc/_links/invocation.py index 67ef86a176..5ca0a0ee60 100644 --- a/src/python/grpcio/grpc/_links/invocation.py +++ b/src/python/grpcio/grpc/_links/invocation.py @@ -182,15 +182,15 @@ class _Kernel(object): def _on_finish_event(self, operation_id, event, rpc_state): _no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states) - if event.status.code is _intermediary_low.Code.OK: + if event.status.code == _intermediary_low.Code.OK: termination = links.Ticket.Termination.COMPLETION - elif event.status.code is _intermediary_low.Code.CANCELLED: + elif event.status.code == _intermediary_low.Code.CANCELLED: termination = links.Ticket.Termination.CANCELLATION - elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED: + elif event.status.code == _intermediary_low.Code.DEADLINE_EXCEEDED: termination = links.Ticket.Termination.EXPIRATION - elif event.status.code is _intermediary_low.Code.UNIMPLEMENTED: + elif event.status.code == _intermediary_low.Code.UNIMPLEMENTED: termination = links.Ticket.Termination.REMOTE_FAILURE - elif event.status.code is _intermediary_low.Code.UNKNOWN: + elif event.status.code == _intermediary_low.Code.UNKNOWN: termination = links.Ticket.Termination.LOCAL_FAILURE else: termination = links.Ticket.Termination.TRANSMISSION_FAILURE @@ -262,7 +262,7 @@ class _Kernel(object): self._channel, self._completion_queue, '/%s/%s' % (group, method), self._host, time.time() + timeout) if options is not None and options.credentials is not None: - call.set_credentials(options.credentials._intermediary_low_credentials) + call.set_credentials(options.credentials._low_credentials) if transformed_initial_metadata is not None: for metadata_key, metadata_value in transformed_initial_metadata: call.add_metadata(metadata_key, metadata_value) diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py index f56df84007..01edee6896 100644 --- a/src/python/grpcio/grpc/_links/service.py +++ b/src/python/grpcio/grpc/_links/service.py @@ -254,12 +254,12 @@ class _Kernel(object): rpc_state = self._rpc_states[call] _no_longer_due(_FINISH, rpc_state, call, self._rpc_states) code = event.status.code - if code is _intermediary_low.Code.OK: + if code == _intermediary_low.Code.OK: return - if code is _intermediary_low.Code.CANCELLED: + if code == _intermediary_low.Code.CANCELLED: termination = links.Ticket.Termination.CANCELLATION - elif code is _intermediary_low.Code.DEADLINE_EXCEEDED: + elif code == _intermediary_low.Code.DEADLINE_EXCEEDED: termination = links.Ticket.Termination.EXPIRATION else: termination = links.Ticket.Termination.TRANSMISSION_FAILURE diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py index 05b954d186..2b520cc7e5 100644 --- a/src/python/grpcio/grpc/beta/_server.py +++ b/src/python/grpcio/grpc/beta/_server.py @@ -44,6 +44,12 @@ _DEFAULT_TIMEOUT = 300 _MAXIMUM_TIMEOUT = 24 * 60 * 60 +def _set_event(): + event = threading.Event() + event.set() + return event + + class _GRPCServicer(base.Servicer): def __init__(self, delegate): @@ -61,86 +67,143 @@ class _GRPCServicer(base.Servicer): raise -def _disassemble(grpc_link, end_link, pool, event, grace): - grpc_link.begin_stop() - end_link.stop(grace).wait() - grpc_link.end_stop() - grpc_link.join_link(utilities.NULL_LINK) - end_link.join_link(utilities.NULL_LINK) - if pool is not None: - pool.shutdown(wait=True) - event.set() +class _Server(interfaces.Server): + def __init__( + self, implementations, multi_implementation, pool, pool_size, + default_timeout, maximum_timeout, grpc_link): + self._lock = threading.Lock() + self._implementations = implementations + self._multi_implementation = multi_implementation + self._customer_pool = pool + self._pool_size = pool_size + self._default_timeout = default_timeout + self._maximum_timeout = maximum_timeout + self._grpc_link = grpc_link -class Server(interfaces.Server): + self._end_link = None + self._stop_events = None + self._pool = None - def __init__(self, grpc_link, end_link, pool): - self._grpc_link = grpc_link - self._end_link = end_link - self._pool = pool + def _start(self): + with self._lock: + if self._end_link is not None: + raise ValueError('Cannot start already-started server!') + + if self._customer_pool is None: + self._pool = logging_pool.pool(self._pool_size) + assembly_pool = self._pool + else: + assembly_pool = self._customer_pool + + servicer = _GRPCServicer( + _crust_implementations.servicer( + self._implementations, self._multi_implementation, assembly_pool)) + + self._end_link = _core_implementations.service_end_link( + servicer, self._default_timeout, self._maximum_timeout) + + self._grpc_link.join_link(self._end_link) + self._end_link.join_link(self._grpc_link) + self._grpc_link.start() + self._end_link.start() + + def _dissociate_links_and_shut_down_pool(self): + self._grpc_link.end_stop() + self._grpc_link.join_link(utilities.NULL_LINK) + self._end_link.join_link(utilities.NULL_LINK) + self._end_link = None + if self._pool is not None: + self._pool.shutdown(wait=True) + self._pool = None + + def _stop_stopping(self): + self._dissociate_links_and_shut_down_pool() + for stop_event in self._stop_events: + stop_event.set() + self._stop_events = None + + def _stop_started(self): + self._grpc_link.begin_stop() + self._end_link.stop(0).wait() + self._dissociate_links_and_shut_down_pool() + + def _foreign_thread_stop(self, end_stop_event, stop_events): + end_stop_event.wait() + with self._lock: + if self._stop_events is stop_events: + self._stop_stopping() + + def _schedule_stop(self, grace): + with self._lock: + if self._end_link is None: + return _set_event() + server_stop_event = threading.Event() + if self._stop_events is None: + self._stop_events = [server_stop_event] + self._grpc_link.begin_stop() + else: + self._stop_events.append(server_stop_event) + end_stop_event = self._end_link.stop(grace) + end_stop_thread = threading.Thread( + target=self._foreign_thread_stop, + args=(end_stop_event, self._stop_events)) + end_stop_thread.start() + return server_stop_event + + def _stop_now(self): + with self._lock: + if self._end_link is not None: + if self._stop_events is None: + self._stop_started() + else: + self._stop_stopping() def add_insecure_port(self, address): - return self._grpc_link.add_port(address, None) + with self._lock: + if self._end_link is None: + return self._grpc_link.add_port(address, None) + else: + raise ValueError('Can\'t add port to serving server!') def add_secure_port(self, address, server_credentials): - return self._grpc_link.add_port( - address, server_credentials._intermediary_low_credentials) # pylint: disable=protected-access - - def _start(self): - self._grpc_link.join_link(self._end_link) - self._end_link.join_link(self._grpc_link) - self._grpc_link.start() - self._end_link.start() - - def _stop(self, grace): - stop_event = threading.Event() - if 0 < grace: - disassembly_thread = threading.Thread( - target=_disassemble, - args=( - self._grpc_link, self._end_link, self._pool, stop_event, grace,)) - disassembly_thread.start() - return stop_event - else: - _disassemble(self._grpc_link, self._end_link, self._pool, stop_event, 0) - return stop_event + with self._lock: + if self._end_link is None: + return self._grpc_link.add_port( + address, server_credentials._low_credentials) # pylint: disable=protected-access + else: + raise ValueError('Can\'t add port to serving server!') def start(self): self._start() def stop(self, grace): - return self._stop(grace) + if 0 < grace: + return self._schedule_stop(grace) + else: + self._stop_now() + return _set_event() def __enter__(self): self._start() return self def __exit__(self, exc_type, exc_val, exc_tb): - self._stop(0).wait() + self._stop_now() return False + def __del__(self): + self._stop_now() + def server( implementations, multi_implementation, request_deserializers, response_serializers, thread_pool, thread_pool_size, default_timeout, maximum_timeout): - if thread_pool is None: - service_thread_pool = logging_pool.pool( - _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size) - assembly_thread_pool = service_thread_pool - else: - service_thread_pool = thread_pool - assembly_thread_pool = None - - servicer = _GRPCServicer( - _crust_implementations.servicer( - implementations, multi_implementation, service_thread_pool)) - grpc_link = service.service_link(request_deserializers, response_serializers) - - end_link = _core_implementations.service_end_link( - servicer, + return _Server( + implementations, multi_implementation, thread_pool, + _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size, _DEFAULT_TIMEOUT if default_timeout is None else default_timeout, - _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout) - - return Server(grpc_link, end_link, assembly_thread_pool) + _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout, + grpc_link) diff --git a/src/python/grpcio/grpc/beta/_stub.py b/src/python/grpcio/grpc/beta/_stub.py index 11dab889cd..2af019309a 100644 --- a/src/python/grpcio/grpc/beta/_stub.py +++ b/src/python/grpcio/grpc/beta/_stub.py @@ -42,76 +42,114 @@ _DEFAULT_POOL_SIZE = 6 class _AutoIntermediary(object): - def __init__(self, delegate, on_deletion): + def __init__(self, up, down, delegate): + self._lock = threading.Lock() + self._up = up + self._down = down + self._in_context = False self._delegate = delegate - self._on_deletion = on_deletion def __getattr__(self, attr): - return getattr(self._delegate, attr) + with self._lock: + if self._delegate is None: + raise AttributeError('No useful attributes out of context!') + else: + return getattr(self._delegate, attr) def __enter__(self): - return self + with self._lock: + if self._in_context: + raise ValueError('Already in context!') + elif self._delegate is None: + self._delegate = self._up() + self._in_context = True + return self def __exit__(self, exc_type, exc_val, exc_tb): - return False + with self._lock: + if not self._in_context: + raise ValueError('Not in context!') + self._down() + self._in_context = False + self._delegate = None + return False def __del__(self): - self._on_deletion() + with self._lock: + if self._delegate is not None: + self._down() + self._delegate = None + + +class _StubAssemblyManager(object): + + def __init__( + self, thread_pool, thread_pool_size, end_link, grpc_link, stub_creator): + self._thread_pool = thread_pool + self._pool_size = thread_pool_size + self._end_link = end_link + self._grpc_link = grpc_link + self._stub_creator = stub_creator + self._own_pool = None + + def up(self): + if self._thread_pool is None: + self._own_pool = logging_pool.pool( + _DEFAULT_POOL_SIZE if self._pool_size is None else self._pool_size) + assembly_pool = self._own_pool + else: + assembly_pool = self._thread_pool + self._end_link.join_link(self._grpc_link) + self._grpc_link.join_link(self._end_link) + self._end_link.start() + self._grpc_link.start() + return self._stub_creator(self._end_link, assembly_pool) + + def down(self): + self._end_link.stop(0).wait() + self._grpc_link.stop() + self._end_link.join_link(utilities.NULL_LINK) + self._grpc_link.join_link(utilities.NULL_LINK) + if self._own_pool is not None: + self._own_pool.shutdown(wait=True) + self._own_pool = None def _assemble( channel, host, metadata_transformer, request_serializers, - response_deserializers, thread_pool, thread_pool_size): + response_deserializers, thread_pool, thread_pool_size, stub_creator): end_link = _core_implementations.invocation_end_link() grpc_link = invocation.invocation_link( channel, host, metadata_transformer, request_serializers, response_deserializers) - if thread_pool is None: - invocation_pool = logging_pool.pool( - _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size) - assembly_pool = invocation_pool - else: - invocation_pool = thread_pool - assembly_pool = None - end_link.join_link(grpc_link) - grpc_link.join_link(end_link) - end_link.start() - grpc_link.start() - return end_link, grpc_link, invocation_pool, assembly_pool - - -def _disassemble(end_link, grpc_link, pool): - end_link.stop(24 * 60 * 60).wait() - grpc_link.stop() - end_link.join_link(utilities.NULL_LINK) - grpc_link.join_link(utilities.NULL_LINK) - if pool is not None: - pool.shutdown(wait=True) - - -def _wrap_assembly(stub, end_link, grpc_link, assembly_pool): - disassembly_thread = threading.Thread( - target=_disassemble, args=(end_link, grpc_link, assembly_pool)) - return _AutoIntermediary(stub, disassembly_thread.start) + stub_assembly_manager = _StubAssemblyManager( + thread_pool, thread_pool_size, end_link, grpc_link, stub_creator) + stub = stub_assembly_manager.up() + return _AutoIntermediary( + stub_assembly_manager.up, stub_assembly_manager.down, stub) + + +def _dynamic_stub_creator(service, cardinalities): + def create_dynamic_stub(end_link, invocation_pool): + return _crust_implementations.dynamic_stub( + end_link, service, cardinalities, invocation_pool) + return create_dynamic_stub def generic_stub( channel, host, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size): - end_link, grpc_link, invocation_pool, assembly_pool = _assemble( + return _assemble( channel, host, metadata_transformer, request_serializers, - response_deserializers, thread_pool, thread_pool_size) - stub = _crust_implementations.generic_stub(end_link, invocation_pool) - return _wrap_assembly(stub, end_link, grpc_link, assembly_pool) + response_deserializers, thread_pool, thread_pool_size, + _crust_implementations.generic_stub) def dynamic_stub( channel, host, service, cardinalities, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size): - end_link, grpc_link, invocation_pool, assembly_pool = _assemble( + return _assemble( channel, host, metadata_transformer, request_serializers, - response_deserializers, thread_pool, thread_pool_size) - stub = _crust_implementations.dynamic_stub( - end_link, service, cardinalities, invocation_pool) - return _wrap_assembly(stub, end_link, grpc_link, assembly_pool) + response_deserializers, thread_pool, thread_pool_size, + _dynamic_stub_creator(service, cardinalities)) diff --git a/src/python/grpcio/grpc/beta/implementations.py b/src/python/grpcio/grpc/beta/implementations.py index c9d64ad35a..a0ca330d2c 100644 --- a/src/python/grpcio/grpc/beta/implementations.py +++ b/src/python/grpcio/grpc/beta/implementations.py @@ -36,6 +36,7 @@ import threading # pylint: disable=unused-import # cardinality and face are referenced from specification in this module. from grpc._adapter import _intermediary_low +from grpc._adapter import _low from grpc._adapter import _types from grpc.beta import _connectivity_channel from grpc.beta import _server @@ -48,7 +49,7 @@ _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( 'Exception calling channel subscription callback!') -class ClientCredentials(object): +class ChannelCredentials(object): """A value encapsulating the data required to create a secure Channel. This class and its instances have no supported interface - it exists to define @@ -56,13 +57,12 @@ class ClientCredentials(object): functions. """ - def __init__(self, low_credentials, intermediary_low_credentials): + def __init__(self, low_credentials): self._low_credentials = low_credentials - self._intermediary_low_credentials = intermediary_low_credentials -def ssl_client_credentials(root_certificates, private_key, certificate_chain): - """Creates a ClientCredentials for use with an SSL-enabled Channel. +def ssl_channel_credentials(root_certificates, private_key, certificate_chain): + """Creates a ChannelCredentials for use with an SSL-enabled Channel. Args: root_certificates: The PEM-encoded root certificates or None to ask for @@ -73,12 +73,73 @@ def ssl_client_credentials(root_certificates, private_key, certificate_chain): certificate chain should be used. Returns: - A ClientCredentials for use with an SSL-enabled Channel. + A ChannelCredentials for use with an SSL-enabled Channel. """ - intermediary_low_credentials = _intermediary_low.ClientCredentials( - root_certificates, private_key, certificate_chain) - return ClientCredentials( - intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access + return ChannelCredentials(_low.channel_credentials_ssl( + root_certificates, private_key, certificate_chain)) + + +class CallCredentials(object): + """A value encapsulating data asserting an identity over an *established* + channel. May be composed with ChannelCredentials to always assert identity for + every call over that channel. + + This class and its instances have no supported interface - it exists to define + the type of its instances and its instances exist to be passed to other + functions. + """ + + def __init__(self, low_credentials): + self._low_credentials = low_credentials + + +def metadata_call_credentials(metadata_plugin, name=None): + """Construct CallCredentials from an interfaces.GRPCAuthMetadataPlugin. + + Args: + metadata_plugin: An interfaces.GRPCAuthMetadataPlugin to use in constructing + the CallCredentials object. + + Returns: + A CallCredentials object for use in a GRPCCallOptions object. + """ + if name is None: + name = metadata_plugin.__name__ + return CallCredentials( + _low.call_credentials_metadata_plugin(metadata_plugin, name)) + +def composite_call_credentials(call_credentials, additional_call_credentials): + """Compose two CallCredentials to make a new one. + + Args: + call_credentials: A CallCredentials object. + additional_call_credentials: Another CallCredentials object to compose on + top of call_credentials. + + Returns: + A CallCredentials object for use in a GRPCCallOptions object. + """ + return CallCredentials( + _low.call_credentials_composite( + call_credentials._low_credentials, + additional_call_credentials._low_credentials)) + +def composite_channel_credentials(channel_credentials, + additional_call_credentials): + """Compose ChannelCredentials on top of client credentials to make a new one. + + Args: + channel_credentials: A ChannelCredentials object. + additional_call_credentials: A CallCredentials object to compose on + top of channel_credentials. + + Returns: + A ChannelCredentials object for use in a GRPCCallOptions object. + """ + return ChannelCredentials( + _low.channel_credentials_composite( + channel_credentials._low_credentials, + additional_call_credentials._low_credentials)) class Channel(object): @@ -135,19 +196,19 @@ def insecure_channel(host, port): return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access -def secure_channel(host, port, client_credentials): +def secure_channel(host, port, channel_credentials): """Creates a secure Channel to a remote host. Args: host: The name of the remote host to which to connect. port: The port of the remote host to which to connect. - client_credentials: A ClientCredentials. + channel_credentials: A ChannelCredentials. Returns: A secure Channel to the remote host through which RPCs may be conducted. """ intermediary_low_channel = _intermediary_low.Channel( - '%s:%d' % (host, port), client_credentials._intermediary_low_credentials) + '%s:%d' % (host, port), channel_credentials._low_credentials) return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access @@ -251,9 +312,8 @@ class ServerCredentials(object): functions. """ - def __init__(self, low_credentials, intermediary_low_credentials): + def __init__(self, low_credentials): self._low_credentials = low_credentials - self._intermediary_low_credentials = intermediary_low_credentials def ssl_server_credentials( @@ -282,11 +342,9 @@ def ssl_server_credentials( raise ValueError( 'Illegal to require client auth without providing root certificates!') else: - intermediary_low_credentials = _intermediary_low.ServerCredentials( + return ServerCredentials(_low.server_credentials_ssl( root_certificates, private_key_certificate_chain_pairs, - require_client_auth) - return ServerCredentials( - intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access + require_client_auth)) class ServerOptions(object): diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py index d4ca56500f..0663119163 100644 --- a/src/python/grpcio/grpc/beta/interfaces.py +++ b/src/python/grpcio/grpc/beta/interfaces.py @@ -100,14 +100,55 @@ def grpc_call_options(disable_compression=False, credentials=None): disable_compression: A boolean indicating whether or not compression should be disabled for the request object of the RPC. Only valid for request-unary RPCs. - credentials: Reserved for gRPC per-call credentials. The type for this does - not exist yet at the Python level. + credentials: A CallCredentials object to use for the invoked RPC. """ - if credentials is not None: - raise ValueError('`credentials` is a reserved argument') return GRPCCallOptions(disable_compression, None, credentials) +class GRPCAuthMetadataContext(object): + """Provides information to call credentials metadata plugins. + + Attributes: + service_url: A string URL of the service being called into. + method_name: A string of the fully qualified method name being called. + """ + __metaclass__ = abc.ABCMeta + + +class GRPCAuthMetadataPluginCallback(object): + """Callback object received by a metadata plugin.""" + __metaclass__ = abc.ABCMeta + + def __call__(self, metadata, error): + """Inform the gRPC runtime of the metadata to construct a CallCredentials. + + Args: + metadata: An iterable of 2-sequences (e.g. tuples) of metadata key/value + pairs. + error: An Exception to indicate error or None to indicate success. + """ + raise NotImplementedError() + + +class GRPCAuthMetadataPlugin(object): + """ + """ + __metaclass__ = abc.ABCMeta + + def __call__(self, context, callback): + """Invoke the plugin. + + Must not block. Need only be called by the gRPC runtime. + + Args: + context: A GRPCAuthMetadataContext providing information on what the + plugin is being used for. + callback: A GRPCAuthMetadataPluginCallback to be invoked either + synchronously or asynchronously. + """ + raise NotImplementedError() + + class GRPCServicerContext(object): """Exposes gRPC-specific options and behaviors to code servicing RPCs.""" __metaclass__ = abc.ABCMeta diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py index 8e07d9061e..9c615672aa 100644 --- a/src/python/grpcio/grpc/framework/core/_end.py +++ b/src/python/grpcio/grpc/framework/core/_end.py @@ -85,35 +85,6 @@ def _future_shutdown(lock, cycle, event): return in_future -def _termination_action(lock, stats, operation_id, cycle): - """Constructs the termination action for a single operation. - - Args: - lock: A lock to hold during the termination action. - stats: A mapping from base.Outcome.Kind values to integers to increment - with the outcome kind given to the termination action. - operation_id: The operation ID for the termination action. - cycle: A _Cycle value to be updated during the termination action. - - Returns: - A callable that takes an operation outcome kind as its sole parameter and - that should be used as the termination action for the operation - associated with the given operation ID. - """ - def termination_action(outcome_kind): - with lock: - stats[outcome_kind] += 1 - cycle.operations.pop(operation_id, None) - if not cycle.operations: - for action in cycle.idle_actions: - cycle.pool.submit(action) - cycle.idle_actions = [] - if cycle.grace: - _cancel_futures(cycle.futures) - cycle.pool.shutdown(wait=False) - return termination_action - - class _End(End): """An End implementation.""" @@ -133,6 +104,31 @@ class _End(End): self._cycle = None + def _termination_action(self, operation_id): + """Constructs the termination action for a single operation. + + Args: + operation_id: The operation ID for the termination action. + + Returns: + A callable that takes an operation outcome kind as its sole parameter and + that should be used as the termination action for the operation + associated with the given operation ID. + """ + def termination_action(outcome_kind): + with self._lock: + self._stats[outcome_kind] += 1 + self._cycle.operations.pop(operation_id, None) + if not self._cycle.operations: + for action in self._cycle.idle_actions: + self._cycle.pool.submit(action) + self._cycle.idle_actions = [] + if self._cycle.grace: + _cancel_futures(self._cycle.futures) + self._cycle.pool.shutdown(wait=False) + self._cycle = None + return termination_action + def start(self): """See base.End.start for specification.""" with self._lock: @@ -174,8 +170,7 @@ class _End(End): with self._lock: if self._cycle is None or self._cycle.grace: raise ValueError('Can\'t operate on stopped or stopping End!') - termination_action = _termination_action( - self._lock, self._stats, operation_id, self._cycle) + termination_action = self._termination_action(operation_id) operation = _operation.invocation_operate( operation_id, group, method, subscription, timeout, protocol_options, initial_metadata, payload, completion, self._mate.accept_ticket, @@ -208,8 +203,7 @@ class _End(End): if operation is not None: operation.handle_ticket(ticket) elif self._servicer_package is not None and not self._cycle.grace: - termination_action = _termination_action( - self._lock, self._stats, ticket.operation_id, self._cycle) + termination_action = self._termination_action(ticket.operation_id) operation = _operation.service_operate( self._servicer_package, ticket, self._mate.accept_ticket, termination_action, self._cycle.pool) diff --git a/src/python/grpcio/requirements.txt b/src/python/grpcio/requirements.txt index ee8568120b..06516ee0d7 100644 --- a/src/python/grpcio/requirements.txt +++ b/src/python/grpcio/requirements.txt @@ -1,3 +1,4 @@ enum34>=1.0.4 futures>=2.2.0 cython>=0.23 +coverage>=4.0 diff --git a/src/python/grpcio/setup.cfg b/src/python/grpcio/setup.cfg index 8f69613632..52b6b50900 100644 --- a/src/python/grpcio/setup.cfg +++ b/src/python/grpcio/setup.cfg @@ -1,2 +1,8 @@ +[coverage:run] +plugins = Cython.Coverage + [build_ext] inplace=1 + +[build_proto_modules] +exclude=.*protoc_plugin/protoc_plugin_test\.proto$ diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py index ec68eb6755..a948ca1fac 100644 --- a/src/python/grpcio/setup.py +++ b/src/python/grpcio/setup.py @@ -43,27 +43,23 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) # Break import-style to ensure we can actually find our commands module. import commands -# Use environment variables to determine whether or not the Cython extension -# should *use* Cython or use the generated C files. Note that this requires the -# C files to have been generated by building first *with* Cython support. -_BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False) - -_C_EXTENSION_SOURCES = ( - 'grpc/_adapter/_c/module.c', - 'grpc/_adapter/_c/types.c', - 'grpc/_adapter/_c/utility.c', - 'grpc/_adapter/_c/types/call_credentials.c', - 'grpc/_adapter/_c/types/channel_credentials.c', - 'grpc/_adapter/_c/types/server_credentials.c', - 'grpc/_adapter/_c/types/completion_queue.c', - 'grpc/_adapter/_c/types/call.c', - 'grpc/_adapter/_c/types/channel.c', - 'grpc/_adapter/_c/types/server.c', -) +# Environment variable to determine whether or not the Cython extension should +# *use* Cython or use the generated C files. Note that this requires the C files +# to have been generated by building first *with* Cython support. +BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False) + +# Environment variable to determine whether or not to enable coverage analysis +# in Cython modules. +ENABLE_CYTHON_TRACING = os.environ.get( + 'GRPC_PYTHON_ENABLE_CYTHON_TRACING', False) + +# Environment variable to determine whether or not to include the test files in +# the installation. +INSTALL_TESTS = os.environ.get('GRPC_PYTHON_INSTALL_TESTS', False) -_CYTHON_EXTENSION_PACKAGE_NAMES = () +CYTHON_EXTENSION_PACKAGE_NAMES = () -_CYTHON_EXTENSION_MODULE_NAMES = ( +CYTHON_EXTENSION_MODULE_NAMES = ( 'grpc._cython.cygrpc', 'grpc._cython._cygrpc.call', 'grpc._cython._cygrpc.channel', @@ -73,24 +69,16 @@ _CYTHON_EXTENSION_MODULE_NAMES = ( 'grpc._cython._cygrpc.server', ) -_EXTENSION_INCLUDE_DIRECTORIES = ( +EXTENSION_INCLUDE_DIRECTORIES = ( '.', ) -_EXTENSION_LIBRARIES = ( +EXTENSION_LIBRARIES = ( 'grpc', 'gpr', ) if not "darwin" in sys.platform: - _EXTENSION_LIBRARIES += ('rt',) - - -_C_EXTENSION_MODULE = _core.Extension( - 'grpc._adapter._c', sources=list(_C_EXTENSION_SOURCES), - include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES), - libraries=list(_EXTENSION_LIBRARIES), -) -_EXTENSION_MODULES = [_C_EXTENSION_MODULE] + EXTENSION_LIBRARIES += ('rt',) def cython_extensions(package_names, module_names, include_dirs, libraries, @@ -101,48 +89,89 @@ def cython_extensions(package_names, module_names, include_dirs, libraries, extensions = [ _extension.Extension( name=module_name, sources=[module_file], - include_dirs=include_dirs, libraries=libraries + include_dirs=include_dirs, libraries=libraries, + define_macros=[('CYTHON_TRACE_NOGIL', 1)] if ENABLE_CYTHON_TRACING else [] ) for (module_name, module_file) in zip(module_names, module_files) ] if build_with_cython: import Cython.Build - return Cython.Build.cythonize(extensions) + return Cython.Build.cythonize( + extensions, + compiler_directives={'linetrace': bool(ENABLE_CYTHON_TRACING)}) else: return extensions -_CYTHON_EXTENSION_MODULES = cython_extensions( - list(_CYTHON_EXTENSION_PACKAGE_NAMES), list(_CYTHON_EXTENSION_MODULE_NAMES), - list(_EXTENSION_INCLUDE_DIRECTORIES), list(_EXTENSION_LIBRARIES), - bool(_BUILD_WITH_CYTHON)) +CYTHON_EXTENSION_MODULES = cython_extensions( + list(CYTHON_EXTENSION_PACKAGE_NAMES), list(CYTHON_EXTENSION_MODULE_NAMES), + list(EXTENSION_INCLUDE_DIRECTORIES), list(EXTENSION_LIBRARIES), + bool(BUILD_WITH_CYTHON)) -_PACKAGES = setuptools.find_packages('.') - -_PACKAGE_DIRECTORIES = { +PACKAGE_DIRECTORIES = { '': '.', } -_INSTALL_REQUIRES = ( +INSTALL_REQUIRES = ( 'enum34>=1.0.4', 'futures>=2.2.0', ) -_SETUP_REQUIRES = ( +SETUP_REQUIRES = ( 'sphinx>=1.3', -) + _INSTALL_REQUIRES +) + INSTALL_REQUIRES -_COMMAND_CLASS = { +COMMAND_CLASS = { 'doc': commands.SphinxDocumentation, + 'build_proto_modules': commands.BuildProtoModules, 'build_project_metadata': commands.BuildProjectMetadata, 'build_py': commands.BuildPy, + 'gather': commands.Gather, + 'run_interop': commands.RunInterop, +} + +TEST_PACKAGE_DATA = { + 'tests.interop': [ + 'credentials/ca.pem', + 'credentials/server1.key', + 'credentials/server1.pem', + ], + 'tests.protoc_plugin': [ + 'protoc_plugin_test.proto', + ], + 'tests.unit': [ + 'credentials/ca.pem', + 'credentials/server1.key', + 'credentials/server1.pem', + ], } +TESTS_REQUIRE = ( + 'oauth2client>=1.4.7', + 'protobuf==3.0.0a3', + 'coverage>=4.0', +) + INSTALL_REQUIRES + +TEST_SUITE = 'tests' +TEST_LOADER = 'tests:Loader' +TEST_RUNNER = 'tests:Runner' + +PACKAGE_DATA = {} +if INSTALL_TESTS: + PACKAGE_DATA = dict(PACKAGE_DATA, **TEST_PACKAGE_DATA) + PACKAGES = setuptools.find_packages('.') +else: + PACKAGES = setuptools.find_packages('.', exclude=['tests', 'tests.*']) + setuptools.setup( name='grpcio', - version='0.11.0b1', - ext_modules=_EXTENSION_MODULES + _CYTHON_EXTENSION_MODULES, - packages=list(_PACKAGES), - package_dir=_PACKAGE_DIRECTORIES, - install_requires=_INSTALL_REQUIRES, - setup_requires=_SETUP_REQUIRES, - cmdclass=_COMMAND_CLASS + version='0.11.0b2', + ext_modules=CYTHON_EXTENSION_MODULES, + packages=list(PACKAGES), + package_dir=PACKAGE_DIRECTORIES, + install_requires=INSTALL_REQUIRES, + setup_requires=SETUP_REQUIRES, + cmdclass=COMMAND_CLASS, + tests_require=TESTS_REQUIRE, + test_suite=TEST_SUITE, + test_loader=TEST_LOADER, + test_runner=TEST_RUNNER, ) diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio/tests/__init__.py index e9ee45a92a..b76b3985a1 100644 --- a/src/python/grpcio_test/setup.py +++ b/src/python/grpcio/tests/__init__.py @@ -27,68 +27,8 @@ # (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 setup module for the GRPC Python interop testing package.""" +from tests import _loader +from tests import _runner -import os -import os.path - -import setuptools - -# Ensure we're in the proper directory whether or not we're being used by pip. -os.chdir(os.path.dirname(os.path.abspath(__file__))) - -# Break import-style to ensure we can actually find our commands module. -import commands - -_PACKAGES = setuptools.find_packages('.') - -_PACKAGE_DIRECTORIES = { - '': '.', -} - -_PACKAGE_DATA = { - 'grpc_interop': [ - 'credentials/ca.pem', - 'credentials/server1.key', - 'credentials/server1.pem', - ], - 'grpc_protoc_plugin': [ - 'test.proto', - ], - 'grpc_test': [ - 'credentials/ca.pem', - 'credentials/server1.key', - 'credentials/server1.pem', - ], -} - -_SETUP_REQUIRES = ( - 'pytest>=2.6', - 'pytest-cov>=2.0', - 'pytest-xdist>=1.11', - 'pytest-timeout>=0.5', -) - -_INSTALL_REQUIRES = ( - 'oauth2client>=1.4.7', - 'grpcio>=0.11.0b0', - # TODO(issue 3321): Unpin protobuf dependency. - 'protobuf==3.0.0a3', -) - -_COMMAND_CLASS = { - 'test': commands.RunTests, - 'build_proto_modules': commands.BuildProtoModules, - 'build_py': commands.BuildPy, -} - -setuptools.setup( - name='grpcio_test', - version='0.11.0b0', - packages=_PACKAGES, - package_dir=_PACKAGE_DIRECTORIES, - package_data=_PACKAGE_DATA, - install_requires=_INSTALL_REQUIRES + _SETUP_REQUIRES, - setup_requires=_SETUP_REQUIRES, - cmdclass=_COMMAND_CLASS, -) +Loader = _loader.Loader +Runner = _runner.Runner diff --git a/src/python/grpcio/tests/_loader.py b/src/python/grpcio/tests/_loader.py new file mode 100644 index 0000000000..6992029b5e --- /dev/null +++ b/src/python/grpcio/tests/_loader.py @@ -0,0 +1,119 @@ +# 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 importlib +import pkgutil +import re +import unittest + +import coverage + +TEST_MODULE_REGEX = r'^.*_test$' + + +class Loader(object): + """Test loader for setuptools test suite support. + + Attributes: + suite (unittest.TestSuite): All tests collected by the loader. + loader (unittest.TestLoader): Standard Python unittest loader to be ran per + module discovered. + module_matcher (re.RegexObject): A regular expression object to match + against module names and determine whether or not the discovered module + contributes to the test suite. + """ + + def __init__(self): + self.suite = unittest.TestSuite() + self.loader = unittest.TestLoader() + self.module_matcher = re.compile(TEST_MODULE_REGEX) + + def loadTestsFromNames(self, names, module=None): + """Function mirroring TestLoader::loadTestsFromNames, as expected by + setuptools.setup argument `test_loader`.""" + # ensure that we capture decorators and definitions (else our coverage + # measure unnecessarily suffers) + coverage_context = coverage.Coverage(data_suffix=True) + coverage_context.start() + modules = [importlib.import_module(name) for name in names] + for module in modules: + self.visit_module(module) + for module in modules: + try: + package_paths = module.__path__ + except: + continue + self.walk_packages(package_paths) + coverage_context.stop() + coverage_context.save() + return self.suite + + def walk_packages(self, package_paths): + """Walks over the packages, dispatching `visit_module` calls. + + Args: + package_paths (list): A list of paths over which to walk through modules + along. + """ + for importer, module_name, is_package in ( + pkgutil.iter_modules(package_paths)): + module = importer.find_module(module_name).load_module(module_name) + self.visit_module(module) + if is_package: + self.walk_packages(module.__path__) + + def visit_module(self, module): + """Visits the module, adding discovered tests to the test suite. + + Args: + module (module): Module to match against self.module_matcher; if matched + it has its tests loaded via self.loader into self.suite. + """ + if self.module_matcher.match(module.__name__): + module_suite = self.loader.loadTestsFromModule(module) + self.suite.addTest(module_suite) + + +def iterate_suite_cases(suite): + """Generator over all unittest.TestCases in a unittest.TestSuite. + + Args: + suite (unittest.TestSuite): Suite to iterate over in the generator. + + Returns: + generator: A generator over all unittest.TestCases in `suite`. + """ + for item in suite: + if isinstance(item, unittest.TestSuite): + for child_item in iterate_suite_cases(item): + yield child_item + elif isinstance(item, unittest.TestCase): + yield item + else: + raise ValueError('unexpected suite item of type {}'.format(type(item))) diff --git a/src/python/grpcio/tests/_result.py b/src/python/grpcio/tests/_result.py new file mode 100644 index 0000000000..5a570f4279 --- /dev/null +++ b/src/python/grpcio/tests/_result.py @@ -0,0 +1,451 @@ +# 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 cStringIO as StringIO +import collections +import itertools +import traceback +import unittest +from xml.etree import ElementTree + +import coverage + +from tests import _loader + + +class CaseResult(collections.namedtuple('CaseResult', [ + 'id', 'name', 'kind', 'stdout', 'stderr', 'skip_reason', 'traceback'])): + """A serializable result of a single test case. + + Attributes: + id (object): Any serializable object used to denote the identity of this + test case. + name (str or None): A human-readable name of the test case. + kind (CaseResult.Kind): The kind of test result. + stdout (object or None): Output on stdout, or None if nothing was captured. + stderr (object or None): Output on stderr, or None if nothing was captured. + skip_reason (object or None): The reason the test was skipped. Must be + something if self.kind is CaseResult.Kind.SKIP, else None. + traceback (object or None): The traceback of the test. Must be something if + self.kind is CaseResult.Kind.{ERROR, FAILURE, EXPECTED_FAILURE}, else + None. + """ + + class Kind: + UNTESTED = 'untested' + RUNNING = 'running' + ERROR = 'error' + FAILURE = 'failure' + SUCCESS = 'success' + SKIP = 'skip' + EXPECTED_FAILURE = 'expected failure' + UNEXPECTED_SUCCESS = 'unexpected success' + + def __new__(cls, id=None, name=None, kind=None, stdout=None, stderr=None, + skip_reason=None, traceback=None): + """Helper keyword constructor for the namedtuple. + + See this class' attributes for information on the arguments.""" + assert id is not None + assert name is None or isinstance(name, str) + if kind is CaseResult.Kind.UNTESTED: + pass + elif kind is CaseResult.Kind.RUNNING: + pass + elif kind is CaseResult.Kind.ERROR: + assert traceback is not None + elif kind is CaseResult.Kind.FAILURE: + assert traceback is not None + elif kind is CaseResult.Kind.SUCCESS: + pass + elif kind is CaseResult.Kind.SKIP: + assert skip_reason is not None + elif kind is CaseResult.Kind.EXPECTED_FAILURE: + assert traceback is not None + elif kind is CaseResult.Kind.UNEXPECTED_SUCCESS: + pass + else: + assert False + return super(cls, CaseResult).__new__( + cls, id, name, kind, stdout, stderr, skip_reason, traceback) + + def updated(self, name=None, kind=None, stdout=None, stderr=None, + skip_reason=None, traceback=None): + """Get a new validated CaseResult with the fields updated. + + See this class' attributes for information on the arguments.""" + name = self.name if name is None else name + kind = self.kind if kind is None else kind + stdout = self.stdout if stdout is None else stdout + stderr = self.stderr if stderr is None else stderr + skip_reason = self.skip_reason if skip_reason is None else skip_reason + traceback = self.traceback if traceback is None else traceback + return CaseResult(id=self.id, name=name, kind=kind, stdout=stdout, + stderr=stderr, skip_reason=skip_reason, + traceback=traceback) + + +class AugmentedResult(unittest.TestResult): + """unittest.Result that keeps track of additional information. + + Uses CaseResult objects to store test-case results, providing additional + information beyond that of the standard Python unittest library, such as + standard output. + + Attributes: + id_map (callable): A unary callable mapping unittest.TestCase objects to + unique identifiers. + cases (dict): A dictionary mapping from the identifiers returned by id_map + to CaseResult objects corresponding to those IDs. + """ + + def __init__(self, id_map): + """Initialize the object with an identifier mapping. + + Arguments: + id_map (callable): Corresponds to the attribute `id_map`.""" + super(AugmentedResult, self).__init__() + self.id_map = id_map + self.cases = None + + def startTestRun(self): + """See unittest.TestResult.startTestRun.""" + super(AugmentedResult, self).startTestRun() + self.cases = dict() + + def stopTestRun(self): + """See unittest.TestResult.stopTestRun.""" + super(AugmentedResult, self).stopTestRun() + + def startTest(self, test): + """See unittest.TestResult.startTest.""" + super(AugmentedResult, self).startTest(test) + case_id = self.id_map(test) + self.cases[case_id] = CaseResult( + id=case_id, name=test.id(), kind=CaseResult.Kind.RUNNING) + + def addError(self, test, error): + """See unittest.TestResult.addError.""" + super(AugmentedResult, self).addError(test, error) + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + kind=CaseResult.Kind.ERROR, traceback=error) + + def addFailure(self, test, error): + """See unittest.TestResult.addFailure.""" + super(AugmentedResult, self).addFailure(test, error) + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + kind=CaseResult.Kind.FAILURE, traceback=error) + + def addSuccess(self, test): + """See unittest.TestResult.addSuccess.""" + super(AugmentedResult, self).addSuccess(test) + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + kind=CaseResult.Kind.SUCCESS) + + def addSkip(self, test, reason): + """See unittest.TestResult.addSkip.""" + super(AugmentedResult, self).addSkip(test, reason) + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + kind=CaseResult.Kind.SKIP, skip_reason=reason) + + def addExpectedFailure(self, test, error): + """See unittest.TestResult.addExpectedFailure.""" + super(AugmentedResult, self).addExpectedFailure(test, error) + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=error) + + def addUnexpectedSuccess(self, test): + """See unittest.TestResult.addUnexpectedSuccess.""" + super(AugmentedResult, self).addUnexpectedSuccess(test) + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + kind=CaseResult.Kind.UNEXPECTED_SUCCESS) + + def set_output(self, test, stdout, stderr): + """Set the output attributes for the CaseResult corresponding to a test. + + Args: + test (unittest.TestCase): The TestCase to set the outputs of. + stdout (str): Output from stdout to assign to self.id_map(test). + stderr (str): Output from stderr to assign to self.id_map(test). + """ + case_id = self.id_map(test) + self.cases[case_id] = self.cases[case_id].updated( + stdout=stdout, stderr=stderr) + + def augmented_results(self, filter): + """Convenience method to retrieve filtered case results. + + Args: + filter (callable): A unary predicate to filter over CaseResult objects. + """ + return (self.cases[case_id] for case_id in self.cases + if filter(self.cases[case_id])) + + +class CoverageResult(AugmentedResult): + """Extension to AugmentedResult adding coverage.py support per test.\ + + Attributes: + coverage_context (coverage.Coverage): coverage.py management object. + """ + + def __init__(self, id_map): + """See AugmentedResult.__init__.""" + super(CoverageResult, self).__init__(id_map=id_map) + self.coverage_context = None + + def startTest(self, test): + """See unittest.TestResult.startTest. + + Additionally initializes and begins code coverage tracking.""" + super(CoverageResult, self).startTest(test) + self.coverage_context = coverage.Coverage(data_suffix=True) + self.coverage_context.start() + + def stopTest(self, test): + """See unittest.TestResult.stopTest. + + Additionally stops and deinitializes code coverage tracking.""" + super(CoverageResult, self).stopTest(test) + self.coverage_context.stop() + self.coverage_context.save() + self.coverage_context = None + + def stopTestRun(self): + """See unittest.TestResult.stopTestRun.""" + super(CoverageResult, self).stopTestRun() + # TODO(atash): Dig deeper into why the following line fails to properly + # combine coverage data from the Cython plugin. + #coverage.Coverage().combine() + + +class _Colors: + """Namespaced constants for terminal color magic numbers.""" + HEADER = '\033[95m' + INFO = '\033[94m' + OK = '\033[92m' + WARN = '\033[93m' + FAIL = '\033[91m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + END = '\033[0m' + + +class TerminalResult(CoverageResult): + """Extension to CoverageResult adding basic terminal reporting.""" + + def __init__(self, out, id_map): + """Initialize the result object. + + Args: + out (file-like): Output file to which terminal-colored live results will + be written. + id_map (callable): See AugmentedResult.__init__. + """ + super(TerminalResult, self).__init__(id_map=id_map) + self.out = out + + def startTestRun(self): + """See unittest.TestResult.startTestRun.""" + super(TerminalResult, self).startTestRun() + self.out.write( + _Colors.HEADER + + 'Testing gRPC Python...\n' + + _Colors.END) + + def stopTestRun(self): + """See unittest.TestResult.stopTestRun.""" + super(TerminalResult, self).stopTestRun() + self.out.write(summary(self)) + self.out.flush() + + def addError(self, test, error): + """See unittest.TestResult.addError.""" + super(TerminalResult, self).addError(test, error) + self.out.write( + _Colors.FAIL + + 'ERROR {}\n'.format(test.id()) + + _Colors.END) + self.out.flush() + + def addFailure(self, test, error): + """See unittest.TestResult.addFailure.""" + super(TerminalResult, self).addFailure(test, error) + self.out.write( + _Colors.FAIL + + 'FAILURE {}\n'.format(test.id()) + + _Colors.END) + self.out.flush() + + def addSuccess(self, test): + """See unittest.TestResult.addSuccess.""" + super(TerminalResult, self).addSuccess(test) + self.out.write( + _Colors.OK + + 'SUCCESS {}\n'.format(test.id()) + + _Colors.END) + self.out.flush() + + def addSkip(self, test, reason): + """See unittest.TestResult.addSkip.""" + super(TerminalResult, self).addSkip(test, reason) + self.out.write( + _Colors.INFO + + 'SKIP {}\n'.format(test.id()) + + _Colors.END) + self.out.flush() + + def addExpectedFailure(self, test, error): + """See unittest.TestResult.addExpectedFailure.""" + super(TerminalResult, self).addExpectedFailure(test, error) + self.out.write( + _Colors.INFO + + 'FAILURE_OK {}\n'.format(test.id()) + + _Colors.END) + self.out.flush() + + def addUnexpectedSuccess(self, test): + """See unittest.TestResult.addUnexpectedSuccess.""" + super(TerminalResult, self).addUnexpectedSuccess(test) + self.out.write( + _Colors.INFO + + 'UNEXPECTED_OK {}\n'.format(test.id()) + + _Colors.END) + self.out.flush() + +def _traceback_string(type, value, trace): + """Generate a descriptive string of a Python exception traceback. + + Args: + type (class): The type of the exception. + value (Exception): The value of the exception. + trace (traceback): Traceback of the exception. + + Returns: + str: Formatted exception descriptive string. + """ + buffer = StringIO.StringIO() + traceback.print_exception(type, value, trace, file=buffer) + return buffer.getvalue() + +def summary(result): + """A summary string of a result object. + + Args: + result (AugmentedResult): The result object to get the summary of. + + Returns: + str: The summary string. + """ + assert isinstance(result, AugmentedResult) + untested = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.UNTESTED)) + running = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.RUNNING)) + failures = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.FAILURE)) + errors = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.ERROR)) + successes = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.SUCCESS)) + skips = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.SKIP)) + expected_failures = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.EXPECTED_FAILURE)) + unexpected_successes = list(result.augmented_results( + lambda case_result: case_result.kind is CaseResult.Kind.UNEXPECTED_SUCCESS)) + running_names = [case.name for case in running] + finished_count = (len(failures) + len(errors) + len(successes) + + len(expected_failures) + len(unexpected_successes)) + statistics = ( + '{finished} tests finished:\n' + '\t{successful} successful\n' + '\t{unsuccessful} unsuccessful\n' + '\t{skipped} skipped\n' + '\t{expected_fail} expected failures\n' + '\t{unexpected_successful} unexpected successes\n' + 'Interrupted Tests:\n' + '\t{interrupted}\n' + .format(finished=finished_count, + successful=len(successes), + unsuccessful=(len(failures)+len(errors)), + skipped=len(skips), + expected_fail=len(expected_failures), + unexpected_successful=len(unexpected_successes), + interrupted=str(running_names))) + tracebacks = '\n\n'.join([ + (_Colors.FAIL + '{test_name}' + _Colors.END + + '\n' + + _Colors.BOLD + 'traceback:' + _Colors.END + '\n' + + '{traceback}\n' + + _Colors.BOLD + 'stdout:' + _Colors.END + '\n' + + '{stdout}\n' + + _Colors.BOLD + 'stderr:' + _Colors.END + '\n' + + '{stderr}\n').format( + test_name=result.name, + traceback=_traceback_string(*result.traceback), + stdout=result.stdout, stderr=result.stderr) + for result in itertools.chain(failures, errors) + ]) + notes = 'Unexpected successes: {}\n'.format([ + result.name for result in unexpected_successes]) + return statistics + '\nErrors/Failures: \n' + tracebacks + '\n' + notes + + +def jenkins_junit_xml(result): + """An XML tree object that when written is recognizable by Jenkins. + + Args: + result (AugmentedResult): The result object to get the junit xml output of. + + Returns: + ElementTree.ElementTree: The XML tree. + """ + assert isinstance(result, AugmentedResult) + root = ElementTree.Element('testsuites') + suite = ElementTree.SubElement(root, 'testsuite', { + 'name': 'Python gRPC tests', + }) + for case in result.cases.values(): + if case.kind is CaseResult.Kind.SUCCESS: + ElementTree.SubElement(suite, 'testcase', { + 'name': case.name, + }) + elif case.kind in (CaseResult.Kind.ERROR, CaseResult.Kind.FAILURE): + case_xml = ElementTree.SubElement(suite, 'testcase', { + 'name': case.name, + }) + error_xml = ElementTree.SubElement(case_xml, 'error', {}) + error_xml.text = ''.format(case.stderr, case.traceback) + return ElementTree.ElementTree(element=root) diff --git a/src/python/grpcio/tests/_runner.py b/src/python/grpcio/tests/_runner.py new file mode 100644 index 0000000000..4f1ddb57fc --- /dev/null +++ b/src/python/grpcio/tests/_runner.py @@ -0,0 +1,224 @@ +# 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 cStringIO as StringIO +import collections +import fcntl +import multiprocessing +import os +import select +import signal +import sys +import threading +import time +import unittest +import uuid + +from tests import _loader +from tests import _result + + +class CapturePipe(object): + """A context-manager pipe to redirect output to a byte array. + + Attributes: + _redirect_fd (int): File descriptor of file to redirect writes from. + _saved_fd (int): A copy of the original value of the redirected file + descriptor. + _read_thread (threading.Thread or None): Thread upon which reads through the + pipe are performed. Only non-None when self is started. + _read_fd (int or None): File descriptor of the read end of the redirect + pipe. Only non-None when self is started. + _write_fd (int or None): File descriptor of the write end of the redirect + pipe. Only non-None when self is started. + output (bytearray or None): Redirected output from writes to the redirected + file descriptor. Only valid during and after self has started. + """ + + def __init__(self, fd): + self._redirect_fd = fd + self._saved_fd = os.dup(self._redirect_fd) + self._read_thread = None + self._read_fd = None + self._write_fd = None + self.output = None + + def start(self): + """Start redirection of writes to the file descriptor.""" + self._read_fd, self._write_fd = os.pipe() + os.dup2(self._write_fd, self._redirect_fd) + flags = fcntl.fcntl(self._read_fd, fcntl.F_GETFL) + fcntl.fcntl(self._read_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) + self._read_thread = threading.Thread(target=self._read) + self._read_thread.start() + + def stop(self): + """Stop redirection of writes to the file descriptor.""" + os.close(self._write_fd) + os.dup2(self._saved_fd, self._redirect_fd) # auto-close self._redirect_fd + self._read_thread.join() + self._read_thread = None + # we waited for the read thread to finish, so _read_fd has been read and we + # can close it. + os.close(self._read_fd) + + def _read(self): + """Read-thread target for self.""" + self.output = bytearray() + while True: + select.select([self._read_fd], [], []) + read_bytes = os.read(self._read_fd, 1024) + if read_bytes: + self.output.extend(read_bytes) + else: + break + + def write_bypass(self, value): + """Bypass the redirection and write directly to the original file. + + Arguments: + value (str): What to write to the original file. + """ + if self._saved_fd is None: + os.write(self._redirect_fd, value) + else: + os.write(self._saved_fd, value) + + def __enter__(self): + self.start() + return self + + def __exit__(self, type, value, traceback): + self.stop() + + def close(self): + """Close any resources used by self not closed by stop().""" + os.close(self._saved_fd) + + +class AugmentedCase(collections.namedtuple('AugmentedCase', [ + 'case', 'id'])): + """A test case with a guaranteed unique externally specified identifier. + + Attributes: + case (unittest.TestCase): TestCase we're decorating with an additional + identifier. + id (object): Any identifier that may be considered 'unique' for testing + purposes. + """ + + def __new__(cls, case, id=None): + if id is None: + id = uuid.uuid4() + return super(cls, AugmentedCase).__new__(cls, case, id) + + +class Runner(object): + + def run(self, suite): + """See setuptools' test_runner setup argument for information.""" + # Ensure that every test case has no collision with any other test case in + # the augmented results. + augmented_cases = [AugmentedCase(case, uuid.uuid4()) + for case in _loader.iterate_suite_cases(suite)] + case_id_by_case = dict((augmented_case.case, augmented_case.id) + for augmented_case in augmented_cases) + result_out = StringIO.StringIO() + result = _result.TerminalResult( + result_out, id_map=lambda case: case_id_by_case[case]) + stdout_pipe = CapturePipe(sys.stdout.fileno()) + stderr_pipe = CapturePipe(sys.stderr.fileno()) + kill_flag = [False] + + def sigint_handler(signal_number, frame): + if signal_number == signal.SIGINT: + kill_flag[0] = True # Python 2.7 not having 'local'... :-( + signal.signal(signal_number, signal.SIG_DFL) + + def fault_handler(signal_number, frame): + stdout_pipe.write_bypass( + 'Received fault signal {}\nstdout:\n{}\n\nstderr:{}\n' + .format(signal_number, stdout_pipe.output, stderr_pipe.output)) + os._exit(1) + + def check_kill_self(): + if kill_flag[0]: + stdout_pipe.write_bypass('Stopping tests short...') + result.stopTestRun() + stdout_pipe.write_bypass(result_out.getvalue()) + stdout_pipe.write_bypass( + '\ninterrupted stdout:\n{}\n'.format(stdout_pipe.output)) + stderr_pipe.write_bypass( + '\ninterrupted stderr:\n{}\n'.format(stderr_pipe.output)) + os._exit(1) + signal.signal(signal.SIGINT, sigint_handler) + signal.signal(signal.SIGSEGV, fault_handler) + signal.signal(signal.SIGBUS, fault_handler) + signal.signal(signal.SIGABRT, fault_handler) + signal.signal(signal.SIGFPE, fault_handler) + signal.signal(signal.SIGILL, fault_handler) + # Sometimes output will lag after a test has successfully finished; we + # ignore such writes to our pipes. + signal.signal(signal.SIGPIPE, signal.SIG_IGN) + + # Run the tests + result.startTestRun() + for augmented_case in augmented_cases: + sys.stdout.write('Running {}\n'.format(augmented_case.case.id())) + sys.stdout.flush() + case_thread = threading.Thread( + target=augmented_case.case.run, args=(result,)) + try: + with stdout_pipe, stderr_pipe: + case_thread.start() + while case_thread.is_alive(): + check_kill_self() + time.sleep(0) + case_thread.join() + except: + # re-raise the exception after forcing the with-block to end + raise + result.set_output( + augmented_case.case, stdout_pipe.output, stderr_pipe.output) + sys.stdout.write(result_out.getvalue()) + sys.stdout.flush() + result_out.truncate(0) + check_kill_self() + result.stopTestRun() + stdout_pipe.close() + stderr_pipe.close() + + # Report results + sys.stdout.write(result_out.getvalue()) + sys.stdout.flush() + signal.signal(signal.SIGINT, signal.SIG_DFL) + with open('report.xml', 'w') as report_xml_file: + _result.jenkins_junit_xml(result).write(report_xml_file) + return result + diff --git a/src/python/grpcio_test/grpc_interop/__init__.py b/src/python/grpcio/tests/interop/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_interop/__init__.py +++ b/src/python/grpcio/tests/interop/__init__.py diff --git a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py b/src/python/grpcio/tests/interop/_insecure_interop_test.py index 5007be28ff..00b49aba37 100644 --- a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py +++ b/src/python/grpcio/tests/interop/_insecure_interop_test.py @@ -33,10 +33,10 @@ import unittest from grpc.beta import implementations -from grpc_interop import _interop_test_case -from grpc_interop import methods -from grpc_interop import server -from grpc_interop import test_pb2 +from tests.interop import _interop_test_case +from tests.interop import methods +from tests.interop import server +from tests.interop import test_pb2 class InsecureInteropTest( diff --git a/src/python/grpcio_test/grpc_interop/_interop_test_case.py b/src/python/grpcio/tests/interop/_interop_test_case.py index b6d06b300d..ccea17a66d 100644 --- a/src/python/grpcio_test/grpc_interop/_interop_test_case.py +++ b/src/python/grpcio/tests/interop/_interop_test_case.py @@ -29,7 +29,7 @@ """Common code for unit tests of the interoperability test code.""" -from grpc_interop import methods +from tests.interop import methods class InteropTestCase(object): diff --git a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py b/src/python/grpcio/tests/interop/_secure_interop_test.py index 108e15b0f9..7e3061133f 100644 --- a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py +++ b/src/python/grpcio/tests/interop/_secure_interop_test.py @@ -33,12 +33,12 @@ import unittest from grpc.beta import implementations -from grpc_test.beta import test_utilities +from tests.interop import _interop_test_case +from tests.interop import methods +from tests.interop import resources +from tests.interop import test_pb2 -from grpc_interop import _interop_test_case -from grpc_interop import methods -from grpc_interop import resources -from grpc_interop import test_pb2 +from tests.unit.beta import test_utilities _SERVER_HOST_OVERRIDE = 'foo.test.google.fr' @@ -55,7 +55,7 @@ class SecureInteropTest( self.server.start() self.stub = test_pb2.beta_create_TestService_stub( test_utilities.not_really_secure_channel( - '[::]', port, implementations.ssl_client_credentials( + '[::]', port, implementations.ssl_channel_credentials( resources.test_root_certificates(), None, None), _SERVER_HOST_OVERRIDE)) diff --git a/src/python/grpcio_test/grpc_interop/client.py b/src/python/grpcio/tests/interop/client.py index b8d5047ca5..5c00bce014 100644 --- a/src/python/grpcio_test/grpc_interop/client.py +++ b/src/python/grpcio/tests/interop/client.py @@ -34,11 +34,10 @@ from oauth2client import client as oauth2client_client from grpc.beta import implementations -from grpc_test.beta import test_utilities - -from grpc_interop import methods -from grpc_interop import resources -from grpc_interop import test_pb2 +from tests.interop import methods +from tests.interop import resources +from tests.interop import test_pb2 +from tests.unit.beta import test_utilities _ONE_DAY_IN_SECONDS = 60 * 60 * 24 @@ -95,7 +94,7 @@ def _stub(args): channel = test_utilities.not_really_secure_channel( args.server_host, args.server_port, - implementations.ssl_client_credentials(root_certificates, None, None), + implementations.ssl_channel_credentials(root_certificates, None, None), args.server_host_override) stub = test_pb2.beta_create_TestService_stub( channel, metadata_transformer=metadata_transformer) @@ -114,7 +113,7 @@ def _test_case_from_arg(test_case_arg): raise ValueError('No test case "%s"!' % test_case_arg) -def _test_interoperability(): +def test_interoperability(): args = _args() stub = _stub(args) test_case = _test_case_from_arg(args.test_case) @@ -122,4 +121,4 @@ def _test_interoperability(): if __name__ == '__main__': - _test_interoperability() + test_interoperability() diff --git a/src/python/grpcio_test/grpc_interop/credentials/README b/src/python/grpcio/tests/interop/credentials/README index cb20dcb49f..cb20dcb49f 100644 --- a/src/python/grpcio_test/grpc_interop/credentials/README +++ b/src/python/grpcio/tests/interop/credentials/README diff --git a/src/python/grpcio_test/grpc_interop/credentials/ca.pem b/src/python/grpcio/tests/interop/credentials/ca.pem index 6c8511a73c..6c8511a73c 100755 --- a/src/python/grpcio_test/grpc_interop/credentials/ca.pem +++ b/src/python/grpcio/tests/interop/credentials/ca.pem diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.key b/src/python/grpcio/tests/interop/credentials/server1.key index 143a5b8765..143a5b8765 100755 --- a/src/python/grpcio_test/grpc_interop/credentials/server1.key +++ b/src/python/grpcio/tests/interop/credentials/server1.key diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.pem b/src/python/grpcio/tests/interop/credentials/server1.pem index f3d43fcc5b..f3d43fcc5b 100755 --- a/src/python/grpcio_test/grpc_interop/credentials/server1.pem +++ b/src/python/grpcio/tests/interop/credentials/server1.pem diff --git a/src/python/grpcio_test/grpc_interop/empty.proto b/src/python/grpcio/tests/interop/empty.proto index 6d0eb937d6..6d0eb937d6 100644 --- a/src/python/grpcio_test/grpc_interop/empty.proto +++ b/src/python/grpcio/tests/interop/empty.proto diff --git a/src/python/grpcio_test/grpc_interop/messages.proto b/src/python/grpcio/tests/interop/messages.proto index 193b6c4171..193b6c4171 100644 --- a/src/python/grpcio_test/grpc_interop/messages.proto +++ b/src/python/grpcio/tests/interop/messages.proto diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio/tests/interop/methods.py index 3ef8545355..b3591aef7b 100644 --- a/src/python/grpcio_test/grpc_interop/methods.py +++ b/src/python/grpcio/tests/interop/methods.py @@ -40,9 +40,9 @@ from oauth2client import client as oauth2client_client from grpc.framework.common import cardinality from grpc.framework.interfaces.face import face -from grpc_interop import empty_pb2 -from grpc_interop import messages_pb2 -from grpc_interop import test_pb2 +from tests.interop import empty_pb2 +from tests.interop import messages_pb2 +from tests.interop import test_pb2 _TIMEOUT = 7 diff --git a/src/python/grpcio_test/grpc_interop/resources.py b/src/python/grpcio/tests/interop/resources.py index 1122499418..1122499418 100644 --- a/src/python/grpcio_test/grpc_interop/resources.py +++ b/src/python/grpcio/tests/interop/resources.py diff --git a/src/python/grpcio_test/grpc_interop/server.py b/src/python/grpcio/tests/interop/server.py index b541087663..6dd55f008c 100644 --- a/src/python/grpcio_test/grpc_interop/server.py +++ b/src/python/grpcio/tests/interop/server.py @@ -35,9 +35,9 @@ import time from grpc.beta import implementations -from grpc_interop import methods -from grpc_interop import resources -from grpc_interop import test_pb2 +from tests.interop import methods +from tests.interop import resources +from tests.interop import test_pb2 _ONE_DAY_IN_SECONDS = 60 * 60 * 24 @@ -68,7 +68,7 @@ def serve(): time.sleep(_ONE_DAY_IN_SECONDS) except BaseException as e: logging.info('Caught exception "%s"; stopping server...', e) - server.stop() + server.stop(0) logging.info('Server stopped; exiting.') if __name__ == '__main__': diff --git a/src/python/grpcio_test/grpc_interop/test.proto b/src/python/grpcio/tests/interop/test.proto index b499813e56..9feecc0278 100644 --- a/src/python/grpcio_test/grpc_interop/test.proto +++ b/src/python/grpcio/tests/interop/test.proto @@ -33,8 +33,8 @@ syntax = "proto3"; -import "grpc_interop/empty.proto"; -import "grpc_interop/messages.proto"; +import "tests/interop/empty.proto"; +import "tests/interop/messages.proto"; package grpc.testing; diff --git a/src/python/grpcio_test/grpc_protoc_plugin/__init__.py b/src/python/grpcio/tests/protoc_plugin/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_protoc_plugin/__init__.py +++ b/src/python/grpcio/tests/protoc_plugin/__init__.py diff --git a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py index 259b978de2..ba5b219a88 100644 --- a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py +++ b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py @@ -45,7 +45,7 @@ import unittest from grpc.beta import implementations from grpc.framework.foundation import future from grpc.framework.interfaces.face import face -from grpc_test.framework.common import test_constants +from tests.unit.framework.common import test_constants # Identifiers of entities we expect to find in the generated module. SERVICER_IDENTIFIER = 'BetaTestServiceServicer' @@ -218,7 +218,7 @@ class PythonPluginTest(unittest.TestCase): protoc_plugin_filename = distutils.spawn.find_executable( 'grpc_python_plugin') test_proto_filename = pkg_resources.resource_filename( - 'grpc_protoc_plugin', 'test.proto') + 'tests.protoc_plugin', 'protoc_plugin_test.proto') if not os.path.isfile(protoc_command): # Assume that if we haven't built protoc that it's on the system. protoc_command = 'protoc' @@ -237,7 +237,7 @@ class PythonPluginTest(unittest.TestCase): ] subprocess.check_call(' '.join(cmd), shell=True, env=os.environ, cwd=os.path.dirname(test_proto_filename)) - sys.path.append(self.outdir) + sys.path.insert(0, self.outdir) def tearDown(self): try: @@ -245,22 +245,26 @@ class PythonPluginTest(unittest.TestCase): except OSError as exc: if exc.errno != errno.ENOENT: raise + sys.path.remove(self.outdir) def testImportAttributes(self): # check that we can access the generated module and its members. - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_FACTORY_IDENTIFIER, None)) def testUpDown(self): - import test_pb2 + import protoc_plugin_test_pb2 as test_pb2 + reload(test_pb2) with _CreateService(test_pb2) as (servicer, stub): request = test_pb2.SimpleRequest(response_size=13) def testUnaryCall(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): request = test_pb2.SimpleRequest(response_size=13) response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT) @@ -268,7 +272,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testUnaryCallFuture(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2) as (methods, stub): # Check that the call does not block waiting for the server to respond. @@ -280,7 +285,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testUnaryCallFutureExpired(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): request = test_pb2.SimpleRequest(response_size=13) with methods.pause(): @@ -290,7 +296,8 @@ class PythonPluginTest(unittest.TestCase): response_future.result() def testUnaryCallFutureCancelled(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): @@ -299,7 +306,8 @@ class PythonPluginTest(unittest.TestCase): self.assertTrue(response_future.cancelled()) def testUnaryCallFutureFailed(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): @@ -308,7 +316,8 @@ class PythonPluginTest(unittest.TestCase): self.assertIsNotNone(response_future.exception()) def testStreamingOutputCall(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (methods, stub): responses = stub.StreamingOutputCall( @@ -320,7 +329,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testStreamingOutputCallExpired(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): @@ -330,7 +340,8 @@ class PythonPluginTest(unittest.TestCase): list(responses) def testStreamingOutputCallCancelled(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (unused_methods, stub): responses = stub.StreamingOutputCall( @@ -341,7 +352,8 @@ class PythonPluginTest(unittest.TestCase): next(responses) def testStreamingOutputCallFailed(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): @@ -351,7 +363,8 @@ class PythonPluginTest(unittest.TestCase): next(responses) def testStreamingInputCall(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): response = stub.StreamingInputCall( _streaming_input_request_iterator(test_pb2), @@ -361,7 +374,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testStreamingInputCallFuture(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.StreamingInputCall.future( @@ -373,7 +387,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testStreamingInputCallFutureExpired(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.StreamingInputCall.future( @@ -385,7 +400,8 @@ class PythonPluginTest(unittest.TestCase): response_future.exception(), face.ExpirationError) def testStreamingInputCallFutureCancelled(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.StreamingInputCall.future( @@ -397,7 +413,8 @@ class PythonPluginTest(unittest.TestCase): response_future.result() def testStreamingInputCallFutureFailed(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): response_future = stub.StreamingInputCall.future( @@ -406,7 +423,8 @@ class PythonPluginTest(unittest.TestCase): self.assertIsNotNone(response_future.exception()) def testFullDuplexCall(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): responses = stub.FullDuplexCall( _full_duplex_request_iterator(test_pb2), test_constants.LONG_TIMEOUT) @@ -417,7 +435,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testFullDuplexCallExpired(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): @@ -427,7 +446,8 @@ class PythonPluginTest(unittest.TestCase): list(responses) def testFullDuplexCallCancelled(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): request_iterator = _full_duplex_request_iterator(test_pb2) responses = stub.FullDuplexCall( @@ -438,7 +458,8 @@ class PythonPluginTest(unittest.TestCase): next(responses) def testFullDuplexCallFailed(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): @@ -449,7 +470,8 @@ class PythonPluginTest(unittest.TestCase): next(responses) def testHalfDuplexCall(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) with _CreateService(test_pb2) as (methods, stub): def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() @@ -468,7 +490,8 @@ class PythonPluginTest(unittest.TestCase): self.assertEqual(expected_response, response) def testHalfDuplexCallWedged(self): - import test_pb2 # pylint: disable=g-import-not-at-top + import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top + reload(test_pb2) condition = threading.Condition() wait_cell = [False] @contextlib.contextmanager diff --git a/src/python/grpcio_test/grpc_protoc_plugin/test.proto b/src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto index 6762a8e7f3..6762a8e7f3 100644 --- a/src/python/grpcio_test/grpc_protoc_plugin/test.proto +++ b/src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto diff --git a/src/python/grpcio_test/grpc_test/__init__.py b/src/python/grpcio/tests/unit/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/__init__.py +++ b/src/python/grpcio/tests/unit/__init__.py diff --git a/src/python/grpcio_test/grpc_test/_adapter/.gitignore b/src/python/grpcio/tests/unit/_adapter/.gitignore index a6f96cd6db..a6f96cd6db 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/.gitignore +++ b/src/python/grpcio/tests/unit/_adapter/.gitignore diff --git a/src/python/grpcio_test/grpc_test/_adapter/__init__.py b/src/python/grpcio/tests/unit/_adapter/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/__init__.py +++ b/src/python/grpcio/tests/unit/_adapter/__init__.py diff --git a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py index 90ad0b9bcb..a6fd82388c 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py +++ b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py @@ -115,6 +115,7 @@ class EchoTest(unittest.TestCase): def tearDown(self): self.server.stop() + self.server.cancel_all_calls() self.server_completion_queue.stop() self.client_completion_queue.stop() self.server_completion_queue_thread.join() @@ -286,11 +287,6 @@ class EchoTest(unittest.TestCase): set((server_trailing_metadata_key, server_trailing_binary_metadata_key,))) - server_timeout_none_event = self.server_completion_queue.get(0) - self.assertIsNone(server_timeout_none_event) - client_timeout_none_event = self.client_completion_queue.get(0) - self.assertIsNone(client_timeout_none_event) - self.assertSequenceEqual(test_data, server_data) self.assertSequenceEqual(test_data, client_data) @@ -335,6 +331,7 @@ class CancellationTest(unittest.TestCase): def tearDown(self): self.server.stop() + self.server.cancel_all_calls() self.server_completion_queue.stop() self.client_completion_queue.stop() self.server_completion_queue_thread.join() @@ -410,14 +407,9 @@ class CancellationTest(unittest.TestCase): finish_event = self.client_events.get() self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind) - self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), + self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), finish_event.status) - server_timeout_none_event = self.server_completion_queue.get(0) - self.assertIsNone(server_timeout_none_event) - client_timeout_none_event = self.client_completion_queue.get(0) - self.assertIsNone(client_timeout_none_event) - self.assertSequenceEqual(test_data, server_data) self.assertSequenceEqual(test_data, client_data) diff --git a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py b/src/python/grpcio/tests/unit/_adapter/_low_test.py index 8115cd0e83..ec46617996 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py +++ b/src/python/grpcio/tests/unit/_adapter/_low_test.py @@ -34,7 +34,7 @@ import unittest from grpc import _grpcio_metadata from grpc._adapter import _types from grpc._adapter import _low -from grpc_test import test_common +from tests.unit import test_common def wait_for_events(completion_queues, deadline): @@ -80,11 +80,11 @@ class InsecureServerInsecureClient(unittest.TestCase): del self.client_channel self.client_completion_queue.shutdown() - while (self.client_completion_queue.next().type != + while (self.client_completion_queue.next(float('+inf')).type != _types.EventType.QUEUE_SHUTDOWN): pass self.server_completion_queue.shutdown() - while (self.server_completion_queue.next().type != + while (self.server_completion_queue.next(float('+inf')).type != _types.EventType.QUEUE_SHUTDOWN): pass @@ -294,8 +294,12 @@ class HangingServerShutdown(unittest.TestCase): # Now try to shutdown the server and expect that we see server shutdown # almost immediately after calling cancel_all_calls. + + # First attempt to cancel all calls before shutting down, and expect + # our state machine to catch the erroneous API use. with self.assertRaises(RuntimeError): self.server.cancel_all_calls() + shutdown_tag = object() self.server.shutdown(shutdown_tag) pre_cancel_timestamp = time.time() diff --git a/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py index b3d6ec8607..f55a7a23ea 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py +++ b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py @@ -32,7 +32,7 @@ import abc import threading -from grpc_test._junkdrawer import math_pb2 +from tests.unit._junkdrawer import math_pb2 class ProtoScenario(object): diff --git a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py index cafb6b6eae..efc990421a 100644 --- a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py +++ b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py @@ -41,10 +41,10 @@ from grpc._links import service from grpc.beta import interfaces as beta_interfaces from grpc.framework.core import implementations from grpc.framework.interfaces.base import utilities -from grpc_test import test_common as grpc_test_common -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.base import test_cases -from grpc_test.framework.interfaces.base import test_interfaces +from tests.unit import test_common as grpc_test_common +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.base import test_cases +from tests.unit.framework.interfaces.base import test_interfaces class _SerializationBehaviors( diff --git a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py index a4d4dee38c..4faaaadc2b 100644 --- a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py +++ b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py @@ -40,10 +40,10 @@ 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 as grpc_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 tests.unit import test_common as grpc_test_common +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.face import test_cases +from tests.unit.framework.interfaces.face import test_interfaces class _SerializationBehaviors( diff --git a/src/python/grpcio_test/grpc_test/_cython/.gitignore b/src/python/grpcio/tests/unit/_cython/.gitignore index c315029288..c315029288 100644 --- a/src/python/grpcio_test/grpc_test/_cython/.gitignore +++ b/src/python/grpcio/tests/unit/_cython/.gitignore diff --git a/src/python/grpcio_test/grpc_test/_cython/__init__.py b/src/python/grpcio/tests/unit/_cython/__init__.py index b89398809f..b89398809f 100644 --- a/src/python/grpcio_test/grpc_test/_cython/__init__.py +++ b/src/python/grpcio/tests/unit/_cython/__init__.py diff --git a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py index 1307a30ca0..876da88de9 100644 --- a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py +++ b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py @@ -28,11 +28,24 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import time +import threading import unittest from grpc._cython import cygrpc -from grpc_test._cython import test_utilities -from grpc_test import test_common +from tests.unit._cython import test_utilities +from tests.unit import test_common +from tests.unit import resources + + +_SSL_HOST_OVERRIDE = 'foo.test.google.fr' +_CALL_CREDENTIALS_METADATA_KEY = 'call-creds-key' +_CALL_CREDENTIALS_METADATA_VALUE = 'call-creds-value' + +def _metadata_plugin_callback(context, callback): + callback(cygrpc.Metadata( + [cygrpc.Metadatum(_CALL_CREDENTIALS_METADATA_KEY, + _CALL_CREDENTIALS_METADATA_VALUE)]), + cygrpc.StatusCode.ok, '') class TypeSmokeTest(unittest.TestCase): @@ -89,7 +102,17 @@ class TypeSmokeTest(unittest.TestCase): channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([])) del channel - @unittest.skip('TODO(atash): undo skip after #2229 is merged') + def testCredentialsMetadataPluginUpDown(self): + plugin = cygrpc.CredentialsMetadataPlugin( + lambda ignored_a, ignored_b: None, '') + del plugin + + def testCallCredentialsFromPluginUpDown(self): + plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '') + call_credentials = cygrpc.call_credentials_metadata_plugin(plugin) + del plugin + del call_credentials + def testServerStartNoExplicitShutdown(self): server = cygrpc.Server() completion_queue = cygrpc.CompletionQueue() @@ -99,7 +122,6 @@ class TypeSmokeTest(unittest.TestCase): server.start() del server - @unittest.skip('TODO(atash): undo skip after #2229 is merged') def testServerStartShutdown(self): completion_queue = cygrpc.CompletionQueue() server = cygrpc.Server() @@ -262,5 +284,169 @@ class InsecureServerInsecureClient(unittest.TestCase): del server_call +class SecureServerSecureClient(unittest.TestCase): + + def setUp(self): + server_credentials = cygrpc.server_credentials_ssl( + None, [cygrpc.SslPemKeyCertPair(resources.private_key(), + resources.certificate_chain())], False) + channel_credentials = cygrpc.channel_credentials_ssl( + resources.test_root_certificates(), None) + self.server_completion_queue = cygrpc.CompletionQueue() + self.server = cygrpc.Server() + self.server.register_completion_queue(self.server_completion_queue) + self.port = self.server.add_http2_port('[::]:0', server_credentials) + self.server.start() + self.client_completion_queue = cygrpc.CompletionQueue() + client_channel_arguments = cygrpc.ChannelArgs([ + cygrpc.ChannelArg(cygrpc.ChannelArgKey.ssl_target_name_override, + _SSL_HOST_OVERRIDE)]) + self.client_channel = cygrpc.Channel( + 'localhost:{}'.format(self.port), client_channel_arguments, + channel_credentials) + + def tearDown(self): + del self.server + del self.client_completion_queue + del self.server_completion_queue + + def testEcho(self): + DEADLINE = time.time()+5 + DEADLINE_TOLERANCE = 0.25 + CLIENT_METADATA_ASCII_KEY = b'key' + CLIENT_METADATA_ASCII_VALUE = b'val' + CLIENT_METADATA_BIN_KEY = b'key-bin' + CLIENT_METADATA_BIN_VALUE = b'\0'*1000 + SERVER_INITIAL_METADATA_KEY = b'init_me_me_me' + SERVER_INITIAL_METADATA_VALUE = b'whodawha?' + SERVER_TRAILING_METADATA_KEY = b'california_is_in_a_drought' + SERVER_TRAILING_METADATA_VALUE = b'zomg it is' + SERVER_STATUS_CODE = cygrpc.StatusCode.ok + SERVER_STATUS_DETAILS = b'our work is never over' + REQUEST = b'in death a member of project mayhem has a name' + RESPONSE = b'his name is robert paulson' + METHOD = b'/twinkies' + HOST = None # Default host + + cygrpc_deadline = cygrpc.Timespec(DEADLINE) + + server_request_tag = object() + request_call_result = self.server.request_call( + self.server_completion_queue, self.server_completion_queue, + server_request_tag) + + self.assertEqual(cygrpc.CallError.ok, request_call_result) + + plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '') + call_credentials = cygrpc.call_credentials_metadata_plugin(plugin) + + client_call_tag = object() + client_call = self.client_channel.create_call( + None, 0, self.client_completion_queue, METHOD, HOST, cygrpc_deadline) + client_call.set_credentials(call_credentials) + client_initial_metadata = cygrpc.Metadata([ + cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY, + CLIENT_METADATA_ASCII_VALUE), + cygrpc.Metadatum(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]) + client_start_batch_result = client_call.start_batch(cygrpc.Operations([ + cygrpc.operation_send_initial_metadata(client_initial_metadata), + cygrpc.operation_send_message(REQUEST), + cygrpc.operation_send_close_from_client(), + cygrpc.operation_receive_initial_metadata(), + cygrpc.operation_receive_message(), + cygrpc.operation_receive_status_on_client() + ]), client_call_tag) + self.assertEqual(cygrpc.CallError.ok, client_start_batch_result) + client_event_future = test_utilities.CompletionQueuePollFuture( + self.client_completion_queue, cygrpc_deadline) + + request_event = self.server_completion_queue.poll(cygrpc_deadline) + self.assertEqual(cygrpc.CompletionType.operation_complete, + request_event.type) + self.assertIsInstance(request_event.operation_call, cygrpc.Call) + self.assertIs(server_request_tag, request_event.tag) + self.assertEqual(0, len(request_event.batch_operations)) + client_metadata_with_credentials = list(client_initial_metadata) + [ + (_CALL_CREDENTIALS_METADATA_KEY, _CALL_CREDENTIALS_METADATA_VALUE)] + self.assertTrue( + test_common.metadata_transmitted(client_metadata_with_credentials, + request_event.request_metadata)) + self.assertEqual(METHOD, request_event.request_call_details.method) + self.assertEqual(_SSL_HOST_OVERRIDE, + request_event.request_call_details.host) + self.assertLess( + abs(DEADLINE - float(request_event.request_call_details.deadline)), + DEADLINE_TOLERANCE) + + server_call_tag = object() + server_call = request_event.operation_call + server_initial_metadata = cygrpc.Metadata([ + cygrpc.Metadatum(SERVER_INITIAL_METADATA_KEY, + SERVER_INITIAL_METADATA_VALUE)]) + server_trailing_metadata = cygrpc.Metadata([ + cygrpc.Metadatum(SERVER_TRAILING_METADATA_KEY, + SERVER_TRAILING_METADATA_VALUE)]) + server_start_batch_result = server_call.start_batch([ + cygrpc.operation_send_initial_metadata(server_initial_metadata), + cygrpc.operation_receive_message(), + cygrpc.operation_send_message(RESPONSE), + cygrpc.operation_receive_close_on_server(), + cygrpc.operation_send_status_from_server( + server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS) + ], server_call_tag) + self.assertEqual(cygrpc.CallError.ok, server_start_batch_result) + + client_event = client_event_future.result() + server_event = self.server_completion_queue.poll(cygrpc_deadline) + + self.assertEqual(6, len(client_event.batch_operations)) + found_client_op_types = set() + for client_result in client_event.batch_operations: + # we expect each op type to be unique + self.assertNotIn(client_result.type, found_client_op_types) + found_client_op_types.add(client_result.type) + if client_result.type == cygrpc.OperationType.receive_initial_metadata: + self.assertTrue( + test_common.metadata_transmitted(server_initial_metadata, + client_result.received_metadata)) + elif client_result.type == cygrpc.OperationType.receive_message: + self.assertEqual(RESPONSE, client_result.received_message.bytes()) + elif client_result.type == cygrpc.OperationType.receive_status_on_client: + self.assertTrue( + test_common.metadata_transmitted(server_trailing_metadata, + client_result.received_metadata)) + self.assertEqual(SERVER_STATUS_DETAILS, + client_result.received_status_details) + self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code) + self.assertEqual(set([ + cygrpc.OperationType.send_initial_metadata, + cygrpc.OperationType.send_message, + cygrpc.OperationType.send_close_from_client, + cygrpc.OperationType.receive_initial_metadata, + cygrpc.OperationType.receive_message, + cygrpc.OperationType.receive_status_on_client + ]), found_client_op_types) + + self.assertEqual(5, len(server_event.batch_operations)) + found_server_op_types = set() + for server_result in server_event.batch_operations: + self.assertNotIn(client_result.type, found_server_op_types) + found_server_op_types.add(server_result.type) + if server_result.type == cygrpc.OperationType.receive_message: + self.assertEqual(REQUEST, server_result.received_message.bytes()) + elif server_result.type == cygrpc.OperationType.receive_close_on_server: + self.assertFalse(server_result.received_cancelled) + self.assertEqual(set([ + cygrpc.OperationType.send_initial_metadata, + cygrpc.OperationType.receive_message, + cygrpc.OperationType.send_message, + cygrpc.OperationType.receive_close_on_server, + cygrpc.OperationType.send_status_from_server + ]), found_server_op_types) + + del client_call + del server_call + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/_cython/test_utilities.py b/src/python/grpcio/tests/unit/_cython/test_utilities.py index 21ea3075b4..21ea3075b4 100644 --- a/src/python/grpcio_test/grpc_test/_cython/test_utilities.py +++ b/src/python/grpcio/tests/unit/_cython/test_utilities.py diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py b/src/python/grpcio/tests/unit/_junkdrawer/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py +++ b/src/python/grpcio/tests/unit/_junkdrawer/__init__.py diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py b/src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py index 20165955b4..20165955b4 100644 --- a/src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py +++ b/src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py b/src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py index eef18f82d6..eef18f82d6 100644 --- a/src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py +++ b/src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py diff --git a/src/python/grpcio_test/grpc_test/_links/__init__.py b/src/python/grpcio/tests/unit/_links/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/_links/__init__.py +++ b/src/python/grpcio/tests/unit/_links/__init__.py diff --git a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py index 8e12e8cc22..890755f81c 100644 --- a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py +++ b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py @@ -34,9 +34,9 @@ import unittest from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc.framework.interfaces.links import links -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.links import test_cases -from grpc_test.framework.interfaces.links import test_utilities +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.links import test_cases +from tests.unit.framework.interfaces.links import test_utilities _NULL_BEHAVIOR = lambda unused_argument: None diff --git a/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py index 0d74d66297..f69ff51b16 100644 --- a/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py +++ b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py @@ -32,8 +32,8 @@ import abc import threading -from grpc_test._junkdrawer import math_pb2 -from grpc_test.framework.common import test_constants +from tests.unit._junkdrawer import math_pb2 +from tests.unit.framework.common import test_constants class ProtoScenario(object): diff --git a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py b/src/python/grpcio/tests/unit/_links/_transmission_test.py index 77e83d5561..888684d197 100644 --- a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py +++ b/src/python/grpcio/tests/unit/_links/_transmission_test.py @@ -36,11 +36,11 @@ from grpc._links import invocation from grpc._links import service from grpc.beta import interfaces as beta_interfaces from grpc.framework.interfaces.links import links -from grpc_test import test_common -from grpc_test._links import _proto_scenarios -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.links import test_cases -from grpc_test.framework.interfaces.links import test_utilities +from tests.unit import test_common +from tests.unit._links import _proto_scenarios +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.links import test_cases +from tests.unit.framework.interfaces.links import test_utilities _IDENTITY = lambda x: x diff --git a/src/python/grpcio_test/grpc_test/beta/__init__.py b/src/python/grpcio/tests/unit/beta/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/beta/__init__.py +++ b/src/python/grpcio/tests/unit/beta/__init__.py diff --git a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py b/src/python/grpcio/tests/unit/beta/_beta_features_test.py index 5916a9e3ea..ea44177b49 100644 --- a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py +++ b/src/python/grpcio/tests/unit/beta/_beta_features_test.py @@ -36,12 +36,15 @@ from grpc.beta import implementations from grpc.beta import interfaces from grpc.framework.common import cardinality from grpc.framework.interfaces.face import utilities -from grpc_test import resources -from grpc_test.beta import test_utilities -from grpc_test.framework.common import test_constants +from tests.unit import resources +from tests.unit.beta import test_utilities +from tests.unit.framework.common import test_constants _SERVER_HOST_OVERRIDE = 'foo.test.google.fr' +_PER_RPC_CREDENTIALS_METADATA_KEY = 'my-call-credentials-metadata-key' +_PER_RPC_CREDENTIALS_METADATA_VALUE = 'my-call-credentials-metadata-value' + _GROUP = 'group' _UNARY_UNARY = 'unary-unary' _UNARY_STREAM = 'unary-stream' @@ -63,6 +66,7 @@ class _Servicer(object): with self._condition: self._request = request self._peer = context.protocol_context().peer() + self._invocation_metadata = context.invocation_metadata() context.protocol_context().disable_next_response_compression() self._serviced = True self._condition.notify_all() @@ -72,6 +76,7 @@ class _Servicer(object): with self._condition: self._request = request self._peer = context.protocol_context().peer() + self._invocation_metadata = context.invocation_metadata() context.protocol_context().disable_next_response_compression() self._serviced = True self._condition.notify_all() @@ -83,6 +88,7 @@ class _Servicer(object): self._request = request with self._condition: self._peer = context.protocol_context().peer() + self._invocation_metadata = context.invocation_metadata() context.protocol_context().disable_next_response_compression() self._serviced = True self._condition.notify_all() @@ -95,6 +101,7 @@ class _Servicer(object): context.protocol_context().disable_next_response_compression() yield _RESPONSE with self._condition: + self._invocation_metadata = context.invocation_metadata() self._serviced = True self._condition.notify_all() @@ -137,6 +144,11 @@ class _BlockingIterator(object): self._condition.notify_all() +def _metadata_plugin(context, callback): + callback([(_PER_RPC_CREDENTIALS_METADATA_KEY, + _PER_RPC_CREDENTIALS_METADATA_VALUE)], None) + + class BetaFeaturesTest(unittest.TestCase): def setUp(self): @@ -167,10 +179,12 @@ class BetaFeaturesTest(unittest.TestCase): [(resources.private_key(), resources.certificate_chain(),),]) port = self._server.add_secure_port('[::]:0', server_credentials) self._server.start() - self._client_credentials = implementations.ssl_client_credentials( + self._channel_credentials = implementations.ssl_channel_credentials( resources.test_root_certificates(), None, None) + self._call_credentials = implementations.metadata_call_credentials( + _metadata_plugin) channel = test_utilities.not_really_secure_channel( - 'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE) + 'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE) stub_options = implementations.stub_options( thread_pool_size=test_constants.POOL_SIZE) self._dynamic_stub = implementations.dynamic_stub( @@ -181,21 +195,36 @@ class BetaFeaturesTest(unittest.TestCase): self._server.stop(test_constants.SHORT_TIMEOUT).wait() def test_unary_unary(self): - call_options = interfaces.grpc_call_options(disable_compression=True) + call_options = interfaces.grpc_call_options( + disable_compression=True, credentials=self._call_credentials) response = getattr(self._dynamic_stub, _UNARY_UNARY)( _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) self.assertEqual(_RESPONSE, response) self.assertIsNotNone(self._servicer.peer()) + invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in + self._servicer._invocation_metadata] + self.assertIn( + (_PER_RPC_CREDENTIALS_METADATA_KEY, + _PER_RPC_CREDENTIALS_METADATA_VALUE), + invocation_metadata) def test_unary_stream(self): - call_options = interfaces.grpc_call_options(disable_compression=True) + call_options = interfaces.grpc_call_options( + disable_compression=True, credentials=self._call_credentials) response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)( _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) + invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in + self._servicer._invocation_metadata] + self.assertIn( + (_PER_RPC_CREDENTIALS_METADATA_KEY, + _PER_RPC_CREDENTIALS_METADATA_VALUE), + invocation_metadata) def test_stream_unary(self): - call_options = interfaces.grpc_call_options() + call_options = interfaces.grpc_call_options( + credentials=self._call_credentials) request_iterator = _BlockingIterator(iter((_REQUEST,))) response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future( request_iterator, test_constants.LONG_TIMEOUT, @@ -207,9 +236,16 @@ class BetaFeaturesTest(unittest.TestCase): self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) self.assertEqual(_RESPONSE, response_future.result()) + invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in + self._servicer._invocation_metadata] + self.assertIn( + (_PER_RPC_CREDENTIALS_METADATA_KEY, + _PER_RPC_CREDENTIALS_METADATA_VALUE), + invocation_metadata) def test_stream_stream(self): - call_options = interfaces.grpc_call_options() + call_options = interfaces.grpc_call_options( + credentials=self._call_credentials) request_iterator = _BlockingIterator(iter((_REQUEST,))) response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)( request_iterator, test_constants.SHORT_TIMEOUT, @@ -222,6 +258,85 @@ class BetaFeaturesTest(unittest.TestCase): self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) self.assertEqual(_RESPONSE, response) + invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in + self._servicer._invocation_metadata] + self.assertIn( + (_PER_RPC_CREDENTIALS_METADATA_KEY, + _PER_RPC_CREDENTIALS_METADATA_VALUE), + invocation_metadata) + + +class ContextManagementAndLifecycleTest(unittest.TestCase): + + def setUp(self): + self._servicer = _Servicer() + self._method_implementations = { + (_GROUP, _UNARY_UNARY): + utilities.unary_unary_inline(self._servicer.unary_unary), + (_GROUP, _UNARY_STREAM): + utilities.unary_stream_inline(self._servicer.unary_stream), + (_GROUP, _STREAM_UNARY): + utilities.stream_unary_inline(self._servicer.stream_unary), + (_GROUP, _STREAM_STREAM): + utilities.stream_stream_inline(self._servicer.stream_stream), + } + + self._cardinalities = { + _UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY, + _UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM, + _STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY, + _STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM, + } + + self._server_options = implementations.server_options( + thread_pool_size=test_constants.POOL_SIZE) + self._server_credentials = implementations.ssl_server_credentials( + [(resources.private_key(), resources.certificate_chain(),),]) + self._channel_credentials = implementations.ssl_channel_credentials( + resources.test_root_certificates(), None, None) + self._stub_options = implementations.stub_options( + thread_pool_size=test_constants.POOL_SIZE) + + def test_stub_context(self): + server = implementations.server( + self._method_implementations, options=self._server_options) + port = server.add_secure_port('[::]:0', self._server_credentials) + server.start() + + channel = test_utilities.not_really_secure_channel( + 'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE) + dynamic_stub = implementations.dynamic_stub( + channel, _GROUP, self._cardinalities, options=self._stub_options) + for _ in range(100): + with dynamic_stub: + pass + for _ in range(10): + with dynamic_stub: + call_options = interfaces.grpc_call_options( + disable_compression=True) + response = getattr(dynamic_stub, _UNARY_UNARY)( + _REQUEST, test_constants.LONG_TIMEOUT, + protocol_options=call_options) + self.assertEqual(_RESPONSE, response) + self.assertIsNotNone(self._servicer.peer()) + + server.stop(test_constants.SHORT_TIMEOUT).wait() + + def test_server_lifecycle(self): + for _ in range(100): + server = implementations.server( + self._method_implementations, options=self._server_options) + port = server.add_secure_port('[::]:0', self._server_credentials) + server.start() + server.stop(test_constants.SHORT_TIMEOUT).wait() + for _ in range(100): + server = implementations.server( + self._method_implementations, options=self._server_options) + server.add_secure_port('[::]:0', self._server_credentials) + server.add_insecure_port('[::]:0') + with server: + server.stop(test_constants.SHORT_TIMEOUT) + server.stop(test_constants.SHORT_TIMEOUT) if __name__ == '__main__': diff --git a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py index b3c05bdb0c..5dc8720639 100644 --- a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py +++ b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py @@ -37,7 +37,7 @@ from grpc._adapter import _low from grpc._adapter import _types from grpc.beta import _connectivity_channel from grpc.beta import interfaces -from grpc_test.framework.common import test_constants +from tests.unit.framework.common import test_constants def _drive_completion_queue(completion_queue): diff --git a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py b/src/python/grpcio/tests/unit/beta/_face_interface_test.py index aa33e1e6f8..1c21dfd03d 100644 --- a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py +++ b/src/python/grpcio/tests/unit/beta/_face_interface_test.py @@ -34,12 +34,12 @@ import unittest from grpc.beta import implementations from grpc.beta import interfaces -from grpc_test import resources -from grpc_test import test_common as grpc_test_common -from grpc_test.beta import test_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 tests.unit import resources +from tests.unit import test_common as grpc_test_common +from tests.unit.beta import test_utilities +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.face import test_cases +from tests.unit.framework.interfaces.face import test_interfaces _SERVER_HOST_OVERRIDE = 'foo.test.google.fr' @@ -91,10 +91,10 @@ class _Implementation(test_interfaces.Implementation): [(resources.private_key(), resources.certificate_chain(),),]) port = server.add_secure_port('[::]:0', server_credentials) server.start() - client_credentials = implementations.ssl_client_credentials( + channel_credentials = implementations.ssl_channel_credentials( resources.test_root_certificates(), None, None) channel = test_utilities.not_really_secure_channel( - 'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE) + 'localhost', port, channel_credentials, _SERVER_HOST_OVERRIDE) stub_options = implementations.stub_options( request_serializers=serialization_behaviors.request_serializers, response_deserializers=serialization_behaviors.response_deserializers, diff --git a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py b/src/python/grpcio/tests/unit/beta/_not_found_test.py index 5feb997fef..44fcd1e13c 100644 --- a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py +++ b/src/python/grpcio/tests/unit/beta/_not_found_test.py @@ -34,7 +34,7 @@ import unittest from grpc.beta import implementations from grpc.beta import interfaces from grpc.framework.interfaces.face import face -from grpc_test.framework.common import test_constants +from tests.unit.framework.common import test_constants class NotFoundTest(unittest.TestCase): diff --git a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py b/src/python/grpcio/tests/unit/beta/_utilities_test.py index 996cea9118..08ce98e751 100644 --- a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py +++ b/src/python/grpcio/tests/unit/beta/_utilities_test.py @@ -38,7 +38,7 @@ from grpc._adapter import _types from grpc.beta import implementations from grpc.beta import utilities from grpc.framework.foundation import future -from grpc_test.framework.common import test_constants +from tests.unit.framework.common import test_constants def _drive_completion_queue(completion_queue): diff --git a/src/python/grpcio_test/grpc_test/beta/test_utilities.py b/src/python/grpcio/tests/unit/beta/test_utilities.py index 24a8600e12..0313e06a93 100644 --- a/src/python/grpcio_test/grpc_test/beta/test_utilities.py +++ b/src/python/grpcio/tests/unit/beta/test_utilities.py @@ -34,13 +34,13 @@ from grpc.beta import implementations def not_really_secure_channel( - host, port, client_credentials, server_host_override): + host, port, channel_credentials, server_host_override): """Creates an insecure Channel to a remote host. Args: host: The name of the remote host to which to connect. port: The port of the remote host to which to connect. - client_credentials: The implementations.ClientCredentials with which to + channel_credentials: The implementations.ChannelCredentials with which to connect. server_host_override: The target name used for SSL host name checking. @@ -50,7 +50,7 @@ def not_really_secure_channel( """ hostport = '%s:%d' % (host, port) intermediary_low_channel = _intermediary_low.Channel( - hostport, client_credentials._intermediary_low_credentials, + hostport, channel_credentials._low_credentials, server_host_override=server_host_override) return implementations.Channel( intermediary_low_channel._internal, intermediary_low_channel) diff --git a/src/python/grpcio_test/grpc_test/credentials/README b/src/python/grpcio/tests/unit/credentials/README index cb20dcb49f..cb20dcb49f 100644 --- a/src/python/grpcio_test/grpc_test/credentials/README +++ b/src/python/grpcio/tests/unit/credentials/README diff --git a/src/python/grpcio_test/grpc_test/credentials/ca.pem b/src/python/grpcio/tests/unit/credentials/ca.pem index 6c8511a73c..6c8511a73c 100755 --- a/src/python/grpcio_test/grpc_test/credentials/ca.pem +++ b/src/python/grpcio/tests/unit/credentials/ca.pem diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.key b/src/python/grpcio/tests/unit/credentials/server1.key index 143a5b8765..143a5b8765 100755 --- a/src/python/grpcio_test/grpc_test/credentials/server1.key +++ b/src/python/grpcio/tests/unit/credentials/server1.key diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio/tests/unit/credentials/server1.pem index f3d43fcc5b..f3d43fcc5b 100755 --- a/src/python/grpcio_test/grpc_test/credentials/server1.pem +++ b/src/python/grpcio/tests/unit/credentials/server1.pem diff --git a/src/python/grpcio_test/grpc_test/framework/__init__.py b/src/python/grpcio/tests/unit/framework/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/__init__.py +++ b/src/python/grpcio/tests/unit/framework/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py index 30bb85f6c3..360ecc95d5 100644 --- a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py +++ b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py @@ -36,10 +36,10 @@ 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 +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.face import test_cases +from tests.unit.framework.interfaces.face import test_interfaces +from tests.unit.framework.interfaces.links import test_utilities class _Implementation(test_interfaces.Implementation): diff --git a/src/python/grpcio_test/grpc_test/framework/common/__init__.py b/src/python/grpcio/tests/unit/framework/common/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/common/__init__.py +++ b/src/python/grpcio/tests/unit/framework/common/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py b/src/python/grpcio/tests/unit/framework/common/test_constants.py index e1d3c2709d..e1d3c2709d 100644 --- a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py +++ b/src/python/grpcio/tests/unit/framework/common/test_constants.py diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_control.py b/src/python/grpcio/tests/unit/framework/common/test_control.py index 8d6eba5c2c..8d6eba5c2c 100644 --- a/src/python/grpcio_test/grpc_test/framework/common/test_control.py +++ b/src/python/grpcio/tests/unit/framework/common/test_control.py diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_coverage.py b/src/python/grpcio/tests/unit/framework/common/test_coverage.py index a7ed3582c4..a7ed3582c4 100644 --- a/src/python/grpcio_test/grpc_test/framework/common/test_coverage.py +++ b/src/python/grpcio/tests/unit/framework/common/test_coverage.py diff --git a/src/python/grpcio_test/grpc_test/framework/core/__init__.py b/src/python/grpcio/tests/unit/framework/core/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/core/__init__.py +++ b/src/python/grpcio/tests/unit/framework/core/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py index 8d72f131d5..1310292306 100644 --- a/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py +++ b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py @@ -36,9 +36,9 @@ import unittest from grpc.framework.core import implementations from grpc.framework.interfaces.base import utilities -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.base import test_cases -from grpc_test.framework.interfaces.base import test_interfaces +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.base import test_cases +from tests.unit.framework.interfaces.base import test_interfaces class _Implementation(test_interfaces.Implementation): diff --git a/src/python/grpcio_test/grpc_test/framework/face/__init__.py b/src/python/grpcio/tests/unit/framework/face/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/__init__.py +++ b/src/python/grpcio/tests/unit/framework/face/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py b/src/python/grpcio/tests/unit/framework/face/testing/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py index 1df1529b27..1df1529b27 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py index 251e1eb68e..0613516421 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py @@ -34,12 +34,12 @@ import abc import unittest # pylint: disable=unused-import from grpc.framework.face import exceptions -from grpc_test.framework.common import test_constants -from grpc_test.framework.face.testing import control -from grpc_test.framework.face.testing import coverage -from grpc_test.framework.face.testing import digest -from grpc_test.framework.face.testing import stock_service -from grpc_test.framework.face.testing import test_case +from tests.unit.framework.common import test_constants +from tests.unit.framework.face.testing import control +from tests.unit.framework.face.testing import coverage +from tests.unit.framework.face.testing import digest +from tests.unit.framework.face.testing import stock_service +from tests.unit.framework.face.testing import test_case class BlockingInvocationInlineServiceTestCase( diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/callback.py b/src/python/grpcio/tests/unit/framework/face/testing/callback.py index d0e63c8c56..d0e63c8c56 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/callback.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/callback.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/control.py b/src/python/grpcio/tests/unit/framework/face/testing/control.py index 3960c4e649..3960c4e649 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/control.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/control.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py index f3aca113fe..f3aca113fe 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py b/src/python/grpcio/tests/unit/framework/face/testing/digest.py index 54ff21779a..39f28b9657 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/digest.py @@ -40,9 +40,9 @@ from grpc.framework.face import exceptions from grpc.framework.face import interfaces as face_interfaces from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util -from grpc_test.framework.face.testing import control as testing_control # pylint: disable=unused-import -from grpc_test.framework.face.testing import interfaces # pylint: disable=unused-import -from grpc_test.framework.face.testing import service as testing_service # pylint: disable=unused-import +from tests.unit.framework.face.testing import control as testing_control # pylint: disable=unused-import +from tests.unit.framework.face.testing import interfaces # pylint: disable=unused-import +from tests.unit.framework.face.testing import service as testing_service # pylint: disable=unused-import _IDENTITY = lambda x: x diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py index 9df77678eb..179f3a2f67 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py @@ -33,13 +33,13 @@ import abc import unittest from grpc.framework.face import interfaces -from grpc_test.framework.common import test_constants -from grpc_test.framework.face.testing import callback as testing_callback -from grpc_test.framework.face.testing import control -from grpc_test.framework.face.testing import coverage -from grpc_test.framework.face.testing import digest -from grpc_test.framework.face.testing import stock_service -from grpc_test.framework.face.testing import test_case +from tests.unit.framework.common import test_constants +from tests.unit.framework.face.testing import callback as testing_callback +from tests.unit.framework.face.testing import control +from tests.unit.framework.face.testing import coverage +from tests.unit.framework.face.testing import digest +from tests.unit.framework.face.testing import stock_service +from tests.unit.framework.face.testing import test_case class EventInvocationSynchronousEventServiceTestCase( diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py index 70d86a0422..485524a356 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py @@ -37,12 +37,12 @@ import unittest from grpc.framework.face import exceptions from grpc.framework.foundation import future from grpc.framework.foundation import logging_pool -from grpc_test.framework.common import test_constants -from grpc_test.framework.face.testing import control -from grpc_test.framework.face.testing import coverage -from grpc_test.framework.face.testing import digest -from grpc_test.framework.face.testing import stock_service -from grpc_test.framework.face.testing import test_case +from tests.unit.framework.common import test_constants +from tests.unit.framework.face.testing import control +from tests.unit.framework.face.testing import coverage +from tests.unit.framework.face.testing import digest +from tests.unit.framework.face.testing import stock_service +from tests.unit.framework.face.testing import test_case _MAXIMUM_POOL_SIZE = 10 diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py index 5932dabf1e..5932dabf1e 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/service.py b/src/python/grpcio/tests/unit/framework/face/testing/service.py index ee9d6a3da3..ac0b89b6ee 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/service.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/service.py @@ -33,7 +33,7 @@ import abc # interfaces is referenced from specification in this module. from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import -from grpc_test.framework.face.testing import interfaces +from tests.unit.framework.face.testing import interfaces class UnaryUnaryTestMethodImplementation(interfaces.Method): diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py index 0f83ca4db1..117c723f79 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py @@ -33,8 +33,8 @@ from grpc.framework.common import cardinality from grpc.framework.foundation import abandonment from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util -from grpc_test.framework.face.testing import service -from grpc_test._junkdrawer import stock_pb2 +from tests.unit.framework.face.testing import service +from tests.unit._junkdrawer import stock_pb2 SYMBOL_FORMAT = 'test symbol:%03d' STREAM_LENGTH = 400 diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py index 858d5cf7fd..23d4d919c2 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py @@ -33,7 +33,7 @@ import abc # face_interfaces and interfaces are referenced in specification in this module. from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import -from grpc_test.framework.face.testing import interfaces # pylint: disable=unused-import +from tests.unit.framework.face.testing import interfaces # pylint: disable=unused-import class FaceTestCase(object): diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/__init__.py b/src/python/grpcio/tests/unit/framework/foundation/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/foundation/__init__.py +++ b/src/python/grpcio/tests/unit/framework/foundation/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py index 6c2459e185..6c2459e185 100644 --- a/src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py +++ b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py index 452802da6a..452802da6a 100644 --- a/src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py +++ b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py b/src/python/grpcio/tests/unit/framework/foundation/stream_testing.py index 098a53d5e7..098a53d5e7 100644 --- a/src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py +++ b/src/python/grpcio/tests/unit/framework/foundation/stream_testing.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py index 46a01876d8..38102b198a 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py @@ -37,10 +37,10 @@ import threading import time from grpc.framework.interfaces.base import base -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.base import _sequence -from grpc_test.framework.interfaces.base import _state -from grpc_test.framework.interfaces.base import test_interfaces # pylint: disable=unused-import +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.base import _sequence +from tests.unit.framework.interfaces.base import _state +from tests.unit.framework.interfaces.base import test_interfaces # pylint: disable=unused-import _GROUP = 'base test cases test group' _METHOD = 'base test cases test method' diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py index f547d91681..571d0e1e63 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py @@ -33,7 +33,7 @@ import collections import enum from grpc.framework.interfaces.base import base -from grpc_test.framework.common import test_constants +from tests.unit.framework.common import test_constants class Invocation( diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_state.py index 21cf33aeb6..21cf33aeb6 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_state.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py index ddda1018c3..4f8e26c9a2 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py @@ -38,9 +38,9 @@ import unittest from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.base import base from grpc.framework.interfaces.base import utilities -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.base import _control -from grpc_test.framework.interfaces.base import test_interfaces +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.base import _control +from tests.unit.framework.interfaces.base import test_interfaces _SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True)) @@ -271,6 +271,7 @@ def test_cases(implementation): '_randomness': randomness, '_synchronicity_variation': synchronicity_variation[1], '_controller_creator': controller_creator, + '__module__': implementation.__module__, })) return test_case_classes diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py index 02426ab846..84afd24d47 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py @@ -131,7 +131,7 @@ class Implementation(object): @abc.abstractmethod def service_initial_metadata(self): - """Provices an operation's service-side initial metadata. + """Provides an operation's service-side initial metadata. Returns: A value to use for an operation's service-side initial metadata, or diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py index 363d9ce8f1..1ea356c0bf 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py @@ -30,7 +30,7 @@ """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 +from tests.unit.framework.common import test_constants # pylint: disable=unused-import # TODO(issue 3069): Replace uses of this constant with # test_constants.SHORT_TIMEOUT. diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py index 2d2a081955..3bcefa601d 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py @@ -34,13 +34,13 @@ import unittest # test_interfaces is referenced from specification in this module. 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 +from tests.unit.framework.common import test_constants +from tests.unit.framework.common import test_control +from tests.unit.framework.common import test_coverage +from tests.unit.framework.interfaces.face import _3069_test_constant +from tests.unit.framework.interfaces.face import _digest +from tests.unit.framework.interfaces.face import _stock_service +from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import class TestCase(test_coverage.Coverage, unittest.TestCase): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py index da56ed7b27..9304b6b1db 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py @@ -39,9 +39,9 @@ from grpc.framework.common import style from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util from grpc.framework.interfaces.face import face -from grpc_test.framework.common import test_control # pylint: disable=unused-import -from grpc_test.framework.interfaces.face import _service # pylint: disable=unused-import -from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import +from tests.unit.framework.common import test_control # pylint: disable=unused-import +from tests.unit.framework.interfaces.face import _service # pylint: disable=unused-import +from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import _IDENTITY = lambda x: x diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py index 7cb273bf78..34db6c3e55 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py @@ -34,14 +34,14 @@ import unittest # test_interfaces is referenced from specification in this module. 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 -from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import +from tests.unit.framework.common import test_constants +from tests.unit.framework.common import test_control +from tests.unit.framework.common import test_coverage +from tests.unit.framework.interfaces.face import _3069_test_constant +from tests.unit.framework.interfaces.face import _digest +from tests.unit.framework.interfaces.face import _receiver +from tests.unit.framework.interfaces.face import _stock_service +from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import class TestCase(test_coverage.Coverage, unittest.TestCase): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py index 3032736975..c178f2f108 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py @@ -37,13 +37,13 @@ import unittest # test_interfaces is referenced from specification in this module. from grpc.framework.foundation import logging_pool 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 +from tests.unit.framework.common import test_constants +from tests.unit.framework.common import test_control +from tests.unit.framework.common import test_coverage +from tests.unit.framework.interfaces.face import _3069_test_constant +from tests.unit.framework.interfaces.face import _digest +from tests.unit.framework.interfaces.face import _stock_service +from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import class _PauseableIterator(object): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py index 448e845a08..448e845a08 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py index 2e444ff09d..2e444ff09d 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py index e25b8a038c..28941e2ad0 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py @@ -33,7 +33,7 @@ import abc # face is referenced from specification in this module. from grpc.framework.interfaces.face import face # pylint: disable=unused-import -from grpc_test.framework.interfaces.face import test_interfaces +from tests.unit.framework.interfaces.face import test_interfaces class UnaryUnaryTestMethodImplementation(test_interfaces.Method): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py index 808e2c4e36..5299655bb3 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py @@ -32,9 +32,9 @@ from grpc.framework.common import cardinality from grpc.framework.foundation import abandonment from grpc.framework.foundation import stream -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.face import _service -from grpc_test._junkdrawer import stock_pb2 +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.face import _service +from tests.unit._junkdrawer import stock_pb2 _STOCK_GROUP_NAME = 'Stock' _SYMBOL_FORMAT = 'test symbol:%03d' diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py index ca623662f7..462829b660 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py @@ -33,11 +33,11 @@ import unittest # pylint: disable=unused-import # test_interfaces is referenced from specification in this module. -from grpc_test.framework.interfaces.face import _blocking_invocation_inline_service -from grpc_test.framework.interfaces.face import _event_invocation_synchronous_event_service -from grpc_test.framework.interfaces.face import _future_invocation_asynchronous_event_service -from grpc_test.framework.interfaces.face import _invocation -from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import +from tests.unit.framework.interfaces.face import _blocking_invocation_inline_service +from tests.unit.framework.interfaces.face import _event_invocation_synchronous_event_service +from tests.unit.framework.interfaces.face import _future_invocation_asynchronous_event_service +from tests.unit.framework.interfaces.face import _invocation +from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import _TEST_CASE_SUPERCLASSES = ( _blocking_invocation_inline_service.TestCase, @@ -63,5 +63,7 @@ def test_cases(implementation): test_case_classes.append( type(invoker_constructor.name() + super_class.NAME, (super_class,), {'implementation': implementation, - 'invoker_constructor': invoker_constructor})) + 'invoker_constructor': invoker_constructor, + '__module__': implementation.__module__, + })) return test_case_classes diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py index b2b5c10fa6..b2b5c10fa6 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py index 7086519106..7086519106 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py index ecf49d9cdb..dace6c23f3 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py @@ -34,8 +34,8 @@ import abc import unittest # pylint: disable=unused-import from grpc.framework.interfaces.links import links -from grpc_test.framework.common import test_constants -from grpc_test.framework.interfaces.links import test_utilities +from tests.unit.framework.common import test_constants +from tests.unit.framework.interfaces.links import test_utilities def at_least_n_payloads_received_predicate(n): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py index 39c7f2fc63..39c7f2fc63 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py diff --git a/src/python/grpcio_test/grpc_test/resources.py b/src/python/grpcio/tests/unit/resources.py index 2c3045313d..2c3045313d 100644 --- a/src/python/grpcio_test/grpc_test/resources.py +++ b/src/python/grpcio/tests/unit/resources.py diff --git a/src/python/grpcio_test/grpc_test/test_common.py b/src/python/grpcio/tests/unit/test_common.py index 29431bfb9d..29431bfb9d 100644 --- a/src/python/grpcio_test/grpc_test/test_common.py +++ b/src/python/grpcio/tests/unit/test_common.py diff --git a/src/python/grpcio/tox.ini b/src/python/grpcio/tox.ini new file mode 100644 index 0000000000..bfb1ca0cfa --- /dev/null +++ b/src/python/grpcio/tox.ini @@ -0,0 +1,19 @@ +# Tox (http://tox.testrun.org/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +skipsdist = true +envlist = py27 + +[testenv] +commands = + {envpython} setup.py build_py + {envpython} setup.py test + coverage combine + coverage html --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py' + coverage report --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py' +deps = + -rrequirements.txt +passenv = * diff --git a/src/python/grpcio_test/.gitignore b/src/python/grpcio_test/.gitignore deleted file mode 100644 index 6158313bde..0000000000 --- a/src/python/grpcio_test/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -MANIFEST -*.egg-info/ -build/ -dist/ -*.egg -*.egg/ -*.eggs/ -*_pb2.py -.coverage -.coverage.* -.cache/ -nosetests.xml diff --git a/src/python/grpcio_test/MANIFEST.in b/src/python/grpcio_test/MANIFEST.in deleted file mode 100644 index c9327307dc..0000000000 --- a/src/python/grpcio_test/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -graft grpc_interop -graft grpc_test -include commands.py -include requirements.txt diff --git a/src/python/grpcio_test/commands.py b/src/python/grpcio_test/commands.py deleted file mode 100644 index edaa2aa72d..0000000000 --- a/src/python/grpcio_test/commands.py +++ /dev/null @@ -1,106 +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. - -"""Provides distutils command classes for the GRPC Python test setup process.""" - -import distutils -import os -import os.path -import subprocess -import sys - -import setuptools -from setuptools.command import build_py - - -class RunTests(setuptools.Command): - """Command to run all tests via py.test.""" - - description = '' - user_options = [('pytest-args=', 'a', 'arguments to pass to py.test')] - - def initialize_options(self): - self.pytest_args = [] - - def finalize_options(self): - pass - - def run(self): - # We import here to ensure that setup.py has had a chance to install the - # relevant package eggs first. - import pytest - - self.run_command('build_proto_modules') - result = pytest.main(self.pytest_args) - if result != 0: - raise SystemExit(result) - - -class BuildProtoModules(setuptools.Command): - """Command to generate project *_pb2.py modules from proto files.""" - - description = '' - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - self.protoc_command = distutils.spawn.find_executable('protoc') - self.grpc_python_plugin_command = distutils.spawn.find_executable( - 'grpc_python_plugin') - - def run(self): - paths = [] - root_directory = os.getcwd() - for walk_root, directories, filenames in os.walk(root_directory): - for filename in filenames: - if filename.endswith('.proto'): - paths.append(os.path.join(walk_root, filename)) - command = [ - self.protoc_command, - '--plugin=protoc-gen-python-grpc={}'.format( - self.grpc_python_plugin_command), - '-I {}'.format(root_directory), - '--python_out={}'.format(root_directory), - '--python-grpc_out={}'.format(root_directory), - ] + paths - try: - subprocess.check_output(' '.join(command), cwd=root_directory, shell=True, - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise Exception('{}\nOutput:\n{}'.format(e.message, e.output)) - - -class BuildPy(build_py.build_py): - """Custom project build command.""" - - def run(self): - self.run_command('build_proto_modules') - build_py.build_py.run(self) diff --git a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py b/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py deleted file mode 100644 index f1bec238cf..0000000000 --- a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py +++ /dev/null @@ -1,187 +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. - -# Fork of grpc._adapter._low_test; the grpc._cython.types adapter in -# grpc._cython.low should transparently support the semantics expected of -# grpc._adapter._low. - -import time -import unittest - -from grpc._adapter import _types -from grpc._cython import adapter_low as _low - - -class InsecureServerInsecureClient(unittest.TestCase): - - def setUp(self): - self.server_completion_queue = _low.CompletionQueue() - self.server = _low.Server(self.server_completion_queue, []) - self.port = self.server.add_http2_port('[::]:0') - self.client_completion_queue = _low.CompletionQueue() - self.client_channel = _low.Channel('localhost:%d'%self.port, []) - - self.server.start() - - def tearDown(self): - self.server.shutdown() - del self.client_channel - - self.client_completion_queue.shutdown() - while (self.client_completion_queue.next().type != - _types.EventType.QUEUE_SHUTDOWN): - pass - self.server_completion_queue.shutdown() - while (self.server_completion_queue.next().type != - _types.EventType.QUEUE_SHUTDOWN): - pass - - del self.client_completion_queue - del self.server_completion_queue - del self.server - - @unittest.skip('TODO(atash): implement grpc._cython.adapter_low') - def testEcho(self): - DEADLINE = time.time()+5 - DEADLINE_TOLERANCE = 0.25 - CLIENT_METADATA_ASCII_KEY = 'key' - CLIENT_METADATA_ASCII_VALUE = 'val' - CLIENT_METADATA_BIN_KEY = 'key-bin' - CLIENT_METADATA_BIN_VALUE = b'\0'*1000 - SERVER_INITIAL_METADATA_KEY = 'init_me_me_me' - SERVER_INITIAL_METADATA_VALUE = 'whodawha?' - SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought' - SERVER_TRAILING_METADATA_VALUE = 'zomg it is' - SERVER_STATUS_CODE = _types.StatusCode.OK - SERVER_STATUS_DETAILS = 'our work is never over' - REQUEST = 'in death a member of project mayhem has a name' - RESPONSE = 'his name is robert paulson' - METHOD = 'twinkies' - HOST = 'hostess' - server_request_tag = object() - request_call_result = self.server.request_call(self.server_completion_queue, - server_request_tag) - - self.assertEqual(_types.CallError.OK, request_call_result) - - client_call_tag = object() - client_call = self.client_channel.create_call(self.client_completion_queue, - METHOD, HOST, DEADLINE) - client_initial_metadata = [ - (CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE), - (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)] - client_start_batch_result = client_call.start_batch([ - _types.OpArgs.send_initial_metadata(client_initial_metadata), - _types.OpArgs.send_message(REQUEST), - _types.OpArgs.send_close_from_client(), - _types.OpArgs.recv_initial_metadata(), - _types.OpArgs.recv_message(), - _types.OpArgs.recv_status_on_client() - ], client_call_tag) - self.assertEqual(_types.CallError.OK, client_start_batch_result) - - request_event = self.server_completion_queue.next(DEADLINE) - self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type) - self.assertIsInstance(request_event.call, _low.Call) - self.assertIs(server_request_tag, request_event.tag) - self.assertEqual(1, len(request_event.results)) - self.assertEqual(dict(client_initial_metadata), - dict(request_event.results[0].initial_metadata)) - self.assertEqual(METHOD, request_event.call_details.method) - self.assertEqual(HOST, request_event.call_details.host) - self.assertLess(abs(DEADLINE - request_event.call_details.deadline), - DEADLINE_TOLERANCE) - - server_call_tag = object() - server_call = request_event.call - server_initial_metadata = [ - (SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)] - server_trailing_metadata = [ - (SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)] - server_start_batch_result = server_call.start_batch([ - _types.OpArgs.send_initial_metadata(server_initial_metadata), - _types.OpArgs.recv_message(), - _types.OpArgs.send_message(RESPONSE), - _types.OpArgs.recv_close_on_server(), - _types.OpArgs.send_status_from_server( - server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS) - ], server_call_tag) - self.assertEqual(_types.CallError.OK, server_start_batch_result) - - client_event = self.client_completion_queue.next(DEADLINE) - server_event = self.server_completion_queue.next(DEADLINE) - - self.assertEqual(6, len(client_event.results)) - found_client_op_types = set() - for client_result in client_event.results: - # we expect each op type to be unique - self.assertNotIn(client_result.type, found_client_op_types) - found_client_op_types.add(client_result.type) - if client_result.type == _types.OpType.RECV_INITIAL_METADATA: - self.assertEqual(dict(server_initial_metadata), - dict(client_result.initial_metadata)) - elif client_result.type == _types.OpType.RECV_MESSAGE: - self.assertEqual(RESPONSE, client_result.message) - elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT: - self.assertEqual(dict(server_trailing_metadata), - dict(client_result.trailing_metadata)) - self.assertEqual(SERVER_STATUS_DETAILS, client_result.status.details) - self.assertEqual(SERVER_STATUS_CODE, client_result.status.code) - self.assertEqual(set([ - _types.OpType.SEND_INITIAL_METADATA, - _types.OpType.SEND_MESSAGE, - _types.OpType.SEND_CLOSE_FROM_CLIENT, - _types.OpType.RECV_INITIAL_METADATA, - _types.OpType.RECV_MESSAGE, - _types.OpType.RECV_STATUS_ON_CLIENT - ]), found_client_op_types) - - self.assertEqual(5, len(server_event.results)) - found_server_op_types = set() - for server_result in server_event.results: - self.assertNotIn(client_result.type, found_server_op_types) - found_server_op_types.add(server_result.type) - if server_result.type == _types.OpType.RECV_MESSAGE: - self.assertEqual(REQUEST, server_result.message) - elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER: - self.assertFalse(server_result.cancelled) - self.assertEqual(set([ - _types.OpType.SEND_INITIAL_METADATA, - _types.OpType.RECV_MESSAGE, - _types.OpType.SEND_MESSAGE, - _types.OpType.RECV_CLOSE_ON_SERVER, - _types.OpType.SEND_STATUS_FROM_SERVER - ]), found_server_op_types) - - del client_call - del server_call - - -if __name__ == '__main__': - unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/conftest.py b/src/python/grpcio_test/grpc_test/conftest.py deleted file mode 100644 index 357320ec64..0000000000 --- a/src/python/grpcio_test/grpc_test/conftest.py +++ /dev/null @@ -1,60 +0,0 @@ -import types -import unittest - -import pytest - - -class LoadTestsSuiteCollector(pytest.Collector): - - def __init__(self, name, parent, suite): - super(LoadTestsSuiteCollector, self).__init__(name, parent=parent) - self.suite = suite - self.obj = suite - - def collect(self): - collected = [] - for case in self.suite: - if isinstance(case, unittest.TestCase): - collected.append(LoadTestsCase(case.id(), self, case)) - elif isinstance(case, unittest.TestSuite): - collected.append( - LoadTestsSuiteCollector('suite_child_of_mine', self, case)) - return collected - - def reportinfo(self): - return str(self.suite) - - -class LoadTestsCase(pytest.Function): - - def __init__(self, name, parent, item): - super(LoadTestsCase, self).__init__(name, parent, callobj=self._item_run) - self.item = item - - def _item_run(self): - result = unittest.TestResult() - self.item(result) - if result.failures: - test_method, trace = result.failures[0] - pytest.fail(trace, False) - elif result.errors: - test_method, trace = result.errors[0] - pytest.fail(trace, False) - elif result.skipped: - test_method, reason = result.skipped[0] - pytest.skip(reason) - - -def pytest_pycollect_makeitem(collector, name, obj): - if name == 'load_tests' and isinstance(obj, types.FunctionType): - suite = unittest.TestSuite() - loader = unittest.TestLoader() - pattern = '*' - try: - # Check that the 'load_tests' object is actually a callable that actually - # accepts the arguments expected for the load_tests protocol. - suite = obj(loader, suite, pattern) - except Exception as e: - return None - else: - return LoadTestsSuiteCollector(name, collector, suite) diff --git a/src/python/grpcio_test/requirements.txt b/src/python/grpcio_test/requirements.txt deleted file mode 100644 index fea80ca07f..0000000000 --- a/src/python/grpcio_test/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -grpcio>=0.11.0b0 -oauth2client>=1.4.7 -protobuf>=3.0.0a3 -pytest>=2.6 -pytest-cov>=2.0 -pytest-xdist>=1.11 diff --git a/src/python/grpcio_test/setup.cfg b/src/python/grpcio_test/setup.cfg deleted file mode 100644 index 3be93cb918..0000000000 --- a/src/python/grpcio_test/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -python_files = *_test.py |