diff --git a/.travis.yml b/.travis.yml index b6c80629852..d2d1c8ba639 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,42 +1,32 @@ -language: cpp -before_install: - - sudo add-apt-repository ppa:yjwong/gflags -y - - sudo add-apt-repository ppa:h-rayflood/llvm -y - - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF - - echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list - - echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list - - sudo apt-get update -qq - - sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv python-dev python3-dev clang-3.5 - - sudo pip install --upgrade virtualenv - - sudo pip install cpp-coveralls mako simplejson - - sudo apt-get install -qq mono-devel nunit - - wget www.nuget.org/NuGet.exe -O nuget.exe +language: objective-c +osx_image: xcode7.1 env: global: - - RUBY_VERSION=2.1 - - COVERALLS_PARALLEL=true - - CPPFLAGS=-I/tmp/prebuilt/include - - NUGET="mono nuget.exe" - matrix: - - CONFIG=opt TEST=sanity JOBS=1 - - CONFIG=gcov TEST=c JOBS=16 - - CONFIG=gcov TEST=c++ JOBS=16 - - CONFIG=opt TEST=c JOBS=16 - - CONFIG=opt TEST=c++ JOBS=16 - - CONFIG=opt TEST=node JOBS=16 - - CONFIG=opt TEST=ruby JOBS=16 - - CONFIG=opt TEST=python JOBS=1 - - CONFIG=opt TEST=csharp JOBS=16 - - USE_GCC=4.4 CONFIG=opt TEST=build JOBS=16 -script: - - rvm use $RUBY_VERSION - - gem install bundler - - ./tools/run_tests/prepare_travis.sh - - if [ ! -z "$USE_GCC" ] ; then export CC=gcc-$USE_GCC ; export CXX=g++-$USE_GCC ; fi - - ./tools/run_tests/run_tests.py -l $TEST -t -j $JOBS -c $CONFIG -s 4.0 -after_success: - - if [ "$CONFIG" = "gcov" ] ; then coveralls --exclude third_party --exclude gens --exclude test --exclude tools --exclude src/compiler -b. --gcov-options '\-p' ; fi + - CONFIG=opt + - TEST=objc + - JOBS=1 +before_install: + - brew install gflags + # Pod install does this too, but we don't want the output. + - pod repo update --silent +install: + - make grpc_objective_c_plugin + - pushd src/objective-c/tests + # Needs to be verbose, or otherwise OpenSSL's prepare_command makes Travis + # time out: + - pod install --verbose + - popd +before_script: + - make interop_server + - bins/$CONFIG/interop_server --port=5050 & + - bins/$CONFIG/interop_server --port=5051 --use_tls & +xcode_workspace: src/objective-c/tests/Tests.xcworkspace +xcode_scheme: + - RxLibraryUnitTests + - InteropTestsLocalSSL + - InteropTestsLocalCleartext + # TODO(jcanizales): Investigate why they time out: + # - InteropTestsRemote +xcode_sdk: iphonesimulator9.1 notifications: email: false - webhooks: - - https://coveralls.io/webhook?repo_token=54IxAHPjJNdQJzJAhPU0MFpCtg7KvcydQ diff --git a/Makefile b/Makefile index c4183914e63..9d94ee85992 100644 --- a/Makefile +++ b/Makefile @@ -889,6 +889,7 @@ qps_worker: $(BINDIR)/$(CONFIG)/qps_worker reconnect_interop_client: $(BINDIR)/$(CONFIG)/reconnect_interop_client reconnect_interop_server: $(BINDIR)/$(CONFIG)/reconnect_interop_server secure_auth_context_test: $(BINDIR)/$(CONFIG)/secure_auth_context_test +secure_sync_unary_ping_pong_test: $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test server_crash_test: $(BINDIR)/$(CONFIG)/server_crash_test server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test @@ -1802,7 +1803,7 @@ buildtests: buildtests_c buildtests_cxx buildtests_zookeeper buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/compression_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/endpoint_pair_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_cpu_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_args_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/lb_policies_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timer_heap_test $(BINDIR)/$(CONFIG)/timer_list_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/udp_server_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/workqueue_test $(BINDIR)/$(CONFIG)/h2_compress_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_compress_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_compress_call_creds_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_compress_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_compress_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_compress_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_compress_default_host_test $(BINDIR)/$(CONFIG)/h2_compress_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_compress_empty_batch_test $(BINDIR)/$(CONFIG)/h2_compress_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_compress_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_compress_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_compress_large_metadata_test $(BINDIR)/$(CONFIG)/h2_compress_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_compress_max_message_length_test $(BINDIR)/$(CONFIG)/h2_compress_metadata_test $(BINDIR)/$(CONFIG)/h2_compress_no_op_test $(BINDIR)/$(CONFIG)/h2_compress_payload_test $(BINDIR)/$(CONFIG)/h2_compress_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_compress_registered_call_test $(BINDIR)/$(CONFIG)/h2_compress_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_compress_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_compress_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_compress_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_compress_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_compress_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_compress_simple_request_test $(BINDIR)/$(CONFIG)/h2_compress_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_fakesec_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_fakesec_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_fakesec_call_creds_test $(BINDIR)/$(CONFIG)/h2_fakesec_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_fakesec_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_fakesec_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_fakesec_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_fakesec_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_fakesec_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_fakesec_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_fakesec_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_fakesec_default_host_test $(BINDIR)/$(CONFIG)/h2_fakesec_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_fakesec_empty_batch_test $(BINDIR)/$(CONFIG)/h2_fakesec_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_fakesec_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_fakesec_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_fakesec_large_metadata_test $(BINDIR)/$(CONFIG)/h2_fakesec_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_fakesec_max_message_length_test $(BINDIR)/$(CONFIG)/h2_fakesec_metadata_test $(BINDIR)/$(CONFIG)/h2_fakesec_no_op_test $(BINDIR)/$(CONFIG)/h2_fakesec_payload_test $(BINDIR)/$(CONFIG)/h2_fakesec_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_fakesec_registered_call_test $(BINDIR)/$(CONFIG)/h2_fakesec_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_fakesec_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_fakesec_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_fakesec_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_fakesec_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_fakesec_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_fakesec_simple_request_test $(BINDIR)/$(CONFIG)/h2_fakesec_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_full_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_full_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_full_call_creds_test $(BINDIR)/$(CONFIG)/h2_full_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_full_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_full_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_full_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_full_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_full_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_full_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_full_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_full_default_host_test $(BINDIR)/$(CONFIG)/h2_full_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_full_empty_batch_test $(BINDIR)/$(CONFIG)/h2_full_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_full_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_full_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_full_large_metadata_test $(BINDIR)/$(CONFIG)/h2_full_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_full_max_message_length_test $(BINDIR)/$(CONFIG)/h2_full_metadata_test $(BINDIR)/$(CONFIG)/h2_full_no_op_test $(BINDIR)/$(CONFIG)/h2_full_payload_test $(BINDIR)/$(CONFIG)/h2_full_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_full_registered_call_test $(BINDIR)/$(CONFIG)/h2_full_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_full_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_full_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_full_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_full_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_full_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_full_simple_request_test $(BINDIR)/$(CONFIG)/h2_full_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_full+poll_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_full+poll_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_full+poll_call_creds_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_full+poll_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_full+poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_full+poll_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_full+poll_default_host_test $(BINDIR)/$(CONFIG)/h2_full+poll_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_full+poll_empty_batch_test $(BINDIR)/$(CONFIG)/h2_full+poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_full+poll_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_full+poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_full+poll_large_metadata_test $(BINDIR)/$(CONFIG)/h2_full+poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_full+poll_max_message_length_test $(BINDIR)/$(CONFIG)/h2_full+poll_metadata_test $(BINDIR)/$(CONFIG)/h2_full+poll_no_op_test $(BINDIR)/$(CONFIG)/h2_full+poll_payload_test $(BINDIR)/$(CONFIG)/h2_full+poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_full+poll_registered_call_test $(BINDIR)/$(CONFIG)/h2_full+poll_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_full+poll_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_full+poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_full+poll_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_full+poll_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_full+poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_full+poll_simple_request_test $(BINDIR)/$(CONFIG)/h2_full+poll_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_oauth2_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_oauth2_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_oauth2_call_creds_test $(BINDIR)/$(CONFIG)/h2_oauth2_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_oauth2_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_oauth2_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_oauth2_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_oauth2_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_oauth2_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_oauth2_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_oauth2_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_oauth2_default_host_test $(BINDIR)/$(CONFIG)/h2_oauth2_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_oauth2_empty_batch_test $(BINDIR)/$(CONFIG)/h2_oauth2_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_oauth2_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_oauth2_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_oauth2_large_metadata_test $(BINDIR)/$(CONFIG)/h2_oauth2_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_oauth2_max_message_length_test $(BINDIR)/$(CONFIG)/h2_oauth2_metadata_test $(BINDIR)/$(CONFIG)/h2_oauth2_no_op_test $(BINDIR)/$(CONFIG)/h2_oauth2_payload_test $(BINDIR)/$(CONFIG)/h2_oauth2_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_oauth2_registered_call_test $(BINDIR)/$(CONFIG)/h2_oauth2_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_oauth2_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_oauth2_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_oauth2_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_oauth2_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_oauth2_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_oauth2_simple_request_test $(BINDIR)/$(CONFIG)/h2_oauth2_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_proxy_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_proxy_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_proxy_call_creds_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_proxy_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_proxy_default_host_test $(BINDIR)/$(CONFIG)/h2_proxy_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_proxy_empty_batch_test $(BINDIR)/$(CONFIG)/h2_proxy_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_proxy_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_proxy_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_proxy_large_metadata_test $(BINDIR)/$(CONFIG)/h2_proxy_max_message_length_test $(BINDIR)/$(CONFIG)/h2_proxy_metadata_test $(BINDIR)/$(CONFIG)/h2_proxy_no_op_test $(BINDIR)/$(CONFIG)/h2_proxy_payload_test $(BINDIR)/$(CONFIG)/h2_proxy_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_proxy_registered_call_test $(BINDIR)/$(CONFIG)/h2_proxy_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_proxy_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_proxy_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_proxy_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_proxy_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_proxy_simple_request_test $(BINDIR)/$(CONFIG)/h2_proxy_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_sockpair_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_call_creds_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_sockpair_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair_empty_batch_test $(BINDIR)/$(CONFIG)/h2_sockpair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_sockpair_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_sockpair_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_large_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_sockpair_max_message_length_test $(BINDIR)/$(CONFIG)/h2_sockpair_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_no_op_test $(BINDIR)/$(CONFIG)/h2_sockpair_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_sockpair_registered_call_test $(BINDIR)/$(CONFIG)/h2_sockpair_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_sockpair_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_sockpair_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_sockpair_simple_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_call_creds_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_empty_batch_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_large_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_max_message_length_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_no_op_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_registered_call_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_simple_request_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_call_creds_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_empty_batch_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_large_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_max_message_length_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_metadata_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_no_op_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_registered_call_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_simple_request_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_ssl_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_call_creds_test $(BINDIR)/$(CONFIG)/h2_ssl_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_ssl_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_ssl_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_ssl_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_ssl_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_ssl_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_ssl_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_ssl_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_ssl_default_host_test $(BINDIR)/$(CONFIG)/h2_ssl_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_ssl_empty_batch_test $(BINDIR)/$(CONFIG)/h2_ssl_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_ssl_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_ssl_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_ssl_large_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_ssl_max_message_length_test $(BINDIR)/$(CONFIG)/h2_ssl_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_no_op_test $(BINDIR)/$(CONFIG)/h2_ssl_payload_test $(BINDIR)/$(CONFIG)/h2_ssl_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_ssl_registered_call_test $(BINDIR)/$(CONFIG)/h2_ssl_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_ssl_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_ssl_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_ssl_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_ssl_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_ssl_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_ssl_simple_request_test $(BINDIR)/$(CONFIG)/h2_ssl_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_call_creds_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_default_host_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_empty_batch_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_large_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_max_message_length_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_no_op_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_payload_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_registered_call_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_simple_request_test $(BINDIR)/$(CONFIG)/h2_ssl+poll_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_call_creds_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_default_host_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_empty_batch_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_large_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_max_message_length_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_metadata_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_no_op_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_payload_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_registered_call_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_simple_request_test $(BINDIR)/$(CONFIG)/h2_ssl_proxy_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_uchannel_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_uchannel_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_uchannel_call_creds_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_uchannel_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_uchannel_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_uchannel_large_metadata_test $(BINDIR)/$(CONFIG)/h2_uchannel_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_uchannel_max_message_length_test $(BINDIR)/$(CONFIG)/h2_uchannel_metadata_test $(BINDIR)/$(CONFIG)/h2_uchannel_no_op_test $(BINDIR)/$(CONFIG)/h2_uchannel_payload_test $(BINDIR)/$(CONFIG)/h2_uchannel_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_uchannel_registered_call_test $(BINDIR)/$(CONFIG)/h2_uchannel_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_uchannel_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_uds_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_uds_call_creds_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_uds_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_uds_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_uds_empty_batch_test $(BINDIR)/$(CONFIG)/h2_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_uds_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_uds_large_metadata_test $(BINDIR)/$(CONFIG)/h2_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_uds_max_message_length_test $(BINDIR)/$(CONFIG)/h2_uds_metadata_test $(BINDIR)/$(CONFIG)/h2_uds_no_op_test $(BINDIR)/$(CONFIG)/h2_uds_payload_test $(BINDIR)/$(CONFIG)/h2_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_uds_registered_call_test $(BINDIR)/$(CONFIG)/h2_uds_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_uds_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_uds_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_uds_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_uds_simple_request_test $(BINDIR)/$(CONFIG)/h2_uds_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_uds+poll_bad_hostname_test $(BINDIR)/$(CONFIG)/h2_uds+poll_binary_metadata_test $(BINDIR)/$(CONFIG)/h2_uds+poll_call_creds_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_after_client_done_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/h2_uds+poll_census_simple_request_test $(BINDIR)/$(CONFIG)/h2_uds+poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/h2_uds+poll_compressed_payload_test $(BINDIR)/$(CONFIG)/h2_uds+poll_disappearing_server_test $(BINDIR)/$(CONFIG)/h2_uds+poll_empty_batch_test $(BINDIR)/$(CONFIG)/h2_uds+poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/h2_uds+poll_high_initial_seqno_test $(BINDIR)/$(CONFIG)/h2_uds+poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/h2_uds+poll_large_metadata_test $(BINDIR)/$(CONFIG)/h2_uds+poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/h2_uds+poll_max_message_length_test $(BINDIR)/$(CONFIG)/h2_uds+poll_metadata_test $(BINDIR)/$(CONFIG)/h2_uds+poll_no_op_test $(BINDIR)/$(CONFIG)/h2_uds+poll_payload_test $(BINDIR)/$(CONFIG)/h2_uds+poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/h2_uds+poll_registered_call_test $(BINDIR)/$(CONFIG)/h2_uds+poll_request_with_flags_test $(BINDIR)/$(CONFIG)/h2_uds+poll_request_with_payload_test $(BINDIR)/$(CONFIG)/h2_uds+poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/h2_uds+poll_shutdown_finishes_calls_test $(BINDIR)/$(CONFIG)/h2_uds+poll_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/h2_uds+poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/h2_uds+poll_simple_request_test $(BINDIR)/$(CONFIG)/h2_uds+poll_trailing_metadata_test $(BINDIR)/$(CONFIG)/h2_compress_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_channel_connectivity_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_default_host_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_compress_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_full_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_full_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_full_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_full_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_full_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_full_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full_channel_connectivity_nosec_test $(BINDIR)/$(CONFIG)/h2_full_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_full_default_host_nosec_test $(BINDIR)/$(CONFIG)/h2_full_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_full_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_full_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_full_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_full_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_full_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_full_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_full_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_full_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_full_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_full_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_full_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_full_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_full_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_full_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_channel_connectivity_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_default_host_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_full+poll_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_default_host_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_proxy_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair+trace_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_channel_connectivity_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_bad_hostname_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_binary_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_after_accept_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_after_client_done_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_after_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_before_invoke_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_cancel_in_a_vacuum_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_census_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_channel_connectivity_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_compressed_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_disappearing_server_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_empty_batch_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_graceful_server_shutdown_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_high_initial_seqno_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_invoke_large_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_large_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_max_concurrent_streams_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_max_message_length_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_metadata_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_no_op_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_ping_pong_streaming_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_registered_call_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_request_with_flags_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_request_with_payload_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_server_finishes_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_shutdown_finishes_calls_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_shutdown_finishes_tags_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_simple_delayed_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_simple_request_nosec_test $(BINDIR)/$(CONFIG)/h2_uds+poll_trailing_metadata_nosec_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test -buildtests_cxx: buildtests_zookeeper privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_string_ref_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/reconnect_interop_client $(BINDIR)/$(CONFIG)/reconnect_interop_server $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/shutdown_test $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/streaming_throughput_test $(BINDIR)/$(CONFIG)/stress_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test +buildtests_cxx: buildtests_zookeeper privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_string_ref_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/reconnect_interop_client $(BINDIR)/$(CONFIG)/reconnect_interop_server $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/shutdown_test $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/streaming_throughput_test $(BINDIR)/$(CONFIG)/stress_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test ifeq ($(HAS_ZOOKEEPER),true) buildtests_zookeeper: privatelibs_zookeeper $(BINDIR)/$(CONFIG)/zookeeper_test @@ -3546,12 +3547,12 @@ test_cxx: test_zookeeper buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 ) $(E) "[RUN] Testing mock_test" $(Q) $(BINDIR)/$(CONFIG)/mock_test || ( echo test mock_test failed ; exit 1 ) - $(E) "[RUN] Testing qps_openloop_test" - $(Q) $(BINDIR)/$(CONFIG)/qps_openloop_test || ( echo test qps_openloop_test failed ; exit 1 ) $(E) "[RUN] Testing qps_test" $(Q) $(BINDIR)/$(CONFIG)/qps_test || ( echo test qps_test failed ; exit 1 ) $(E) "[RUN] Testing secure_auth_context_test" $(Q) $(BINDIR)/$(CONFIG)/secure_auth_context_test || ( echo test secure_auth_context_test failed ; exit 1 ) + $(E) "[RUN] Testing secure_sync_unary_ping_pong_test" + $(Q) $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test || ( echo test secure_sync_unary_ping_pong_test failed ; exit 1 ) $(E) "[RUN] Testing server_crash_test" $(Q) $(BINDIR)/$(CONFIG)/server_crash_test || ( echo test server_crash_test failed ; exit 1 ) $(E) "[RUN] Testing shutdown_test" @@ -3560,8 +3561,6 @@ test_cxx: test_zookeeper buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/status_test || ( echo test status_test failed ; exit 1 ) $(E) "[RUN] Testing streaming_throughput_test" $(Q) $(BINDIR)/$(CONFIG)/streaming_throughput_test || ( echo test streaming_throughput_test failed ; exit 1 ) - $(E) "[RUN] Testing stress_test" - $(Q) $(BINDIR)/$(CONFIG)/stress_test || ( echo test stress_test failed ; exit 1 ) $(E) "[RUN] Testing sync_streaming_ping_pong_test" $(Q) $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test || ( echo test sync_streaming_ping_pong_test failed ; exit 1 ) $(E) "[RUN] Testing sync_unary_ping_pong_test" @@ -3757,45 +3756,90 @@ $(GENDIR)/test/cpp/util/messages.grpc.pb.cc: test/cpp/util/messages.proto $(PROT endif ifeq ($(NO_PROTOC),true) -$(GENDIR)/test/proto/empty.pb.cc: protoc_dep_error -$(GENDIR)/test/proto/empty.grpc.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/control.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc: protoc_dep_error else -$(GENDIR)/test/proto/empty.pb.cc: test/proto/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/test/proto/benchmarks/control.pb.cc: test/proto/benchmarks/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< -$(GENDIR)/test/proto/empty.grpc.pb.cc: test/proto/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc: test/proto/benchmarks/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) -$(GENDIR)/test/proto/messages.pb.cc: protoc_dep_error -$(GENDIR)/test/proto/messages.grpc.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/payloads.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc: protoc_dep_error else -$(GENDIR)/test/proto/messages.pb.cc: test/proto/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/test/proto/benchmarks/payloads.pb.cc: test/proto/benchmarks/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< -$(GENDIR)/test/proto/messages.grpc.pb.cc: test/proto/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc: test/proto/benchmarks/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) -$(GENDIR)/test/proto/qpstest.pb.cc: protoc_dep_error -$(GENDIR)/test/proto/qpstest.grpc.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/services.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc: protoc_dep_error else -$(GENDIR)/test/proto/qpstest.pb.cc: test/proto/qpstest.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/test/proto/benchmarks/services.pb.cc: test/proto/benchmarks/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< -$(GENDIR)/test/proto/qpstest.grpc.pb.cc: test/proto/qpstest.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc: test/proto/benchmarks/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< +endif + +ifeq ($(NO_PROTOC),true) +$(GENDIR)/test/proto/benchmarks/stats.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc: protoc_dep_error +else +$(GENDIR)/test/proto/benchmarks/stats.pb.cc: test/proto/benchmarks/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[PROTOC] Generating protobuf CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc: test/proto/benchmarks/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< +endif + +ifeq ($(NO_PROTOC),true) +$(GENDIR)/test/proto/empty.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/empty.grpc.pb.cc: protoc_dep_error +else +$(GENDIR)/test/proto/empty.pb.cc: test/proto/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[PROTOC] Generating protobuf CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/proto/empty.grpc.pb.cc: test/proto/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< +endif + +ifeq ($(NO_PROTOC),true) +$(GENDIR)/test/proto/messages.pb.cc: protoc_dep_error +$(GENDIR)/test/proto/messages.grpc.pb.cc: protoc_dep_error +else +$(GENDIR)/test/proto/messages.pb.cc: test/proto/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[PROTOC] Generating protobuf CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/proto/messages.grpc.pb.cc: test/proto/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< @@ -5392,7 +5436,11 @@ $(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o: $(GENDIR)/test/proto/empty.pb.cc LIBQPS_SRC = \ - $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc \ + $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc \ + $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc \ + $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc \ + $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc \ + $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc \ $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc \ test/cpp/qps/client_async.cc \ test/cpp/qps/client_sync.cc \ @@ -5447,16 +5495,16 @@ ifneq ($(NO_DEPS),true) -include $(LIBQPS_OBJS:.o=.dep) endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/proto/qpstest.pb.cc $(GENDIR)/test/proto/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/control.pb.cc $(GENDIR)/test/proto/benchmarks/control.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.pb.cc $(GENDIR)/test/proto/benchmarks/payloads.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/services.pb.cc $(GENDIR)/test/proto/benchmarks/services.grpc.pb.cc $(GENDIR)/test/proto/benchmarks/stats.pb.cc $(GENDIR)/test/proto/benchmarks/stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc LIBGRPC_CSHARP_EXT_SRC = \ @@ -10239,6 +10287,7 @@ ifneq ($(NO_DEPS),true) -include $(RECONNECT_INTEROP_CLIENT_OBJS:.o=.dep) endif endif +$(OBJDIR)/$(CONFIG)/test/cpp/interop/reconnect_interop_client.o: $(GENDIR)/test/proto/empty.pb.cc $(GENDIR)/test/proto/empty.grpc.pb.cc $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/test.pb.cc $(GENDIR)/test/proto/test.grpc.pb.cc RECONNECT_INTEROP_SERVER_SRC = \ @@ -10285,6 +10334,7 @@ ifneq ($(NO_DEPS),true) -include $(RECONNECT_INTEROP_SERVER_OBJS:.o=.dep) endif endif +$(OBJDIR)/$(CONFIG)/test/cpp/interop/reconnect_interop_server.o: $(GENDIR)/test/proto/empty.pb.cc $(GENDIR)/test/proto/empty.grpc.pb.cc $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/test.pb.cc $(GENDIR)/test/proto/test.grpc.pb.cc SECURE_AUTH_CONTEXT_TEST_SRC = \ @@ -10327,6 +10377,46 @@ endif endif +SECURE_SYNC_UNARY_PING_PONG_TEST_SRC = \ + test/cpp/qps/secure_sync_unary_ping_pong_test.cc \ + +SECURE_SYNC_UNARY_PING_PONG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SECURE_SYNC_UNARY_PING_PONG_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test: openssl_dep_error + +else + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test: $(PROTOBUF_DEP) $(SECURE_SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(SECURE_SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/qps/secure_sync_unary_ping_pong_test.o: $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +deps_secure_sync_unary_ping_pong_test: $(SECURE_SYNC_UNARY_PING_PONG_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(SECURE_SYNC_UNARY_PING_PONG_TEST_OBJS:.o=.dep) +endif +endif + + SERVER_CRASH_TEST_SRC = \ test/cpp/end2end/server_crash_test.cc \ @@ -10575,6 +10665,9 @@ ifneq ($(NO_DEPS),true) -include $(STRESS_TEST_OBJS:.o=.dep) endif endif +$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_client.o: $(GENDIR)/test/proto/empty.pb.cc $(GENDIR)/test/proto/empty.grpc.pb.cc $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/test.pb.cc $(GENDIR)/test/proto/test.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/interop/stress_interop_client.o: $(GENDIR)/test/proto/empty.pb.cc $(GENDIR)/test/proto/empty.grpc.pb.cc $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/test.pb.cc $(GENDIR)/test/proto/test.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/interop/stress_test.o: $(GENDIR)/test/proto/empty.pb.cc $(GENDIR)/test/proto/empty.grpc.pb.cc $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/test.pb.cc $(GENDIR)/test/proto/test.grpc.pb.cc SYNC_STREAMING_PING_PONG_TEST_SRC = \ diff --git a/build.yaml b/build.yaml index 4f6e35b0de1..873606f9806 100644 --- a/build.yaml +++ b/build.yaml @@ -751,7 +751,11 @@ libs: - test/cpp/qps/timer.h - test/cpp/util/benchmark_config.h src: - - test/proto/qpstest.proto + - test/proto/messages.proto + - test/proto/benchmarks/control.proto + - test/proto/benchmarks/payloads.proto + - test/proto/benchmarks/services.proto + - test/proto/benchmarks/stats.proto - test/cpp/qps/perf_db.proto - test/cpp/qps/client_async.cc - test/cpp/qps/client_sync.cc @@ -1937,6 +1941,7 @@ targets: - posix - name: qps_openloop_test build: test + run: false language: c++ src: - test/cpp/qps/qps_openloop_test.cc @@ -2037,6 +2042,23 @@ targets: - grpc - gpr_test_util - gpr +- name: secure_sync_unary_ping_pong_test + build: test + language: c++ + src: + - test/cpp/qps/secure_sync_unary_ping_pong_test.cc + deps: + - qps + - grpc++_test_util + - grpc_test_util + - grpc++ + - grpc + - gpr_test_util + - gpr + platforms: + - mac + - linux + - posix - name: server_crash_test build: test language: c++ @@ -2107,6 +2129,7 @@ targets: - posix - name: stress_test build: test + run: false language: c++ headers: - test/cpp/interop/client_helper.h diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md index 02d4f28102b..7f7055bb4df 100644 --- a/doc/PROTOCOL-HTTP2.md +++ b/doc/PROTOCOL-HTTP2.md @@ -10,58 +10,64 @@ Production rules are using ABNF syn The following is the general sequence of message atoms in a GRPC request & response message stream -* Request → Request-Headers *Delimited-Message EOS -* Response → (Response-Headers *Delimited-Message Trailers) / Trailers-Only +* Request → Request-Headers \*Length-Prefixed-Message EOS +* Response → (Response-Headers \*Length-Prefixed-Message Trailers) / Trailers-Only ### Requests -* Request → Request-Headers *Delimited-Message EOS +* Request → Request-Headers \*Length-Prefixed-Message EOS Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames. -* **Request-Headers** → Call-Definition *Custom-Metadata -* **Call-Definition** → Method Scheme Path TE [Authority] [Timeout] [Content-Type] [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent] -* **Method** → “:method POST” -* **Scheme** → “:scheme ” (“http” / “https”) -* **Path** → “:path” {_path identifying method within exposed API_} -* **Authority** → “:authority” {_virtual host name of authority_} -* **TE** → “te” “trailers” # Used to detect incompatible proxies -* **Timeout** → “grpc-timeout” TimeoutValue TimeoutUnit +* **Request-Headers** → Call-Definition \*Custom-Metadata +* **Call-Definition** → Method Scheme Path TE [Authority] [Timeout] Content-Type [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent] +* **Method** → ":method POST" +* **Scheme** → ":scheme " ("http" / "https") +* **Path** → ":path" {_path identifying method within exposed API_} +* **Authority** → ":authority" {_virtual host name of authority_} +* **TE** → "te" "trailers" # Used to detect incompatible proxies +* **Timeout** → "grpc-timeout" TimeoutValue TimeoutUnit * **TimeoutValue** → {_positive integer as ASCII string of at most 8 digits_} * **TimeoutUnit** → Hour / Minute / Second / Millisecond / Microsecond / Nanosecond -* **Hour** → “H” -* **Minute** → “M” -* **Second** → “S” -* **Millisecond** → “m” -* **Microsecond** → “u” -* **Nanosecond** → “n” -* **Content-Type** → “content-type” “application/grpc” [(“+proto” / “+json” / {_custom_})] -* **Content-Coding** → “gzip” / “deflate” / “snappy” / {_custom_} -* **Message-Encoding** → “grpc-encoding” Content-Coding -* **Message-Accept-Encoding** → “grpc-accept-encoding” Content-Coding *("," Content-Coding) -* **User-Agent** → “user-agent” {_structured user-agent string_} -* **Message-Type** → “grpc-message-type” {_type name for message schema_} +* **Hour** → "H" +* **Minute** → "M" +* **Second** → "S" +* **Millisecond** → "m" +* **Microsecond** → "u" +* **Nanosecond** → "n" +* **Content-Type** → "content-type" "application/grpc" [("+proto" / "+json" / {_custom_})] +* **Content-Coding** → "identity" / "gzip" / "deflate" / "snappy" / {_custom_} +* **Message-Encoding** → "grpc-encoding" Content-Coding +* **Message-Accept-Encoding** → "grpc-accept-encoding" Content-Coding \*("," Content-Coding) +* **User-Agent** → "user-agent" {_structured user-agent string_} +* **Message-Type** → "grpc-message-type" {_type name for message schema_} * **Custom-Metadata** → Binary-Header / ASCII-Header -* **Binary-Header** → {Header-Name “-bin” } {_base64 encoded value_} +* **Binary-Header** → {Header-Name "-bin" } {_base64 encoded value_} * **ASCII-Header** → Header-Name {_value_} -* **Header-Name** → 1*( %x30-39 / %x61-7A / “_” / “-”) ; 0-9 a-z +* **Header-Name** → 1\*( %x30-39 / %x61-7A / "\_" / "-") ; 0-9 a-z \_ - -HTTP2 requires that reserved headers, ones starting with “:” appear before all other headers. Additionally implementations should send **Timeout** immediately after the reserved headers and they should send the **Call-Definition** headers before sending **Custom-Metadata**. +HTTP2 requires that reserved headers, ones starting with ":" appear before all other headers. Additionally implementations should send **Timeout** immediately after the reserved headers and they should send the **Call-Definition** headers before sending **Custom-Metadata**. If **Timeout** is omitted a server should assume an infinite timeout. Client implementations are free to send a default minimum timeout based on their deployment requirements. -**Custom-Metadata** is an arbitrary set of key-value pairs defined by the application layer. Aside from transport limits on the total length of HTTP2 HEADERS the only other constraint is that header names starting with “grpc-” are reserved for future use. +**Custom-Metadata** is an arbitrary set of key-value pairs defined by the application layer. Header names starting with "grpc-" but not listed here are reserved for future GRPC use and should not be used by applications as **Custom-Metadata**. -Note that HTTP2 does not allow arbitrary octet sequences for header values so binary header values must be encoded using Base64 as per https://tools.ietf.org/html/rfc4648#section-4. Implementations MUST accept padded and un-padded values and should emit un-padded values. Applications define binary headers by having their names end with “-bin”. Runtime libraries use this suffix to detect binary headers and properly apply base64 encoding & decoding as headers are sent and received. +Note that HTTP2 does not allow arbitrary octet sequences for header values so binary header values must be encoded using Base64 as per https://tools.ietf.org/html/rfc4648#section-4. Implementations MUST accept padded and un-padded values and should emit un-padded values. Applications define binary headers by having their names end with "-bin". Runtime libraries use this suffix to detect binary headers and properly apply base64 encoding & decoding as headers are sent and received. -The repeated sequence of **Delimited-Message** items is delivered in DATA frames +Servers may limit the size of **Request-Headers**, with a default of 8 KiB +suggested. Implementations are encouraged to compute total header size like +HTTP/2's `SETTINGS_MAX_HEADER_LIST_SIZE`: the sum of all header fields, for each +field the sum of the uncompressed field name and value lengths plus 32, with +binary values' lengths being post-Base64. -* **Delimited-Message** → Compressed-Flag Message-Length Message +The repeated sequence of **Length-Prefixed-Message** items is delivered in DATA frames + +* **Length-Prefixed-Message** → Compressed-Flag Message-Length Message * **Compressed-Flag** → 0 / 1 # encoded as 1 byte unsigned integer * **Message-Length** → {_length of Message_} # encoded as 4 byte unsigned integer -* **Message** → *{binary octet} +* **Message** → \*{binary octet} A **Compressed-Flag** value of 1 indicates that the binary octet sequence of **Message** is compressed using the mechanism declared by the **Message-Encoding** header. A value of 0 indicates that no encoding of **Message** bytes has occurred. Compression contexts are NOT maintained over message boundaries, implementations must create a new context for each message in the stream. If the **Message-Encoding** header is omitted then the **Compressed-Flag** must be 0. @@ -69,13 +75,13 @@ For requests, **EOS** (end-of-stream) is indicated by the presence of the END_ST ###Responses -* **Response** → (Response-Headers *Delimited-Message Trailers) / Trailers-Only -* **Response-Headers** → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type *Custom-Metadata +* **Response** → (Response-Headers \*Length-Prefixed-Message Trailers) / Trailers-Only +* **Response-Headers** → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type \*Custom-Metadata * **Trailers-Only** → HTTP-Status Content-Type Trailers -* **Trailers** → Status [Status-Message] *Custom-Metadata -* **HTTP-Status** → “:status 200” -* **Status** → “grpc-status” -* **Status-Message** → “grpc-message” +* **Trailers** → Status [Status-Message] \*Custom-Metadata +* **HTTP-Status** → ":status 200" +* **Status** → "grpc-status" +* **Status-Message** → "grpc-message" **Response-Headers** & **Trailers-Only** are each delivered in a single HTTP2 HEADERS frame block. Most responses are expected to have both headers and trailers but **Trailers-Only** is permitted for calls that produce an immediate error. Status must be sent in **Trailers** even if the status code is OK. @@ -83,6 +89,9 @@ For responses end-of-stream is indicated by the presence of the END_STREAM flag Implementations should expect broken deployments to send non-200 HTTP status codes in responses as well as a variety of non-GRPC content-types and to omit **Status** & **Status-Message**. Implementations must synthesize a **Status** & **Status-Message** to propagate to the application layer when this occurs. +Clients may limit the size of **Response-Headers**, **Trailers**, and +**Trailers-Only**, with a default of 8 KiB each suggested. + ####Example Sample unary-call showing HTTP2 framing sequence @@ -101,7 +110,7 @@ grpc-encoding = gzip authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v DATA (flags = END_STREAM) - + ``` **Response** ``` @@ -110,7 +119,7 @@ HEADERS (flags = END_HEADERS) grpc-encoding = gzip DATA - + HEADERS (flags = END_STREAM, END_HEADERS) grpc-status = 0 # OK @@ -120,7 +129,7 @@ trace-proto-bin = jher831yy13JHy3hc While the protocol does not require a user-agent to function it is recommended that clients provide a structured user-agent string that provides a basic description of the calling library, version & platform to facilitate issue diagnosis in heterogeneous environments. The following structure is recommended to library developers ``` -User-Agent → “grpc-” Language ?(“-” Variant) “/” Version ?( “ (“ *(AdditionalProperty “;”) “)” ) +User-Agent → "grpc-" Language ?("-" Variant) "/" Version ?( " (" *(AdditionalProperty ";") ")" ) ``` E.g. @@ -136,7 +145,7 @@ grpc-java-android/0.9.1 (gingerbread/1.2.4; nexus5; tmobile) All GRPC calls need to specify an internal ID. We will use HTTP2 stream-ids as call identifiers in this scheme. NOTE: These id’s are contextual to an open HTTP2 session and will not be unique within a given process that is handling more than one HTTP2 session nor can they be used as GUIDs. #####Data Frames -DATA frame boundaries have no relation to **Delimited-Message** boundaries and implementations should make no assumptions about their alignment. +DATA frame boundaries have no relation to **Length-Prefixed-Message** boundaries and implementations should make no assumptions about their alignment. #####Errors diff --git a/examples/README.md b/examples/README.md index cc4b239f8e2..84ec80057e1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -18,7 +18,7 @@ You can find quick start guides for each language, including installation instru * [Android Java](https://github.com/grpc/grpc-java/tree/master/examples/android) * [Python](python/helloworld) * [C#](csharp) -* [Objective-C](objective-c/route_guide) +* [Objective-C](objective-c/helloworld) * [PHP](php) ## What's in this repository? diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective-c/auth_sample/AuthTestService.podspec index 9f2a2cc361b..9521d4971a8 100644 --- a/examples/objective-c/auth_sample/AuthTestService.podspec +++ b/examples/objective-c/auth_sample/AuthTestService.podspec @@ -3,13 +3,13 @@ Pod::Spec.new do |s| s.version = "0.0.1" s.license = "New BSD" - s.ios.deployment_target = "6.0" - s.osx.deployment_target = "10.8" + s.ios.deployment_target = "7.1" + s.osx.deployment_target = "10.9" # Base directory where the .proto files are. src = "../../protos" - # Directory where the generated files will be place. + # Directory where the generated files will be placed. dir = "Pods/" + s.name # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. @@ -22,14 +22,14 @@ Pod::Spec.new do |s| ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" ms.header_mappings_dir = dir ms.requires_arc = false - ms.dependency "Protobuf", "~> 3.0.0-alpha-3" + ms.dependency "Protobuf", "~> 3.0.0-alpha-4" end s.subspec "Services" do |ss| ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" ss.header_mappings_dir = dir ss.requires_arc = true - ss.dependency "gRPC", "~> 0.6" + ss.dependency "gRPC", "~> 0.11" ss.dependency "#{s.name}/Messages" end end diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.m b/examples/objective-c/auth_sample/MakeRPCViewController.m index 366bc9deea9..4fd23dc1448 100644 --- a/examples/objective-c/auth_sample/MakeRPCViewController.m +++ b/examples/objective-c/auth_sample/MakeRPCViewController.m @@ -35,7 +35,6 @@ #import #import -#include #import NSString * const kTestScope = @"https://www.googleapis.com/auth/xapi.zoo"; @@ -49,10 +48,10 @@ static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com"; @implementation NSError (AuthSample) - (NSString *)UIDescription { - if (self.code == GRPC_STATUS_UNAUTHENTICATED) { + if (self.code == GRPCErrorCodeUnauthenticated) { // Authentication error. OAuth2 specifies we'll receive a challenge header. - // |userInfo[kGRPCStatusMetadataKey]| is the dictionary of response metadata. - NSString *challengeHeader = self.userInfo[kGRPCStatusMetadataKey][@"www-authenticate"] ?: @""; + // |userInfo[kGRPCHeadersKey]| is the dictionary of response headers. + NSString *challengeHeader = self.userInfo[kGRPCHeadersKey][@"www-authenticate"] ?: @""; return [@"Invalid credentials. Server challenge:\n" stringByAppendingString:challengeHeader]; } else { // Any other error. @@ -89,7 +88,7 @@ static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com"; // Set the access token to be used. NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken; - call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; + call.requestHeaders[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; // Start the RPC. [call start]; diff --git a/examples/objective-c/auth_sample/Podfile b/examples/objective-c/auth_sample/Podfile index dd4fd558c0e..ea70511dc6c 100644 --- a/examples/objective-c/auth_sample/Podfile +++ b/examples/objective-c/auth_sample/Podfile @@ -1,6 +1,9 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' +pod 'Protobuf', :path => "../../../third_party/protobuf" +pod 'gRPC', :path => "../../.." + target 'AuthSample' do # Depend on the generated AuthTestService library. pod 'AuthTestService', :path => '.' diff --git a/examples/objective-c/auth_sample/README.md b/examples/objective-c/auth_sample/README.md index 5ae64526191..c560b7af65b 100644 --- a/examples/objective-c/auth_sample/README.md +++ b/examples/objective-c/auth_sample/README.md @@ -1,189 +1,3 @@ #OAuth2 on gRPC: Objective-C -This example application demostrates how to use OAuth2 on gRPC to make authenticated API calls on -behalf of a user. By walking through it you'll learn how to use the Objective-C gRPC API to: - -- Initialize and configure a remote call object before the RPC is started. -- Set request metadata elements on a call, which are semantically equivalent to HTTP request -headers. -- Read response metadata from a call, which is equivalent to HTTP response headers and trailers. - -It assumes you know the basics on how to make gRPC API calls using the Objective-C client library, -as shown in the [Hello World](../helloworld) -or [Route Guide](../route_guide) tutorials, -and are familiar with OAuth2 concepts like _access token_. - -- [Example code and setup](#setup) -- [Try it out!](#try) -- [Create an RPC object and start it later](#rpc-object) -- [Set request metadata of a call: Authorization header with an access token](#request-metadata) -- [Get response metadata of a call: Auth challenge header](#response-metadata) - - -## Example code and setup - -The example code for our tutorial is in [examples/objective-c/auth_sample](.). -To download the example, clone this repository by running the following command: -```shell -$ git clone https://github.com/grpc/grpc.git -``` - -Then change your current directory to `examples/objective-c/auth_sample`: -```shell -$ cd examples/objective-c/auth_sample -``` - -Our example is a simple application with two views. The first one lets a user sign in and out using -the OAuth2 flow of Google's [iOS SignIn library](https://developers.google.com/identity/sign-in/ios/). -(Google's library is used in this example because the test gRPC service we are going to call expects -Google account credentials, but neither gRPC nor the Objective-C client library is tied to any -specific OAuth2 provider). The second view makes a gRPC request to the test server, using the -access token obtained by the first view. - -Note: OAuth2 libraries need the application to register and obtain an ID from the identity provider -(in the case of this example app, Google). The app's XCode project is configured using that ID, so -you shouldn't copy this project "as is" for your own app: it would result in your app being -identified in the consent screen as "gRPC-AuthSample", and not having access to real Google -services. Instead, configure your own XCode project following the [instructions here](https://developers.google.com/identity/sign-in/ios/). - -As with the other examples, you also should have [Cocoapods](https://cocoapods.org/#install) -installed, as well as the relevant tools to generate the client library code. You can obtain the -latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). - - - -## Try it out! - -To try the sample app, first have Cocoapods generate and install the client library for our .proto -files: - -```shell -$ pod install -``` - -(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet -on your computer's cache). - -Finally, open the XCode workspace created by Cocoapods, and run the app. - -The first view, `SelectUserViewController.h/m`, asks you to sign in with your Google account, and to -give the "gRPC-AuthSample" app the following permissions: - -- View your email address. -- View your basic profile info. -- "Test scope for access to the Zoo service". - -This last permission, corresponding to the scope `https://www.googleapis.com/auth/xapi.zoo` doesn't -grant any real capability: it's only used for testing. You can log out at any time. - -The second view, `MakeRPCViewController.h/m`, makes a gRPC request to a test server at -https://grpc-test.sandbox.google.com, sending the access token along with the request. The test -service simply validates the token and writes in its response which user it belongs to, and which -scopes it gives access to. (The client application already knows those two values; it's a way to -verify that everything went as expected). - -The next sections guide you step-by-step through how the gRPC call in `MakeRPCViewController` is -performed. - - -## Create an RPC object and start it later - -The other basic tutorials show how to invoke an RPC by calling an asynchronous method in a generated -client object. This shows how to initialize an object that represents the RPC, and configure it -before starting the network request. - -Assume you have a proto service definition like this: - -```protobuf -option objc_class_prefix = "AUTH"; - -service TestService { - rpc UnaryCall(Request) returns (Response); -} -``` - -A `unaryCallWithRequest:handler:` method, with which you're already familiar, is generated for the -`AUTHTestService` class: - -```objective-c -[client unaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { - ... -}]; -``` - -In addition, an `RPCToUnaryCallWithRequest:handler:` method is generated, which returns a -not-yet-started RPC object: - -```objective-c -#import - -ProtoRPC *call = - [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { - ... - }]; -``` - -The RPC represented by this object can be started at any later time like this: - -```objective-c -[call start]; -``` - - -## Set request metadata of a call: Authorization header with an access token - -The `ProtoRPC` class has a `requestMetadata` property (inherited from `GRPCCall`) defined like this: - -```objective-c -- (NSMutableDictionary *)requestMetadata; // nonatomic -- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy -``` - -Setting it to a dictionary of metadata keys and values will have them sent on the wire when the call -is started. gRPC metadata are pieces of information about the call sent by the client to the server -(and vice versa). They take the form of key-value pairs and are essentially opaque to gRPC itself. - -```objective-c -call.requestMetadata = @{@"My-Header": @"Value for this header", - @"Another-Header": @"Its value"}; -``` - -For convenience, the property is initialized with an empty `NSMutableDictionary`, so that request -metadata elements can be set like this: - -```objective-c -call.requestMetadata[@"My-Header"] = @"Value for this header"; -``` - -If you have an access token, OAuth2 specifies it is to be sent in this format: - -```objective-c -call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; -``` - - -## Get response metadata of a call: Auth challenge header - -The `ProtoRPC` class also inherits a `responseMetadata` property, analogous to the request metadata -we just looked at. It's defined like this: - -```objective-c -@property(atomic, readonly) NSDictionary *responseMetadata; -``` - -To access OAuth2's authentication challenge header you write: - -```objective-c -call.responseMetadata[@"www-authenticate"] -``` - -Note that, as gRPC metadata elements are mapped to HTTP/2 headers (or trailers), the keys of the -response metadata are always ASCII strings in lowercase. - -Many uses cases of response metadata are getting more details about an RPC error. For convenience, -when a `NSError` instance is passed to an RPC handler block, the response metadata dictionary can -also be accessed this way: - -```objective-c -error.userInfo[kGRPCStatusMetadataKey] -``` +This is the supporting code for the tutorial "[OAuth2 on gRPC: Objective-C](http://www.grpc.io/docs/tutorials/auth/oauth2-objective-c.html)." diff --git a/examples/objective-c/helloworld/README.md b/examples/objective-c/helloworld/README.md index 75df1a7a26e..81c5aaa7bcb 100644 --- a/examples/objective-c/helloworld/README.md +++ b/examples/objective-c/helloworld/README.md @@ -12,11 +12,13 @@ Here's how to build and run the Objective-C implementation of the [Hello World]( example used in [Getting started](https://github.com/grpc/grpc/tree/master/examples). The example code for this and our other examples lives in the `examples` directory. Clone -this repository to your local machine by running the following command: +this repository to your local machine by running the following commands: ```sh $ git clone https://github.com/grpc/grpc.git +$ cd grpc +$ git submodule update --init ``` Change your current directory to `examples/objective-c/helloworld` @@ -53,4 +55,4 @@ responds with a `HLWHelloResponse`, which contains a string that is then output ## Tutorial -You can find a more detailed tutorial in [gRPC Basics: Objective-C](../route_guide/README.md). +You can find a more detailed tutorial in [gRPC Basics: Objective-C](http://www.grpc.io/docs/tutorials/basic/objective-c.html). diff --git a/examples/objective-c/route_guide/Podfile b/examples/objective-c/route_guide/Podfile index a97f4146858..efa46bba4fa 100644 --- a/examples/objective-c/route_guide/Podfile +++ b/examples/objective-c/route_guide/Podfile @@ -2,6 +2,8 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' target 'RouteGuideClient' do + pod 'Protobuf', :path => "../../../third_party/protobuf" + pod 'gRPC', :path => "../../.." # Depend on the generated RouteGuide library. pod 'RouteGuide', :path => '.' end diff --git a/examples/objective-c/route_guide/README.md b/examples/objective-c/route_guide/README.md index 15864c01f4b..6a6f7c0d338 100644 --- a/examples/objective-c/route_guide/README.md +++ b/examples/objective-c/route_guide/README.md @@ -1,360 +1,4 @@ #gRPC Basics: Objective-C -This tutorial provides a basic Objective-C programmer's introduction to working with gRPC. By -walking through this example you'll learn how to: +This is the supporting code for the tutorial "[gRPC Basics: Objective-C](http://www.grpc.io/docs/tutorials/basic/objective-c.html)." -- Define a service in a .proto file. -- Generate client code using the protocol buffer compiler. -- Use the Objective-C gRPC API to write a simple client for your service. - -It assumes a passing familiarity with [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). -Note that the example in this tutorial uses the proto3 version of the protocol buffers language, -which is currently in alpha release: you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) -and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the -protocol buffers Github repository. - -This isn't a comprehensive guide to using gRPC in Objective-C: more reference documentation is -coming soon. - -- [Why use gRPC?](#why-grpc) -- [Example code and setup](#setup) -- [Try it out!](#try) -- [Defining the service](#proto) -- [Generating client code](#protoc) -- [Creating the client](#client) - - -## Why use gRPC? - -With gRPC you can define your service once in a .proto file and implement clients and servers in any -of gRPC's supported languages, which in turn can be run in environments ranging from servers inside -Google to your own tablet - all the complexity of communication between different languages and -environments is handled for you by gRPC. You also get all the advantages of working with protocol -buffers, including efficient serialization, a simple IDL, and easy interface updating. - -gRPC and proto3 are specially suited for mobile clients: gRPC is implemented on top of HTTP/2, which -results in network bandwidth savings over using HTTP/1.1. Serialization and parsing of the proto -binary format is more efficient than the equivalent JSON, resulting in CPU and battery savings. And -proto3 uses a runtime that has been optimized over the years at Google to keep code size to a -minimum. The latter is important in Objective-C, because the ability of the compiler to strip unused -code is limited by the dynamic nature of the language. - - - -## Example code and setup - -The example code for our tutorial is in [examples/objective-c/route_guide](.). -To download the example, clone this repository by running the following command: -```shell -$ git clone https://github.com/grpc/grpc.git -``` - -Then change your current directory to `examples/objective-c/route_guide`: -```shell -$ cd examples/objective-c/route_guide -``` - -Our example is a simple route mapping application that lets clients get information about features -on their route, create a summary of their route, and exchange route information such as traffic -updates with the server and other clients. - -You also should have [Cocoapods](https://cocoapods.org/#install) installed, as well as the relevant -tools to generate the client library code (and a server in another language, for testing). You can -obtain the latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). - - - -## Try it out! - -To try the sample app, we need a gRPC server running locally. Let's compile and run, for example, -the C++ server in this repository: - -```shell -$ pushd ../../cpp/route_guide -$ make -$ ./route_guide_server & -$ popd -``` - -Now have Cocoapods generate and install the client library for our .proto files: - -```shell -$ pod install -``` - -(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet -on your computer's cache). - -Finally, open the XCode workspace created by Cocoapods, and run the app. You can check the calling -code in `ViewControllers.m` and see the results in XCode's log console. - -The next sections guide you step-by-step through how this proto service is defined, how to generate -a client library from it, and how to create an app that uses that library. - - - -## Defining the service - -First let's look at how the service we're using is defined. A gRPC *service* and its method -*request* and *response* types using [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). -You can see the complete .proto file for our example in [`examples/protos/route_guide.proto`](../../protos/route_guide.proto). - -To define a service, you specify a named `service` in your .proto file: - -```protobuf -service RouteGuide { - ... -} -``` - -Then you define `rpc` methods inside your service definition, specifying their request and response -types. Protocol buffers let you define four kinds of service method, all of which are used in the -`RouteGuide` service: - -- A *simple RPC* where the client sends a request to the server and receives a response later, just -like a normal remote procedure call. -```protobuf - // Obtains the feature at a given position. - rpc GetFeature(Point) returns (Feature) {} -``` - -- A *response-streaming RPC* where the client sends a request to the server and gets back a stream -of response messages. You specify a response-streaming method by placing the `stream` keyword before -the *response* type. -```protobuf - // Obtains the Features available within the given Rectangle. Results are - // streamed rather than returned at once (e.g. in a response message with a - // repeated field), as the rectangle may cover a large area and contain a - // huge number of features. - rpc ListFeatures(Rectangle) returns (stream Feature) {} -``` - -- A *request-streaming RPC* where the client sends a sequence of messages to the server. Once the -client has finished writing the messages, it waits for the server to read them all and return its -response. You specify a request-streaming method by placing the `stream` keyword before the -*request* type. -```protobuf - // Accepts a stream of Points on a route being traversed, returning a - // RouteSummary when traversal is completed. - rpc RecordRoute(stream Point) returns (RouteSummary) {} -``` - -- A *bidirectional streaming RPC* where both sides send a sequence of messages to the other. The two -streams operate independently, so clients and servers can read and write in whatever order they -like: for example, the server could wait to receive all the client messages before writing its -responses, or it could alternately read a message then write a message, or some other combination of -reads and writes. The order of messages in each stream is preserved. You specify this type of method -by placing the `stream` keyword before both the request and the response. -```protobuf - // Accepts a stream of RouteNotes sent while a route is being traversed, - // while receiving other RouteNotes (e.g. from other users). - rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} -``` - -Our .proto file also contains protocol buffer message type definitions for all the request and -response types used in our service methods - for example, here's the `Point` message type: -```protobuf -// Points are represented as latitude-longitude pairs in the E7 representation -// (degrees multiplied by 10**7 and rounded to the nearest integer). -// Latitudes should be in the range +/- 90 degrees and longitude should be in -// the range +/- 180 degrees (inclusive). -message Point { - int32 latitude = 1; - int32 longitude = 2; -} -``` - -You can specify a prefix to be used for your generated classes by adding the `objc_class_prefix` -option at the top of the file. For example: -```protobuf -option objc_class_prefix = "RTG"; -``` - - - -## Generating client code - -Next we need to generate the gRPC client interfaces from our .proto service definition. We do this -using the protocol buffer compiler (`protoc`) with a special gRPC Objective-C plugin. - -For simplicity, we've provided a [Podspec file](RouteGuide.podspec) -that runs `protoc` for you with the appropriate plugin, input, and output, and describes how to -compile the generated files. You just need to run in this directory (`examples/objective-c/route_guide`): - -```shell -$ pod install -``` - -which, before installing the generated library in the XCode project of this sample, runs: - -```shell -$ protoc -I ../../protos --objc_out=Pods/RouteGuide --objcgrpc_out=Pods/RouteGuide ../../protos/route_guide.proto -``` - -Running this command generates the following files under `Pods/RouteGuide/`: -- `RouteGuide.pbobjc.h`, the header which declares your generated message classes. -- `RouteGuide.pbobjc.m`, which contains the implementation of your message classes. -- `RouteGuide.pbrpc.h`, the header which declares your generated service classes. -- `RouteGuide.pbrpc.m`, which contains the implementation of your service classes. - -These contain: -- All the protocol buffer code to populate, serialize, and retrieve our request and response message -types. -- A class called `RTGRouteGuide` that lets clients call the methods defined in the `RouteGuide` -service. - -You can also use the provided Podspec file to generate client code from any other proto service -definition; just replace the name (matching the file name), version, and other metadata. - - - -## Creating the client - -In this section, we'll look at creating an Objective-C client for our `RouteGuide` service. You can -see our complete example client code in [ViewControllers.m](ViewControllers.m). -(Note: In your apps, for maintainability and readability reasons, you shouldn't put all of your view -controllers in a single file; it's done here only to simplify the learning process). - -### Constructing a client object - -To call service methods, we first need to create a client object, an instance of the generated -`RTGRouteGuide` class. The designated initializer of the class expects a `NSString *` with the -server address and port we want to connect to: - -```objective-c -#import - -static NSString * const kHostAddress = @"http://localhost:50051"; - -... - -RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; -``` - -Notice that we've specified the HTTP scheme in the host address. This is because the server we will -be using to test our client doesn't use [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security). -This is fine because it will be running locally on our development machine. The most common case, -though, is connecting with a gRPC server on the internet, running gRPC over TLS. For that case, the -HTTPS scheme can be specified (or no scheme at all, as HTTPS is the default value). The default -value of the port is that of the scheme selected: 443 for HTTPS and 80 for HTTP. - - -### Calling service methods - -Now let's look at how we call our service methods. As you will see, all these methods are -asynchronous, so you can call them from the main thread of your app without worrying about freezing -your UI or the OS killing your app. - -#### Simple RPC - -Calling the simple RPC `GetFeature` is nearly as straightforward as calling any other asynchronous -method on Cocoa. - -```objective-c -RTGPoint *point = [RTGPoint message]; -point.latitude = 40E7; -point.longitude = -74E7; - -[client getFeatureWithRequest:point handler:^(RTGFeature *response, NSError *error) { - if (response) { - // Successful response received - } else { - // RPC error - } -}]; -``` - -As you can see, we create and populate a request protocol buffer object (in our case `RTGPoint`). -Then, we call the method on the client object, passing it the request, and a block to handle the -response (or any RPC error). If the RPC finishes successfully, the handler block is called with a -`nil` error argument, and we can read the response information from the server from the response -argument. If, instead, some RPC error happens, the handler block is called with a `nil` response -argument, and we can read the details of the problem from the error argument. - -```objective-c -NSLog(@"Found feature called %@ at %@.", response.name, response.location); -``` - -#### Streaming RPCs - -Now let's look at our streaming methods. Here's where we call the response-streaming method -`ListFeatures`, which results in our client receiving a stream of geographical `RTGFeature`s: - -```objective-c -[client listFeaturesWithRequest:rectangle - eventHandler:^(BOOL done, RTGFeature *response, NSError *error) { - if (response) { - // Element of the stream of responses received - } else if (error) { - // RPC error; the stream is over. - } - if (done) { - // The stream is over (all the responses were received, or an error occured). Do any cleanup. - } -}]; -``` - -Notice how the signature of the `eventHandler` block now includes a `BOOL done` parameter. The -`eventHandler` block can be called any number of times; only on the last call is the `done` argument -value set to `YES`. If an error occurs, the RPC finishes and the block is called with the arguments -`(YES, nil, error)`. - -The request-streaming method `RecordRoute` expects a stream of `RTGPoint`s from the cient. This -stream is passed to the method as an object of class `GRXWriter`. The simplest way to create one is -to initialize one from a `NSArray` object: - - -```objective-c -#import - -... - -RTGPoint *point1 = [RTGPoint message]; -point.latitude = 40E7; -point.longitude = -74E7; - -RTGPoint *point2 = [RTGPoint message]; -point.latitude = 40E7; -point.longitude = -74E7; - -GRXWriter *locationsWriter = [GRXWriter writerWithContainer:@[point1, point2]]; - -[client recordRouteWithRequestsWriter:locationsWriter - handler:^(RTGRouteSummary *response, NSError *error) { - if (response) { - NSLog(@"Finished trip with %i points", response.pointCount); - NSLog(@"Passed %i features", response.featureCount); - NSLog(@"Travelled %i meters", response.distance); - NSLog(@"It took %i seconds", response.elapsedTime); - } else { - NSLog(@"RPC error: %@", error); - } -}]; - -``` - -The `GRXWriter` class is generic enough to allow for asynchronous streams, streams of future values, -or even infinite streams. - -Finally, let's look at our bidirectional streaming RPC `RouteChat()`. The way to call a -bidirectional streaming RPC is just a combination of how to call request-streaming RPCs and -response-streaming RPCs. - -```objective-c -[client routeChatWithRequestsWriter:notesWriter - eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) { - if (note) { - NSLog(@"Got message %@ at %@", note.message, note.location); - } else if (error) { - NSLog(@"RPC error: %@", error); - } - if (done) { - NSLog(@"Chat ended."); - } -}]; -``` - -The semantics for the handler block and the `GRXWriter` argument here are exactly the same as for -our request-streaming and response-streaming methods. Although both client and server will always -get the other's messages in the order they were written, the two streams operate completely -independently. diff --git a/examples/objective-c/route_guide/RouteGuide.podspec b/examples/objective-c/route_guide/RouteGuide.podspec index 7b99a6c6a77..e00f827e3a4 100644 --- a/examples/objective-c/route_guide/RouteGuide.podspec +++ b/examples/objective-c/route_guide/RouteGuide.podspec @@ -3,13 +3,13 @@ Pod::Spec.new do |s| s.version = "0.0.1" s.license = "New BSD" - s.ios.deployment_target = "6.0" - s.osx.deployment_target = "10.8" + s.ios.deployment_target = "7.1" + s.osx.deployment_target = "10.9" # Base directory where the .proto files are. src = "../../protos" - # Directory where the generated files will be place. + # Directory where the generated files will be placed. dir = "Pods/" + s.name # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. @@ -22,14 +22,14 @@ Pod::Spec.new do |s| ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" ms.header_mappings_dir = dir ms.requires_arc = false - ms.dependency "Protobuf", "~> 3.0.0-alpha-3" + ms.dependency "Protobuf", "~> 3.0.0-alpha-4" end s.subspec "Services" do |ss| ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" ss.header_mappings_dir = dir ss.requires_arc = true - ss.dependency "gRPC", "~> 0.6" + ss.dependency "gRPC", "~> 0.11" ss.dependency "#{s.name}/Messages" end end diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj index 6ab6b27a1b5..f99775562c0 100644 --- a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj +++ b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj @@ -121,6 +121,7 @@ 6325277A1B1D0395003073D9 /* Frameworks */, 6325277B1B1D0395003073D9 /* Resources */, FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */, + B5388EC5A25E89021740B916 /* Embed Pods Frameworks */, ); buildRules = ( ); @@ -177,6 +178,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + B5388EC5A25E89021740B916 /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/examples/objective-c/route_guide/ViewControllers.m b/examples/objective-c/route_guide/ViewControllers.m index cfc3338bcac..0b1a1cf4823 100644 --- a/examples/objective-c/route_guide/ViewControllers.m +++ b/examples/objective-c/route_guide/ViewControllers.m @@ -32,13 +32,14 @@ */ #import +#import #import #import #import -static NSString * const kHostAddress = @"http://localhost:50051"; +static NSString * const kHostAddress = @"localhost:50051"; -// Category to override RTGPoint's description. +/** Category to override RTGPoint's description. */ @interface RTGPoint (Description) - (NSString *)description; @end @@ -53,7 +54,7 @@ static NSString * const kHostAddress = @"http://localhost:50051"; } @end -// Category to give RTGRouteNote a convenience constructor. +/** Category to give RTGRouteNote a convenience constructor. */ @interface RTGRouteNote (Constructors) + (instancetype)noteWithMessage:(NSString *)message latitude:(float)latitude @@ -75,9 +76,10 @@ static NSString * const kHostAddress = @"http://localhost:50051"; #pragma mark Demo: Get Feature -// Run the getFeature demo. Calls getFeature with a point known to have a feature and a point known -// not to have a feature. - +/** + * Run the getFeature demo. Calls getFeature with a point known to have a feature and a point known + * not to have a feature. + */ @interface GetFeatureViewController : UIViewController @end @@ -86,7 +88,10 @@ static NSString * const kHostAddress = @"http://localhost:50051"; - (void)viewDidLoad { [super viewDidLoad]; - RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + // This only needs to be done once per host, before creating service objects for that host. + [GRPCCall useInsecureConnectionsForHost:kHostAddress]; + + RTGRouteGuide *service = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; void (^handler)(RTGFeature *response, NSError *error) = ^(RTGFeature *response, NSError *error) { if (response.name.length) { @@ -102,8 +107,8 @@ static NSString * const kHostAddress = @"http://localhost:50051"; point.latitude = 409146138; point.longitude = -746188906; - [client getFeatureWithRequest:point handler:handler]; - [client getFeatureWithRequest:[RTGPoint message] handler:handler]; + [service getFeatureWithRequest:point handler:handler]; + [service getFeatureWithRequest:[RTGPoint message] handler:handler]; } @end @@ -111,9 +116,10 @@ static NSString * const kHostAddress = @"http://localhost:50051"; #pragma mark Demo: List Features -// Run the listFeatures demo. Calls listFeatures with a rectangle containing all of the features in -// the pre-generated database. Prints each response as it comes in. - +/** + * Run the listFeatures demo. Calls listFeatures with a rectangle containing all of the features in + * the pre-generated database. Prints each response as it comes in. + */ @interface ListFeaturesViewController : UIViewController @end @@ -122,7 +128,7 @@ static NSString * const kHostAddress = @"http://localhost:50051"; - (void)viewDidLoad { [super viewDidLoad]; - RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + RTGRouteGuide *service = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; RTGRectangle *rectangle = [RTGRectangle message]; rectangle.lo.latitude = 405E6; @@ -131,8 +137,8 @@ static NSString * const kHostAddress = @"http://localhost:50051"; rectangle.hi.longitude = -745E6; NSLog(@"Looking for features between %@ and %@", rectangle.lo, rectangle.hi); - [client listFeaturesWithRequest:rectangle - eventHandler:^(BOOL done, RTGFeature *response, NSError *error) { + [service listFeaturesWithRequest:rectangle + eventHandler:^(BOOL done, RTGFeature *response, NSError *error) { if (response) { NSLog(@"Found feature at %@ called %@.", response.location, response.name); } else if (error) { @@ -146,10 +152,11 @@ static NSString * const kHostAddress = @"http://localhost:50051"; #pragma mark Demo: Record Route -// Run the recordRoute demo. Sends several randomly chosen points from the pre-generated feature -// database with a variable delay in between. Prints the statistics when they are sent from the -// server. - +/** + * Run the recordRoute demo. Sends several randomly chosen points from the pre-generated feature + * database with a variable delay in between. Prints the statistics when they are sent from the + * server. + */ @interface RecordRouteViewController : UIViewController @end @@ -171,9 +178,10 @@ static NSString * const kHostAddress = @"http://localhost:50051"; return location; }]; - RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + RTGRouteGuide *service = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; - [client recordRouteWithRequestsWriter:locations handler:^(RTGRouteSummary *response, NSError *error) { + [service recordRouteWithRequestsWriter:locations + handler:^(RTGRouteSummary *response, NSError *error) { if (response) { NSLog(@"Finished trip with %i points", response.pointCount); NSLog(@"Passed %i features", response.featureCount); @@ -190,9 +198,10 @@ static NSString * const kHostAddress = @"http://localhost:50051"; #pragma mark Demo: Route Chat -// Run the routeChat demo. Send some chat messages, and print any chat messages that are sent from -// the server. - +/** + * Run the routeChat demo. Send some chat messages, and print any chat messages that are sent from + * the server. + */ @interface RouteChatViewController : UIViewController @end @@ -210,10 +219,10 @@ static NSString * const kHostAddress = @"http://localhost:50051"; return note; }]; - RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + RTGRouteGuide *service = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; - [client routeChatWithRequestsWriter:notesWriter - eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) { + [service routeChatWithRequestsWriter:notesWriter + eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) { if (note) { NSLog(@"Got message %@ at %@", note.message, note.location); } else if (error) { diff --git a/gRPC.podspec b/gRPC.podspec index d101253bb17..2100fc86e7c 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -566,8 +566,12 @@ Pod::Spec.new do |s| ss.header_mappings_dir = '.' # This isn't officially supported in Cocoapods. We've asked for an alternative: # https://github.com/CocoaPods/CocoaPods/issues/4386 - ss.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC" ' + - '"$(PODS_ROOT)/Headers/Private/gRPC/include"' } + ss.xcconfig = { + 'USE_HEADERMAP' => 'NO', + 'ALWAYS_SEARCH_USER_PATHS' => 'NO', + 'USER_HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC"', + 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC/include"' + } ss.requires_arc = false ss.libraries = 'z' diff --git a/include/grpc++/support/byte_buffer.h b/include/grpc++/support/byte_buffer.h index c413703970b..9d19b077089 100644 --- a/include/grpc++/support/byte_buffer.h +++ b/include/grpc++/support/byte_buffer.h @@ -75,7 +75,6 @@ class ByteBuffer GRPC_FINAL { // takes ownership void set_buffer(grpc_byte_buffer* buf) { if (buffer_) { - gpr_log(GPR_ERROR, "Overriding existing buffer"); Clear(); } buffer_ = buf; diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index a17e167d2bf..9d965260ca3 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -56,7 +56,7 @@ class string_ref { typedef std::reverse_iterator const_reverse_iterator; // constants - const static size_t npos = size_t(-1); + const static size_t npos; // construct/copy. string_ref() : data_(nullptr), length_(0) {} diff --git a/include/grpc++/support/sync_stream.h b/include/grpc++/support/sync_stream.h index 514363338d8..daf4e367aeb 100644 --- a/include/grpc++/support/sync_stream.h +++ b/include/grpc++/support/sync_stream.h @@ -131,7 +131,7 @@ class ClientReader GRPC_FINAL : public ClientReaderInterface { cq_.Pluck(&ops); } - void WaitForInitialMetadata() { + void WaitForInitialMetadata() GRPC_OVERRIDE { GPR_ASSERT(!context_->initial_metadata_received_); CallOpSet ops; @@ -257,7 +257,7 @@ class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface { cq_.Pluck(&ops); } - void WaitForInitialMetadata() { + void WaitForInitialMetadata() GRPC_OVERRIDE { GPR_ASSERT(!context_->initial_metadata_received_); CallOpSet ops; diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h index 1433ffdf7e3..ffc5982bc03 100644 --- a/include/grpc/byte_buffer.h +++ b/include/grpc/byte_buffer.h @@ -106,6 +106,9 @@ void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader); int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, gpr_slice *slice); +/** Merge all data from \a reader into single slice */ +gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader); + /** Returns a RAW byte buffer instance from the output of \a reader. */ grpc_byte_buffer *grpc_raw_byte_buffer_from_reader( grpc_byte_buffer_reader *reader); diff --git a/include/grpc/support/histogram.h b/include/grpc/support/histogram.h index 2fd1084208f..fd56dacc989 100644 --- a/include/grpc/support/histogram.h +++ b/include/grpc/support/histogram.h @@ -50,7 +50,7 @@ void gpr_histogram_add(gpr_histogram *h, double x); /* The following merges the second histogram into the first. It only works if they have the same buckets and resolution. Returns 0 on failure, 1 on success */ -int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src); +int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src); double gpr_histogram_percentile(gpr_histogram *histogram, double percentile); double gpr_histogram_mean(gpr_histogram *histogram); diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c index bce1ce97144..6f478ccacb9 100644 --- a/src/core/iomgr/pollset_posix.c +++ b/src/core/iomgr/pollset_posix.c @@ -121,12 +121,14 @@ void grpc_pollset_kick_ext(grpc_pollset *p, if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { specific_worker->reevaluate_polling_on_wakeup = 1; } + specific_worker->kicked_specifically = 1; grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd); } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) { GPR_TIMER_MARK("kick_yoself", 0); if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { specific_worker->reevaluate_polling_on_wakeup = 1; } + specific_worker->kicked_specifically = 1; grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd); } } else if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) { @@ -242,6 +244,7 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, /* this must happen before we (potentially) drop pollset->mu */ worker->next = worker->prev = NULL; worker->reevaluate_polling_on_wakeup = 0; + worker->kicked_specifically = 0; /* TODO(ctiller): pool these */ grpc_wakeup_fd_init(&worker->wakeup_fd); /* If there's work waiting for the pollset to be idle, and the @@ -308,7 +311,7 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (worker->reevaluate_polling_on_wakeup) { worker->reevaluate_polling_on_wakeup = 0; pollset->kicked_without_pollers = 0; - if (queued_work) { + if (queued_work || worker->kicked_specifically) { /* If there's queued work on the list, then set the deadline to be immediate so we get back out of the polling loop quickly */ deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC); diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h index 34f76db2afa..95ebeab1c26 100644 --- a/src/core/iomgr/pollset_posix.h +++ b/src/core/iomgr/pollset_posix.h @@ -51,6 +51,7 @@ struct grpc_fd; typedef struct grpc_pollset_worker { grpc_wakeup_fd wakeup_fd; int reevaluate_polling_on_wakeup; + int kicked_specifically; struct grpc_pollset_worker *next; struct grpc_pollset_worker *prev; } grpc_pollset_worker; diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c index 8a1a9d92330..77b48af9969 100644 --- a/src/core/support/histogram.c +++ b/src/core/support/histogram.c @@ -125,7 +125,7 @@ void gpr_histogram_add(gpr_histogram *h, double x) { h->buckets[bucket_for(h, x)]++; } -int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) { +int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) { if ((dst->num_buckets != src->num_buckets) || (dst->multiplier != src->multiplier)) { /* Fail because these histograms don't match */ diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c index bc0586d0691..623a8d92337 100644 --- a/src/core/support/time_win32.c +++ b/src/core/support/time_win32.c @@ -66,14 +66,12 @@ gpr_timespec gpr_now(gpr_clock_type clock) { now_tv.tv_nsec = now_tb.millitm * 1000000; break; case GPR_CLOCK_MONOTONIC: + case GPR_CLOCK_PRECISE: QueryPerformanceCounter(×tamp); now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale; now_tv.tv_sec = (time_t)now_dbl; now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9); break; - case GPR_CLOCK_PRECISE: - gpr_precise_clock_now(&now_tv); - break; } return now_tv; } diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c index 283db83833d..9f830df68ce 100644 --- a/src/core/surface/byte_buffer_reader.c +++ b/src/core/surface/byte_buffer_reader.c @@ -31,6 +31,7 @@ * */ +#include #include #include @@ -103,3 +104,21 @@ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, } return 0; } + +gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) { + gpr_slice in_slice; + size_t bytes_read = 0; + const size_t input_size = grpc_byte_buffer_length(reader->buffer_out); + gpr_slice out_slice = gpr_slice_malloc(input_size); + gpr_uint8 *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */ + + while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) { + const size_t slice_length = GPR_SLICE_LENGTH(in_slice); + memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length); + bytes_read += slice_length; + gpr_slice_unref(in_slice); + GPR_ASSERT(bytes_read <= input_size); + } + return out_slice; +} + diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc index 604134fa9da..66c79a18184 100644 --- a/src/cpp/util/string_ref.cc +++ b/src/cpp/util/string_ref.cc @@ -40,7 +40,7 @@ namespace grpc { -const size_t string_ref::npos; +const size_t string_ref::npos = size_t(-1); string_ref& string_ref::operator=(const string_ref& rhs) { data_ = rhs.data_; diff --git a/src/csharp/.gitignore b/src/csharp/.gitignore index deac55029ee..0f96a482219 100644 --- a/src/csharp/.gitignore +++ b/src/csharp/.gitignore @@ -7,6 +7,7 @@ Grpc.v12.suo Grpc.sdf TestResult.xml +coverage_results.xml /TestResults .vs/ *.nupkg diff --git a/src/csharp/.nuget/packages.config b/src/csharp/.nuget/packages.config index a7df95cf6bd..89a310ac569 100644 --- a/src/csharp/.nuget/packages.config +++ b/src/csharp/.nuget/packages.config @@ -1,4 +1,6 @@  + + \ No newline at end of file diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index e58528ff50e..25a5a27c8e3 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -38,6 +38,7 @@ using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; +using Grpc.Core.Profiling; using Grpc.Core.Utils; using NUnit.Framework; @@ -200,19 +201,6 @@ namespace Grpc.Core.Tests Assert.AreEqual(headers[1].Key, trailers[1].Key); CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes); } - - [Test] - public void UnaryCallPerformance() - { - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => - { - return request; - }); - - var callDetails = helper.CreateUnaryCall(); - BenchmarkUtil.RunBenchmark(1, 10, - () => { Calls.BlockingUnaryCall(callDetails, "ABC"); }); - } [Test] public void UnknownMethodHandler() diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 91d072ababe..e5ffa319895 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -88,6 +88,7 @@ + diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs index 874df02baa0..9be5450d810 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs @@ -34,6 +34,7 @@ using System; using System.Runtime.InteropServices; using Grpc.Core.Internal; +using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests @@ -198,5 +199,23 @@ namespace Grpc.Core.Internal.Tests Console.WriteLine("Test cannot be run on this platform, skipping the test."); } } + + // Test attribute commented out to prevent running as part of the default test suite. + // [Test] + // [Category("Performance")] + public void NowBenchmark() + { + // approx Timespec.Now latency <33ns + BenchmarkUtil.RunBenchmark(10000000, 1000000000, () => { var now = Timespec.Now; }); + } + + // Test attribute commented out to prevent running as part of the default test suite. + // [Test] + // [Category("Performance")] + public void PreciseNowBenchmark() + { + // approx Timespec.PreciseNow latency <18ns (when compiled with GRPC_TIMERS_RDTSC) + BenchmarkUtil.RunBenchmark(10000000, 1000000000, () => { var now = Timespec.PreciseNow; }); + } } } diff --git a/src/csharp/Grpc.Core.Tests/PerformanceTest.cs b/src/csharp/Grpc.Core.Tests/PerformanceTest.cs new file mode 100644 index 00000000000..5516cd33774 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/PerformanceTest.cs @@ -0,0 +1,99 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Profiling; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class PerformanceTest + { + const string Host = "127.0.0.1"; + + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + helper = new MockServiceHelper(Host); + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [TearDown] + public void Cleanup() + { + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + + // Test attribute commented out to prevent running as part of the default test suite. + //[Test] + //[Category("Performance")] + public void UnaryCallPerformance() + { + var profiler = new BasicProfiler(); + Profilers.SetForCurrentThread(profiler); + + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + return request; + }); + + var callDetails = helper.CreateUnaryCall(); + for(int i = 0; i < 3000; i++) + { + Calls.BlockingUnaryCall(callDetails, "ABC"); + } + + profiler.Reset(); + + for(int i = 0; i < 3000; i++) + { + Calls.BlockingUnaryCall(callDetails, "ABC"); + } + profiler.Dump("latency_trace_csharp.txt"); + } + } +} diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 92d4e19eac2..0aab7bdd8ad 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -119,6 +119,10 @@ + + + + @@ -150,4 +154,7 @@ + + + \ No newline at end of file diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 800462c8540..e3ecc472826 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -39,6 +39,7 @@ using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; +using Grpc.Core.Profiling; using Grpc.Core.Utils; namespace Grpc.Core.Internal @@ -87,6 +88,9 @@ namespace Grpc.Core.Internal /// public TResponse UnaryCall(TRequest msg) { + var profiler = Profilers.ForCurrentThread(); + + using (profiler.NewScope("AsyncCall.UnaryCall")) using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create()) { byte[] payload = UnsafeSerialize(msg); @@ -104,24 +108,26 @@ namespace Grpc.Core.Internal } using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + using (var ctx = BatchContextSafeHandle.Create()) { - using (var ctx = BatchContextSafeHandle.Create()) - { - call.StartUnary(ctx, payload, metadataArray, GetWriteFlagsForCall()); - var ev = cq.Pluck(ctx.Handle); + call.StartUnary(ctx, payload, metadataArray, GetWriteFlagsForCall()); + + var ev = cq.Pluck(ctx.Handle); - bool success = (ev.success != 0); - try + bool success = (ev.success != 0); + try + { + using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch")) { HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata()); } - catch (Exception e) - { - Logger.Error(e, "Exception occured while invoking completion delegate."); - } + } + catch (Exception e) + { + Logger.Error(e, "Exception occured while invoking completion delegate."); } } - + // Once the blocking call returns, the result should be available synchronously. // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException. return unaryResponseTcs.Task.GetAwaiter().GetResult(); @@ -329,27 +335,35 @@ namespace Grpc.Core.Internal private void Initialize(CompletionQueueSafeHandle cq) { - var call = CreateNativeCall(cq); - details.Channel.AddCallReference(this); - InitializeInternal(call); - RegisterCancellationCallback(); + using (Profilers.ForCurrentThread().NewScope("AsyncCall.Initialize")) + { + var call = CreateNativeCall(cq); + + details.Channel.AddCallReference(this); + InitializeInternal(call); + RegisterCancellationCallback(); + } } private INativeCall CreateNativeCall(CompletionQueueSafeHandle cq) { - if (injectedNativeCall != null) - { - return injectedNativeCall; // allows injecting a mock INativeCall in tests. - } + using (Profilers.ForCurrentThread().NewScope("AsyncCall.CreateNativeCall")) + { + if (injectedNativeCall != null) + { + return injectedNativeCall; // allows injecting a mock INativeCall in tests. + } - var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance; + var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance; - var credentials = details.Options.Credentials; - using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null) - { - return details.Channel.Handle.CreateCall(environment.CompletionRegistry, - parentCall, ContextPropagationToken.DefaultMask, cq, - details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials); + var credentials = details.Options.Credentials; + using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null) + { + var result = details.Channel.Handle.CreateCall(environment.CompletionRegistry, + parentCall, ContextPropagationToken.DefaultMask, cq, + details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials); + return result; + } } } @@ -385,33 +399,37 @@ namespace Grpc.Core.Internal /// private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders) { - TResponse msg = default(TResponse); - var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null; - - lock (myLock) + using (Profilers.ForCurrentThread().NewScope("AsyncCall.HandleUnaryResponse")) { - finished = true; + TResponse msg = default(TResponse); + var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null; - if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK) + lock (myLock) { - receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers); + finished = true; + + if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK) + { + receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers); + } + finishedStatus = receivedStatus; + + ReleaseResourcesIfPossible(); + } - finishedStatus = receivedStatus; - ReleaseResourcesIfPossible(); - } + responseHeadersTcs.SetResult(responseHeaders); - responseHeadersTcs.SetResult(responseHeaders); + var status = receivedStatus.Status; - var status = receivedStatus.Status; + if (!success || status.StatusCode != StatusCode.OK) + { + unaryResponseTcs.SetException(new RpcException(status)); + return; + } - if (!success || status.StatusCode != StatusCode.OK) - { - unaryResponseTcs.SetException(new RpcException(status)); - return; + unaryResponseTcs.SetResult(msg); } - - unaryResponseTcs.SetResult(msg); } /// diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 3e2c57c9b5b..953f61aa1ea 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -41,6 +41,7 @@ using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; +using Grpc.Core.Profiling; using Grpc.Core.Utils; namespace Grpc.Core.Internal @@ -167,16 +168,19 @@ namespace Grpc.Core.Internal /// protected bool ReleaseResourcesIfPossible() { - if (!disposed && call != null) + using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.ReleaseResourcesIfPossible")) { - bool noMoreSendCompletions = sendCompletionDelegate == null && (halfcloseRequested || cancelRequested || finished); - if (noMoreSendCompletions && readingDone && finished) + if (!disposed && call != null) { - ReleaseResources(); - return true; + bool noMoreSendCompletions = sendCompletionDelegate == null && (halfcloseRequested || cancelRequested || finished); + if (noMoreSendCompletions && readingDone && finished) + { + ReleaseResources(); + return true; + } } + return false; } - return false; } protected abstract bool IsClient @@ -228,7 +232,10 @@ namespace Grpc.Core.Internal protected byte[] UnsafeSerialize(TWrite msg) { - return serializer(msg); + using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.UnsafeSerialize")) + { + return serializer(msg); + } } protected Exception TrySerialize(TWrite msg, out byte[] payload) @@ -247,15 +254,20 @@ namespace Grpc.Core.Internal protected Exception TryDeserialize(byte[] payload, out TRead msg) { - try - { - msg = deserializer(payload); - return null; - } - catch (Exception e) + using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.TryDeserialize")) { - msg = default(TRead); - return e; + try + { + + msg = deserializer(payload); + return null; + + } + catch (Exception e) + { + msg = default(TRead); + return e; + } } } diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 0be7a4dd3a1..ddeedebd117 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -34,6 +34,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using Grpc.Core; using Grpc.Core.Utils; +using Grpc.Core.Profiling; namespace Grpc.Core.Internal { @@ -131,8 +132,11 @@ namespace Grpc.Core.Internal public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { - grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags) - .CheckOk(); + using (Profilers.ForCurrentThread().NewScope("CallSafeHandle.StartUnary")) + { + grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags) + .CheckOk(); + } } public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray) diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index d270d77526f..5f9169bcb2f 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -32,6 +32,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Grpc.Core.Profiling; namespace Grpc.Core.Internal { @@ -84,13 +85,16 @@ namespace Grpc.Core.Internal public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials) { - var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline); - if (credentials != null) + using (Profilers.ForCurrentThread().NewScope("ChannelSafeHandle.CreateCall")) { - result.SetCredentials(credentials); + var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline); + if (credentials != null) + { + result.SetCredentials(credentials); + } + result.SetCompletionRegistry(registry); + return result; } - result.SetCompletionRegistry(registry); - return result; } public ChannelState CheckConnectivityState(bool tryToConnect) diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs index f7a3471bb4b..9de2bc7950b 100644 --- a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs @@ -31,6 +31,7 @@ using System; using System.Runtime.InteropServices; using System.Threading.Tasks; +using Grpc.Core.Profiling; namespace Grpc.Core.Internal { @@ -70,7 +71,10 @@ namespace Grpc.Core.Internal public CompletionQueueEvent Pluck(IntPtr tag) { - return grpcsharp_completion_queue_pluck(this, tag); + using (Profilers.ForCurrentThread().NewScope("CompletionQueueSafeHandle.Pluck")) + { + return grpcsharp_completion_queue_pluck(this, tag); + } } public void Shutdown() diff --git a/src/csharp/Grpc.Core/Internal/Enums.cs b/src/csharp/Grpc.Core/Internal/Enums.cs index 185098160b6..b0eab2001bc 100644 --- a/src/csharp/Grpc.Core/Internal/Enums.cs +++ b/src/csharp/Grpc.Core/Internal/Enums.cs @@ -102,6 +102,9 @@ namespace Grpc.Core.Internal /* Realtime clock */ Realtime, + /* Precise clock good for performance profiling. */ + Precise, + /* Timespan - the distance between two time points */ Timespan } diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs index 31b834c979a..ed1bd244980 100644 --- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs @@ -31,6 +31,7 @@ using System; using System.Runtime.InteropServices; using System.Threading.Tasks; +using Grpc.Core.Profiling; namespace Grpc.Core.Internal { @@ -66,14 +67,17 @@ namespace Grpc.Core.Internal public static MetadataArraySafeHandle Create(Metadata metadata) { - // TODO(jtattermusch): we might wanna check that the metadata is readonly - var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count)); - for (int i = 0; i < metadata.Count; i++) + using (Profilers.ForCurrentThread().NewScope("MetadataArraySafeHandle.Create")) { - var valueBytes = metadata[i].GetSerializedValueUnsafe(); - grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length)); + // TODO(jtattermusch): we might wanna check that the metadata is readonly + var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count)); + for (int i = 0; i < metadata.Count; i++) + { + var valueBytes = metadata[i].GetSerializedValueUnsafe(); + grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length)); + } + return metadataArray; } - return metadataArray; } /// diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index daf85d5f61d..38fc067d9f4 100644 --- a/src/csharp/Grpc.Core/Internal/Timespec.cs +++ b/src/csharp/Grpc.Core/Internal/Timespec.cs @@ -239,6 +239,19 @@ namespace Grpc.Core.Internal } } + /// + /// Gets current timestamp using GPRClockType.Precise. + /// Only available internally because core needs to be compiled with + /// GRPC_TIMERS_RDTSC support for this to use RDTSC. + /// + internal static Timespec PreciseNow + { + get + { + return gprsharp_now(GPRClockType.Precise); + } + } + internal static int NativeSize { get diff --git a/src/csharp/Grpc.Core/Profiling/IProfiler.cs b/src/csharp/Grpc.Core/Profiling/IProfiler.cs new file mode 100644 index 00000000000..c426c365d2d --- /dev/null +++ b/src/csharp/Grpc.Core/Profiling/IProfiler.cs @@ -0,0 +1,47 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.IO; +using System.Threading; +using Grpc.Core.Internal; + +namespace Grpc.Core.Profiling +{ + internal interface IProfiler + { + void Begin(string tag); + void End(string tag); + void Mark(string tag); + } +} diff --git a/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs b/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs new file mode 100644 index 00000000000..5cc4c3c0542 --- /dev/null +++ b/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs @@ -0,0 +1,87 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.IO; +using System.Threading; +using Grpc.Core.Internal; + +namespace Grpc.Core.Profiling +{ + internal struct ProfilerEntry + { + public enum Type { + BEGIN, + END, + MARK + } + + public ProfilerEntry(Timespec timespec, Type type, string tag) + { + this.timespec = timespec; + this.type = type; + this.tag = tag; + } + + public Timespec timespec; + public Type type; + public string tag; + + public override string ToString() + { + // mimic the output format used by C core. + return string.Format( + "{{\"t\": {0}.{1}, \"thd\":\"unknown\", \"type\": \"{2}\", \"tag\": \"{3}\", " + + "\"file\": \"unknown\", \"line\": 0, \"imp\": 0}}", + timespec.TimevalSeconds, timespec.TimevalNanos.ToString("D9"), + GetTypeAbbreviation(type), tag); + } + + internal static string GetTypeAbbreviation(Type type) + { + switch (type) + { + case Type.BEGIN: + return "{"; + + case Type.END: + return "}"; + + case Type.MARK: + return "."; + default: + throw new ArgumentException("Unknown type"); + } + } + } +} diff --git a/src/csharp/Grpc.Core/Profiling/ProfilerScope.cs b/src/csharp/Grpc.Core/Profiling/ProfilerScope.cs new file mode 100644 index 00000000000..413f3a1a358 --- /dev/null +++ b/src/csharp/Grpc.Core/Profiling/ProfilerScope.cs @@ -0,0 +1,60 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.IO; +using System.Threading; +using Grpc.Core.Internal; + +namespace Grpc.Core.Profiling +{ + // Allows declaring Begin and End of a profiler scope with a using statement. + // declared as struct for better performance. + internal struct ProfilerScope : IDisposable + { + readonly IProfiler profiler; + readonly string tag; + + public ProfilerScope(IProfiler profiler, string tag) + { + this.profiler = profiler; + this.tag = tag; + this.profiler.Begin(this.tag); + } + + public void Dispose() + { + profiler.End(tag); + } + } +} diff --git a/src/csharp/Grpc.Core/Profiling/Profilers.cs b/src/csharp/Grpc.Core/Profiling/Profilers.cs new file mode 100644 index 00000000000..c8123347f2b --- /dev/null +++ b/src/csharp/Grpc.Core/Profiling/Profilers.cs @@ -0,0 +1,131 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.IO; +using System.Threading; +using Grpc.Core.Internal; + +namespace Grpc.Core.Profiling +{ + internal static class Profilers + { + static readonly NopProfiler defaultProfiler = new NopProfiler(); + static readonly ThreadLocal profilers = new ThreadLocal(); + + public static IProfiler ForCurrentThread() + { + return profilers.Value ?? defaultProfiler; + } + + public static void SetForCurrentThread(IProfiler profiler) + { + profilers.Value = profiler; + } + + public static ProfilerScope NewScope(this IProfiler profiler, string tag) + { + return new ProfilerScope(profiler, tag); + } + } + + internal class NopProfiler : IProfiler + { + public void Begin(string tag) + { + } + + public void End(string tag) + { + } + + public void Mark(string tag) + { + } + } + + // Profiler using Timespec.PreciseNow + internal class BasicProfiler : IProfiler + { + ProfilerEntry[] entries; + int count; + + public BasicProfiler() : this(1024*1024) + { + } + + public BasicProfiler(int capacity) + { + this.entries = new ProfilerEntry[capacity]; + } + + public void Begin(string tag) { + AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag)); + } + + public void End(string tag) { + AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag)); + } + + public void Mark(string tag) { + AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag)); + } + + public void Reset() + { + count = 0; + } + + public void Dump(string filepath) + { + using (var stream = new StreamWriter(filepath)) + { + Dump(stream); + } + } + + public void Dump(TextWriter stream) + { + for (int i = 0; i < count; i++) + { + var entry = entries[i]; + stream.WriteLine(entry.ToString()); + } + } + + // NOT THREADSAFE! + void AddEntry(ProfilerEntry entry) { + entries[count++] = entry; + } + } +} diff --git a/src/csharp/README.md b/src/csharp/README.md index 2083e184af0..65ae0b5efda 100644 --- a/src/csharp/README.md +++ b/src/csharp/README.md @@ -1,3 +1,4 @@ +[![Nuget](https://img.shields.io/nuget/v/Grpc.svg)](http://www.nuget.org/packages/Grpc/) gRPC C# ======= diff --git a/src/node/README.md b/src/node/README.md index 5d89e2228db..b46b9862432 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -1,3 +1,4 @@ +[![npm](https://img.shields.io/npm/v/grpc.svg)](https://www.npmjs.com/package/grpc) # Node.js gRPC Library ## Status diff --git a/src/node/src/client.js b/src/node/src/client.js index 596ea5ebb0b..d57826781d3 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -33,6 +33,17 @@ /** * Client module + * + * This module contains the factory method for creating Client classes, and the + * method calling code for all types of methods. + * + * For example, to create a client and call a method on it: + * + * var proto_obj = grpc.load(proto_file_path); + * var Client = proto_obj.package.subpackage.ServiceName; + * var client = new Client(server_address, client_credentials); + * var call = client.unaryMethod(arguments, callback); + * * @module */ @@ -601,7 +612,15 @@ exports.makeClientConstructor = function(methods, serviceName) { if (!options) { options = {}; } - options['grpc.primary_user_agent'] = 'grpc-node/' + version; + /* Append the grpc-node user agent string after the application user agent + * string, and put the combination at the beginning of the user agent string + */ + if (options['grpc.primary_user_agent']) { + options['grpc.primary_user_agent'] += ' '; + } else { + options['grpc.primary_user_agent'] = ''; + } + options['grpc.primary_user_agent'] += 'grpc-node/' + version; /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ this.$channel = new grpc.Channel(address, credentials, options); diff --git a/src/node/src/common.js b/src/node/src/common.js index ebaaa13db0f..e4fe5a8e035 100644 --- a/src/node/src/common.js +++ b/src/node/src/common.js @@ -32,6 +32,8 @@ */ /** + * This module contains functions that are common to client and server + * code. None of them should be used directly by gRPC users. * @module */ diff --git a/src/node/src/metadata.js b/src/node/src/metadata.js index 183c3ad4fcf..0a2f1489b6e 100644 --- a/src/node/src/metadata.js +++ b/src/node/src/metadata.js @@ -33,6 +33,15 @@ /** * Metadata module + * + * This module defines the Metadata class, which represents header and trailer + * metadata for gRPC calls. Here is an example of how to use it: + * + * var metadata = new metadata_module.Metadata(); + * metadata.set('key1', 'value1'); + * metadata.add('key1', 'value2'); + * metadata.get('key1') // returns ['value1', 'value2'] + * * @module */ diff --git a/src/node/src/server.js b/src/node/src/server.js index 89e1090c6c4..d1fb627e6cb 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -33,6 +33,17 @@ /** * Server module + * + * This module contains all the server code for Node gRPC: both the Server + * class itself and the method handler code for all types of methods. + * + * For example, to create a Server, add a service, and start it: + * + * var server = new server_module.Server(); + * server.addProtoService(protobuf_service_descriptor, service_implementation); + * server.bind('address:port', server_credential); + * server.start(); + * * @module */ @@ -746,8 +757,8 @@ Server.prototype.addProtoService = function(service, implementation) { * Binds the server to the given port, with SSL enabled if creds is given * @param {string} port The port that the server should bind on, in the format * "address:port" - * @param {boolean=} creds Server credential object to be used for SSL. Pass - * nothing for an insecure port + * @param {ServerCredentials=} creds Server credential object to be used for + * SSL. Pass an insecure credentials object for an insecure port. */ Server.prototype.bind = function(port, creds) { if (this.started) { diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h index 2e379a71572..6b443877e9b 100644 --- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h @@ -33,17 +33,19 @@ #import "GRPCCall.h" -// Helpers for setting and reading headers compatible with OAuth2. +/** Helpers for setting and reading headers compatible with OAuth2. */ @interface GRPCCall (OAuth2) -// Setting this property is equivalent to setting "Bearer " as the value of the -// request header with key "authorization" (the authorization header). Setting it to nil removes the -// authorization header from the request. -// The value obtained by getting the property is the OAuth2 bearer token if the authorization header -// of the request has the form "Bearer ", or nil otherwise. +/** + * Setting this property is equivalent to setting "Bearer " as the value of the + * request header with key "authorization" (the authorization header). Setting it to nil removes the + * authorization header from the request. + * The value obtained by getting the property is the OAuth2 bearer token if the authorization header + * of the request has the form "Bearer ", or nil otherwise. + */ @property(atomic, copy) NSString *oauth2AccessToken; -// Returns the value (if any) of the "www-authenticate" response header (the challenge header). +/** Returns the value (if any) of the "www-authenticate" response header (the challenge header). */ @property(atomic, readonly) NSString *oauth2ChallengeHeader; @end diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h index cca16146063..ccc5723ec70 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.h +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h @@ -33,22 +33,28 @@ #import "GRPCCall.h" -// Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be -// used in releases, but are sometimes needed for testing. +/** + * Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be + * used in releases, but are sometimes needed for testing. + */ @interface GRPCCall (Tests) -// Establish all SSL connections to the provided host using the passed SSL target name and the root -// certificates found in the file at |certsPath|. -// -// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to -// more than one invocation of the methods of this category. +/** + * Establish all SSL connections to the provided host using the passed SSL target name and the root + * certificates found in the file at |certsPath|. + * + * Must be called before any gRPC call to that host is made. It's illegal to pass the same host to + * more than one invocation of the methods of this category. + */ + (void)useTestCertsPath:(NSString *)certsPath testName:(NSString *)testName forHost:(NSString *)host; -// Establish all connections to the provided host using cleartext instead of SSL. -// -// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to -// more than one invocation of the methods of this category. +/** + * Establish all connections to the provided host using cleartext instead of SSL. + * + * Must be called before any gRPC call to that host is made. It's illegal to pass the same host to + * more than one invocation of the methods of this category. + */ + (void)useInsecureConnectionsForHost:(NSString *)host; @end diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m index bade0b29208..c8e81337031 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.m +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m @@ -40,6 +40,9 @@ + (void)useTestCertsPath:(NSString *)certsPath testName:(NSString *)testName forHost:(NSString *)host { + if (!host || !certsPath || !testName) { + [NSException raise:NSInvalidArgumentException format:@"host, path and name must be provided."]; + } GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; hostConfig.pathToCertificates = certsPath; hostConfig.hostNameOverride = testName; diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 35f7e16af70..5918f8857a9 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -31,117 +31,145 @@ * */ -// The gRPC protocol is an RPC protocol on top of HTTP2. -// -// While the most common type of RPC receives only one request message and returns only one response -// message, the protocol also supports RPCs that return multiple individual messages in a streaming -// fashion, RPCs that accept a stream of request messages, or RPCs with both streaming requests and -// responses. -// -// Conceptually, each gRPC call consists of a bidirectional stream of binary messages, with RPCs of -// the "non-streaming type" sending only one message in the corresponding direction (the protocol -// doesn't make any distinction). -// -// Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs can be multiplexed -// transparently on the same TCP connection. +/** + * The gRPC protocol is an RPC protocol on top of HTTP2. + * + * While the most common type of RPC receives only one request message and returns only one response + * message, the protocol also supports RPCs that return multiple individual messages in a streaming + * fashion, RPCs that accept a stream of request messages, or RPCs with both streaming requests and + * responses. + * + * Conceptually, each gRPC call consists of a bidirectional stream of binary messages, with RPCs of + * the "non-streaming type" sending only one message in the corresponding direction (the protocol + * doesn't make any distinction). + * + * Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs can be multiplexed + * transparently on the same TCP connection. + */ #import #import #pragma mark gRPC errors -// Domain of NSError objects produced by gRPC. +/** Domain of NSError objects produced by gRPC. */ extern NSString *const kGRPCErrorDomain; -// gRPC error codes. -// Note that a few of these are never produced by the gRPC libraries, but are of general utility for -// server applications to produce. +/** + * gRPC error codes. + * Note that a few of these are never produced by the gRPC libraries, but are of general utility for + * server applications to produce. + */ typedef NS_ENUM(NSUInteger, GRPCErrorCode) { - // The operation was cancelled (typically by the caller). + /** The operation was cancelled (typically by the caller). */ GRPCErrorCodeCancelled = 1, - // Unknown error. Errors raised by APIs that do not return enough error information may be - // converted to this error. + /** + * Unknown error. Errors raised by APIs that do not return enough error information may be + * converted to this error. + */ GRPCErrorCodeUnknown = 2, - // The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. - // INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the - // server (e.g., a malformed file name). + /** + * The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. + * INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the + * server (e.g., a malformed file name). + */ GRPCErrorCodeInvalidArgument = 3, - // Deadline expired before operation could complete. For operations that change the state of the - // server, this error may be returned even if the operation has completed successfully. For - // example, a successful response from the server could have been delayed long enough for the - // deadline to expire. + /** + * Deadline expired before operation could complete. For operations that change the state of the + * server, this error may be returned even if the operation has completed successfully. For + * example, a successful response from the server could have been delayed long enough for the + * deadline to expire. + */ GRPCErrorCodeDeadlineExceeded = 4, - // Some requested entity (e.g., file or directory) was not found. + /** Some requested entity (e.g., file or directory) was not found. */ GRPCErrorCodeNotFound = 5, - // Some entity that we attempted to create (e.g., file or directory) already exists. + /** Some entity that we attempted to create (e.g., file or directory) already exists. */ GRPCErrorCodeAlreadyExists = 6, - // The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't - // used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for - // those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller - // (UNAUTHENTICATED is used instead for those errors). + /** + * The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't + * used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for + * those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller + * (UNAUTHENTICATED is used instead for those errors). + */ GRPCErrorCodePermissionDenied = 7, - // The request does not have valid authentication credentials for the operation (e.g. the caller's - // identity can't be verified). + /** + * The request does not have valid authentication credentials for the operation (e.g. the caller's + * identity can't be verified). + */ GRPCErrorCodeUnauthenticated = 16, - // Some resource has been exhausted, perhaps a per-user quota. + /** Some resource has been exhausted, perhaps a per-user quota. */ GRPCErrorCodeResourceExhausted = 8, - // The RPC was rejected because the server is not in a state required for the procedure's - // execution. For example, a directory to be deleted may be non-empty, etc. - // The client should not retry until the server state has been explicitly fixed (e.g. by - // performing another RPC). The details depend on the service being called, and should be found in - // the NSError's userInfo. + /** + * The RPC was rejected because the server is not in a state required for the procedure's + * execution. For example, a directory to be deleted may be non-empty, etc. + * The client should not retry until the server state has been explicitly fixed (e.g. by + * performing another RPC). The details depend on the service being called, and should be found in + * the NSError's userInfo. + */ GRPCErrorCodeFailedPrecondition = 9, - // The RPC was aborted, typically due to a concurrency issue like sequencer check failures, - // transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read- - // modify-write sequence). + /** + * The RPC was aborted, typically due to a concurrency issue like sequencer check failures, + * transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read- + * modify-write sequence). + */ GRPCErrorCodeAborted = 10, - // The RPC was attempted past the valid range. E.g., enumerating past the end of a list. - // Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state - // changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked - // to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return - // the element at an index past the current size of the list. + /** + * The RPC was attempted past the valid range. E.g., enumerating past the end of a list. + * Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state + * changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked + * to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return + * the element at an index past the current size of the list. + */ GRPCErrorCodeOutOfRange = 11, - // The procedure is not implemented or not supported/enabled in this server. + /** The procedure is not implemented or not supported/enabled in this server. */ GRPCErrorCodeUnimplemented = 12, - // Internal error. Means some invariant expected by the server application or the gRPC library has - // been broken. + /** + * Internal error. Means some invariant expected by the server application or the gRPC library has + * been broken. + */ GRPCErrorCodeInternal = 13, - // The server is currently unavailable. This is most likely a transient condition and may be - // corrected by retrying with a backoff. + /** + * The server is currently unavailable. This is most likely a transient condition and may be + * corrected by retrying with a backoff. + */ GRPCErrorCodeUnavailable = 14, - // Unrecoverable data loss or corruption. + /** Unrecoverable data loss or corruption. */ GRPCErrorCodeDataLoss = 15, }; -// Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by -// the server. +/** + * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by + * the server. + */ extern id const kGRPCHeadersKey; extern id const kGRPCTrailersKey; #pragma mark GRPCCall -// The container of the request headers of an RPC conforms to this protocol, which is a subset of -// NSMutableDictionary's interface. It will become a NSMutableDictionary later on. -// The keys of this container are the header names, which per the HTTP standard are case- -// insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and -// can only consist of ASCII characters. -// A header value is a NSString object (with only ASCII characters), unless the header name has the -// suffix "-bin", in which case the value has to be a NSData object. +/** + * The container of the request headers of an RPC conforms to this protocol, which is a subset of + * NSMutableDictionary's interface. It will become a NSMutableDictionary later on. + * The keys of this container are the header names, which per the HTTP standard are case- + * insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and + * can only consist of ASCII characters. + * A header value is a NSString object (with only ASCII characters), unless the header name has the + * suffix "-bin", in which case the value has to be a NSData object. + */ @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; @@ -154,53 +182,63 @@ extern id const kGRPCTrailersKey; @end -// Represents a single gRPC remote call. +/** Represents a single gRPC remote call. */ @interface GRPCCall : GRXWriter -// These HTTP headers will be passed to the server as part of this call. Each HTTP header is a -// name-value pair with string names and either string or binary values. -// -// The passed dictionary has to use NSString keys, corresponding to the header names. The value -// associated to each can be a NSString object or a NSData object. E.g.: -// -// call.requestHeaders = @{@"authorization": @"Bearer ..."}; -// -// call.requestHeaders[@"my-header-bin"] = someData; -// -// After the call is started, trying to modify this property is an error. -// -// The property is initialized to an empty NSMutableDictionary. +/** + * These HTTP headers will be passed to the server as part of this call. Each HTTP header is a + * name-value pair with string names and either string or binary values. + * + * The passed dictionary has to use NSString keys, corresponding to the header names. The value + * associated to each can be a NSString object or a NSData object. E.g.: + * + * call.requestHeaders = @{@"authorization": @"Bearer ..."}; + * + * call.requestHeaders[@"my-header-bin"] = someData; + * + * After the call is started, trying to modify this property is an error. + * + * The property is initialized to an empty NSMutableDictionary. + */ @property(atomic, readonly) id requestHeaders; -// This dictionary is populated with the HTTP headers received from the server. This happens before -// any response message is received from the server. It has the same structure as the request -// headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a -// NSData value; the others have a NSString value. -// -// The value of this property is nil until all response headers are received, and will change before -// any of -writeValue: or -writesFinishedWithError: are sent to the writeable. +/** + * This dictionary is populated with the HTTP headers received from the server. This happens before + * any response message is received from the server. It has the same structure as the request + * headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a + * NSData value; the others have a NSString value. + * + * The value of this property is nil until all response headers are received, and will change before + * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. + */ @property(atomic, readonly) NSDictionary *responseHeaders; -// Same as responseHeaders, but populated with the HTTP trailers received from the server before the -// call finishes. -// -// The value of this property is nil until all response trailers are received, and will change -// before -writesFinishedWithError: is sent to the writeable. +/** + * Same as responseHeaders, but populated with the HTTP trailers received from the server before the + * call finishes. + * + * The value of this property is nil until all response trailers are received, and will change + * before -writesFinishedWithError: is sent to the writeable. + */ @property(atomic, readonly) NSDictionary *responseTrailers; -// The request writer has to write NSData objects into the provided Writeable. The server will -// receive each of those separately and in order as distinct messages. -// A gRPC call might not complete until the request writer finishes. On the other hand, the request -// finishing doesn't necessarily make the call to finish, as the server might continue sending -// messages to the response side of the call indefinitely (depending on the semantics of the -// specific remote method called). -// To finish a call right away, invoke cancel. +/** + * The request writer has to write NSData objects into the provided Writeable. The server will + * receive each of those separately and in order as distinct messages. + * A gRPC call might not complete until the request writer finishes. On the other hand, the request + * finishing doesn't necessarily make the call to finish, as the server might continue sending + * messages to the response side of the call indefinitely (depending on the semantics of the + * specific remote method called). + * To finish a call right away, invoke cancel. + */ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER; -// Finishes the request side of this call, notifies the server that the RPC should be cancelled, and -// finishes the response side of the call with an error of code CANCELED. +/** + * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and + * finishes the response side of the call with an error of code CANCELED. + */ - (void)cancel; // TODO(jcanizales): Let specify a deadline. As a category of GRXWriter? diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 2a7b701576a..e2d19d506ad 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -35,12 +35,16 @@ struct grpc_channel; -// Each separate instance of this class represents at least one TCP connection to the provided host. -// Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|. +/** + * Each separate instance of this class represents at least one TCP connection to the provided host. + * Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|. + */ @interface GRPCChannel : NSObject @property(nonatomic, readonly) struct grpc_channel *unmanagedChannel; -// This initializer takes ownership of the passed channel, and will destroy it when this object is -// deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects. +/** + * This initializer takes ownership of the passed channel, and will destroy it when this object is + * deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects. + */ - (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h index ab8d714d220..fe3b8f39d12 100644 --- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h +++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h @@ -36,15 +36,17 @@ typedef void(^GRPCQueueCompletionHandler)(bool success); -// This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the -// |unmanagedQueue| property of an instance of this class to |grpc_channel_create_call|. Then for -// every |grpc_call_*| method that accepts a tag, you can pass a block of type -// |GRPCQueueCompletionHandler| (remembering to cast it using |__bridge_retained|). The block is -// guaranteed to eventually be called, by a concurrent queue, and then released. Each such block is -// passed a |bool| that tells if the operation was successful. -// -// Release the GRPCCompletionQueue object only after you are not going to pass any more blocks to -// the |grpc_call| that's using it. +/** + * This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the + * |unmanagedQueue| property of an instance of this class to |grpc_channel_create_call|. Then for + * every |grpc_call_*| method that accepts a tag, you can pass a block of type + * |GRPCQueueCompletionHandler| (remembering to cast it using |__bridge_retained|). The block is + * guaranteed to eventually be called, by a concurrent queue, and then released. Each such block is + * passed a |bool| that tells if the operation was successful. + * + * Release the GRPCCompletionQueue object only after you are not going to pass any more blocks to + * the |grpc_call| that's using it. + */ @interface GRPCCompletionQueue : NSObject @property(nonatomic, readonly) grpc_completion_queue *unmanagedQueue; diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index f0bbd530234..6b4f98746d0 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -40,18 +40,18 @@ struct grpc_call; @property(nonatomic, readonly) NSString *address; -// The following properties should only be modified for testing: +/** The following properties should only be modified for testing: */ @property(nonatomic, getter=isSecure) BOOL secure; @property(nonatomic, copy) NSString *pathToCertificates; @property(nonatomic, copy) NSString *hostNameOverride; -// Host objects initialized with the same address are the same. +/** Host objects initialized with the same address are the same. */ + (instancetype)hostWithAddress:(NSString *)address; - (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER; -// Create a grpc_call object to the provided path on this host. +/** Create a grpc_call object to the provided path on this host. */ - (struct grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue; diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h index 74257eb0584..4e0881e5a2a 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h @@ -40,13 +40,15 @@ struct grpc_credentials; @interface GRPCSecureChannel : GRPCChannel - (instancetype)initWithHost:(NSString *)host; -// Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for -// pathToCertificates results in using the default root certificates distributed with the library. +/** + * Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for + * pathToCertificates results in using the default root certificates distributed with the library. + */ - (instancetype)initWithHost:(NSString *)host pathToCertificates:(NSString *)path hostNameOverride:(NSString *)hostNameOverride; -// The passed arguments aren't required to be valid beyond the invocation of this initializer. +/** The passed arguments aren't required to be valid beyond the invocation of this initializer. */ - (instancetype)initWithHost:(NSString *)host credentials:(struct grpc_credentials *)credentials args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h index 4ca2766147e..7747aa53ef0 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h @@ -39,7 +39,7 @@ @interface GRPCOperation : NSObject @property(nonatomic, readonly) grpc_op op; -// Guaranteed to be called when the operation has finished. +/** Guaranteed to be called when the operation has finished. */ - (void)finish; @end diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.h b/src/objective-c/GRPCClient/private/NSError+GRPC.h index f4729dc8a13..e0c1efc1f91 100644 --- a/src/objective-c/GRPCClient/private/NSError+GRPC.h +++ b/src/objective-c/GRPCClient/private/NSError+GRPC.h @@ -35,7 +35,9 @@ #include @interface NSError (GRPC) -// Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode| -// and whose domain is |kGRPCErrorDomain|. +/** + * Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode| + * and whose domain is |kGRPCErrorDomain|. + */ + (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details; @end diff --git a/src/objective-c/ProtoRPC/ProtoMethod.h b/src/objective-c/ProtoRPC/ProtoMethod.h index 8f554a04832..a0ed2cf98a5 100644 --- a/src/objective-c/ProtoRPC/ProtoMethod.h +++ b/src/objective-c/ProtoRPC/ProtoMethod.h @@ -33,8 +33,10 @@ #import -// A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint -// can implement multiple services. +/** + * A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint + * can implement multiple services. + */ @interface ProtoMethod : NSObject @property(nonatomic, readonly) NSString *package; @property(nonatomic, readonly) NSString *service; diff --git a/src/objective-c/README.md b/src/objective-c/README.md index a861a9f6f93..c1d25b96f50 100644 --- a/src/objective-c/README.md +++ b/src/objective-c/README.md @@ -1,3 +1,4 @@ +[![Cocoapods](https://img.shields.io/cocoapods/v/gRPC.svg)](https://cocoapods.org/pods/gRPC) # gRPC for Objective-C - [Install protoc with the gRPC plugin](#install) diff --git a/src/objective-c/RxLibrary/GRXBufferedPipe.h b/src/objective-c/RxLibrary/GRXBufferedPipe.h index ca94ce275f7..03b0359278a 100644 --- a/src/objective-c/RxLibrary/GRXBufferedPipe.h +++ b/src/objective-c/RxLibrary/GRXBufferedPipe.h @@ -36,25 +36,27 @@ #import "GRXWriteable.h" #import "GRXWriter.h" -// A buffered pipe is a Writer that also acts as a Writeable. -// Once it is started, whatever values are written into it (via -writeValue:) will be propagated -// immediately, unless flow control prevents it. -// If it is throttled and keeps receiving values, as well as if it receives values before being -// started, it will buffer them and propagate them in order as soon as its state becomes Started. -// If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and -// propagate the error immediately. -// -// Beware that a pipe of this type can't prevent receiving more values when it is paused (for -// example if used to write data to a congested network connection). Because in such situations the -// pipe will keep buffering all data written to it, your application could run out of memory and -// crash. If you want to react to flow control signals to prevent that, instead of using this class -// you can implement an object that conforms to GRXWriter. -// -// Thread-safety: -// The methods of an object of this class should not be called concurrently from different threads. +/** + * A buffered pipe is a Writer that also acts as a Writeable. + * Once it is started, whatever values are written into it (via -writeValue:) will be propagated + * immediately, unless flow control prevents it. + * If it is throttled and keeps receiving values, as well as if it receives values before being + * started, it will buffer them and propagate them in order as soon as its state becomes Started. + * If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and + * propagate the error immediately. + * + * Beware that a pipe of this type can't prevent receiving more values when it is paused (for + * example if used to write data to a congested network connection). Because in such situations the + * pipe will keep buffering all data written to it, your application could run out of memory and + * crash. If you want to react to flow control signals to prevent that, instead of using this class + * you can implement an object that conforms to GRXWriter. + * + * Thread-safety: + * The methods of an object of this class should not be called concurrently from different threads. + */ @interface GRXBufferedPipe : GRXWriter -// Convenience constructor. +/** Convenience constructor. */ + (instancetype)pipe; @end diff --git a/src/objective-c/RxLibrary/GRXConcurrentWriteable.h b/src/objective-c/RxLibrary/GRXConcurrentWriteable.h index 1080001905e..b2775f98b56 100644 --- a/src/objective-c/RxLibrary/GRXConcurrentWriteable.h +++ b/src/objective-c/RxLibrary/GRXConcurrentWriteable.h @@ -36,36 +36,48 @@ #import "GRXWriter.h" #import "GRXWriteable.h" -// This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a -// GRXWriteable instance for the main thread, guaranteeing that writesFinishedWithError: is the last -// message sent to it (no matter what messages are sent to the wrapper, in what order, nor from -// which thread). It also guarantees that, if cancelWithError: is called from the main thread (e.g. -// by the app cancelling the writes), no further messages are sent to the writeable except -// writesFinishedWithError:. -// -// TODO(jcanizales): Let the user specify another queue for the writeable callbacks. +/** + * This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a + * GRXWriteable instance for the main thread, guaranteeing that writesFinishedWithError: is the last + * message sent to it (no matter what messages are sent to the wrapper, in what order, nor from + * which thread). It also guarantees that, if cancelWithError: is called from the main thread (e.g. + * by the app cancelling the writes), no further messages are sent to the writeable except + * writesFinishedWithError:. + * + * TODO(jcanizales): Let the user specify another queue for the writeable callbacks. + */ @interface GRXConcurrentWriteable : NSObject -// The GRXWriteable passed is the wrapped writeable. -// The GRXWriteable instance is retained until writesFinishedWithError: is sent to it, and released -// after that. +/** + * The GRXWriteable passed is the wrapped writeable. + * The GRXWriteable instance is retained until writesFinishedWithError: is sent to it, and released + * after that. + */ - (instancetype)initWithWriteable:(id)writeable NS_DESIGNATED_INITIALIZER; -// Enqueues writeValue: to be sent to the writeable in the main thread. -// The passed handler is invoked from the main thread after writeValue: returns. +/** + * Enqueues writeValue: to be sent to the writeable in the main thread. + * The passed handler is invoked from the main thread after writeValue: returns. + */ - (void)enqueueValue:(id)value completionHandler:(void (^)())handler; -// Enqueues writesFinishedWithError:nil to be sent to the writeable in the main thread. After that -// message is sent to the writeable, all other methods of this object are effectively noops. +/** + * Enqueues writesFinishedWithError:nil to be sent to the writeable in the main thread. After that + * message is sent to the writeable, all other methods of this object are effectively noops. + */ - (void)enqueueSuccessfulCompletion; -// If the writeable has not yet received a writesFinishedWithError: message, this will enqueue one -// to be sent to it in the main thread, and cancel all other pending messages to the writeable -// enqueued by this object (both past and future). -// The error argument cannot be nil. +/** + * If the writeable has not yet received a writesFinishedWithError: message, this will enqueue one + * to be sent to it in the main thread, and cancel all other pending messages to the writeable + * enqueued by this object (both past and future). + * The error argument cannot be nil. + */ - (void)cancelWithError:(NSError *)error; -// Cancels all pending messages to the writeable enqueued by this object (both past and future). -// Because the writeable won't receive writesFinishedWithError:, this also releases the writeable. +/** + * Cancels all pending messages to the writeable enqueued by this object (both past and future). + * Because the writeable won't receive writesFinishedWithError:, this also releases the writeable. + */ - (void)cancelSilently; @end diff --git a/src/objective-c/RxLibrary/GRXForwardingWriter.h b/src/objective-c/RxLibrary/GRXForwardingWriter.h index f310832284a..8d45b8ed8d3 100644 --- a/src/objective-c/RxLibrary/GRXForwardingWriter.h +++ b/src/objective-c/RxLibrary/GRXForwardingWriter.h @@ -33,17 +33,19 @@ #import "GRXWriter.h" -// A "proxy" class that simply forwards values, completion, and errors from its input writer to its -// writeable. -// It is useful as a superclass for pipes that act as a transformation of their -// input writer, and for classes that represent objects with input and -// output sequences of values, like an RPC. -// -// Thread-safety: -// All messages sent to this object need to be serialized. When it is started, the writer it wraps -// is started in the same thread. Manual state changes are propagated to the wrapped writer in the -// same thread too. Importantly, all messages the wrapped writer sends to its writeable need to be -// serialized with any message sent to this object. +/** + * A "proxy" class that simply forwards values, completion, and errors from its input writer to its + * writeable. + * It is useful as a superclass for pipes that act as a transformation of their + * input writer, and for classes that represent objects with input and + * output sequences of values, like an RPC. + * + * Thread-safety: + * All messages sent to this object need to be serialized. When it is started, the writer it wraps + * is started in the same thread. Manual state changes are propagated to the wrapped writer in the + * same thread too. Importantly, all messages the wrapped writer sends to its writeable need to be + * serialized with any message sent to this object. + */ @interface GRXForwardingWriter : GRXWriter - (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/RxLibrary/GRXImmediateWriter.h b/src/objective-c/RxLibrary/GRXImmediateWriter.h index 3fcc2594342..e22b056ff56 100644 --- a/src/objective-c/RxLibrary/GRXImmediateWriter.h +++ b/src/objective-c/RxLibrary/GRXImmediateWriter.h @@ -35,46 +35,60 @@ #import "GRXWriter.h" -// Utility to construct GRXWriter instances from values that are immediately available when -// required. -// -// Thread-safety: -// -// An object of this class shouldn't be messaged concurrently by more than one thread. It will start -// messaging the writeable before |startWithWriteable:| returns, in the same thread. That is the -// only place where the writer can be paused or stopped prematurely. -// -// If a paused writer of this class is resumed, it will start messaging the writeable, in the same -// thread, before |setState:| returns. Because the object can't be legally accessed concurrently, -// that's the only place where it can be paused again (or stopped). +/** + * Utility to construct GRXWriter instances from values that are immediately available when + * required. + * + * Thread-safety: + * + * An object of this class shouldn't be messaged concurrently by more than one thread. It will start + * messaging the writeable before |startWithWriteable:| returns, in the same thread. That is the + * only place where the writer can be paused or stopped prematurely. + * + * If a paused writer of this class is resumed, it will start messaging the writeable, in the same + * thread, before |setState:| returns. Because the object can't be legally accessed concurrently, + * that's the only place where it can be paused again (or stopped). + */ @interface GRXImmediateWriter : GRXWriter -// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to -// its writeable. The NSEnumerator is released when it finishes. +/** + * Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to + * its writeable. The NSEnumerator is released when it finishes. + */ + (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator; -// Returns a writer that pushes to its writeable the successive values returned by the passed -// block. When the block first returns nil, it is released. +/** + * Returns a writer that pushes to its writeable the successive values returned by the passed + * block. When the block first returns nil, it is released. + */ + (GRXWriter *)writerWithValueSupplier:(id (^)())block; -// Returns a writer that iterates over the values of the passed container and pushes them to -// its writeable. The container is released when the iteration is over. -// -// Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to -// call one method per element. Because GRXWriteable instances accept values one by one, that speed -// gain doesn't happen here. +/** + * Returns a writer that iterates over the values of the passed container and pushes them to + * its writeable. The container is released when the iteration is over. + * + * Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to + * call one method per element. Because GRXWriteable instances accept values one by one, that speed + * gain doesn't happen here. + */ + (GRXWriter *)writerWithContainer:(id)container; -// Returns a writer that sends the passed value to its writeable and then finishes (releasing the -// value). +/** + * Returns a writer that sends the passed value to its writeable and then finishes (releasing the + * value). + */ + (GRXWriter *)writerWithValue:(id)value; -// Returns a writer that, as part of its start method, sends the passed error to the writeable -// (then releasing the error). +/** + * Returns a writer that, as part of its start method, sends the passed error to the writeable + * (then releasing the error). + */ + (GRXWriter *)writerWithError:(NSError *)error; -// Returns a writer that, as part of its start method, finishes immediately without sending any -// values to its writeable. +/** + * Returns a writer that, as part of its start method, finishes immediately without sending any + * values to its writeable. + */ + (GRXWriter *)emptyWriter; @end diff --git a/src/objective-c/RxLibrary/GRXWriteable.h b/src/objective-c/RxLibrary/GRXWriteable.h index 45613d6dd09..7fe805c6638 100644 --- a/src/objective-c/RxLibrary/GRXWriteable.h +++ b/src/objective-c/RxLibrary/GRXWriteable.h @@ -33,16 +33,20 @@ #import -// A GRXWriteable is an object to which a sequence of values can be sent. The -// sequence finishes with an optional error. +/** + * A GRXWriteable is an object to which a sequence of values can be sent. The + * sequence finishes with an optional error. + */ @protocol GRXWriteable -// Push the next value of the sequence to the receiving object. +/** Push the next value of the sequence to the receiving object. */ - (void)writeValue:(id)value; -// Signal that the sequence is completed, or that an error ocurred. After this -// message is sent to the instance, neither it nor writeValue: may be -// called again. +/** + * Signal that the sequence is completed, or that an error ocurred. After this + * message is sent to the instance, neither it nor writeValue: may be + * called again. + */ - (void)writesFinishedWithError:(NSError *)errorOrNil; @end @@ -51,8 +55,10 @@ typedef void (^GRXCompletionHandler)(NSError *errorOrNil); typedef void (^GRXSingleHandler)(id value, NSError *errorOrNil); typedef void (^GRXEventHandler)(BOOL done, id value, NSError *error); -// Utility to create objects that conform to the GRXWriteable protocol, from -// blocks that handle each of the two methods of the protocol. +/** + * Utility to create objects that conform to the GRXWriteable protocol, from + * blocks that handle each of the two methods of the protocol. + */ @interface GRXWriteable : NSObject + (instancetype)writeableWithSingleHandler:(GRXSingleHandler)handler; diff --git a/src/objective-c/RxLibrary/GRXWriter+Immediate.h b/src/objective-c/RxLibrary/GRXWriter+Immediate.h index b75c0a5a64c..be880151f4f 100644 --- a/src/objective-c/RxLibrary/GRXWriter+Immediate.h +++ b/src/objective-c/RxLibrary/GRXWriter+Immediate.h @@ -35,32 +35,44 @@ @interface GRXWriter (Immediate) -// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to -// its writeable. The NSEnumerator is released when it finishes. +/** + * Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to + * its writeable. The NSEnumerator is released when it finishes. + */ + (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator; -// Returns a writer that pushes to its writeable the successive values returned by the passed -// block. When the block first returns nil, it is released. +/** + * Returns a writer that pushes to its writeable the successive values returned by the passed + * block. When the block first returns nil, it is released. + */ + (instancetype)writerWithValueSupplier:(id (^)())block; -// Returns a writer that iterates over the values of the passed container and pushes them to -// its writeable. The container is released when the iteration is over. -// -// Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to -// call one method per element. Because GRXWriteable instances accept values one by one, that speed -// gain doesn't happen here. +/** + * Returns a writer that iterates over the values of the passed container and pushes them to + * its writeable. The container is released when the iteration is over. + * + * Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to + * call one method per element. Because GRXWriteable instances accept values one by one, that speed + * gain doesn't happen here. + */ + (instancetype)writerWithContainer:(id)container; -// Returns a writer that sends the passed value to its writeable and then finishes (releasing the -// value). +/** + * Returns a writer that sends the passed value to its writeable and then finishes (releasing the + * value). + */ + (instancetype)writerWithValue:(id)value; -// Returns a writer that, as part of its start method, sends the passed error to the writeable -// (then releasing the error). +/** + * Returns a writer that, as part of its start method, sends the passed error to the writeable + * (then releasing the error). + */ + (instancetype)writerWithError:(NSError *)error; -// Returns a writer that, as part of its start method, finishes immediately without sending any -// values to its writeable. +/** + * Returns a writer that, as part of its start method, finishes immediately without sending any + * values to its writeable. + */ + (instancetype)emptyWriter; @end diff --git a/src/objective-c/RxLibrary/GRXWriter+Transformations.h b/src/objective-c/RxLibrary/GRXWriter+Transformations.h index 60c4da37d69..17d61e75410 100644 --- a/src/objective-c/RxLibrary/GRXWriter+Transformations.h +++ b/src/objective-c/RxLibrary/GRXWriter+Transformations.h @@ -35,8 +35,10 @@ @interface GRXWriter (Transformations) -// Returns a writer that wraps the receiver, and has all the values the receiver would write -// transformed by the provided mapping function. +/** + * Returns a writer that wraps the receiver, and has all the values the receiver would write + * transformed by the provided mapping function. + */ - (GRXWriter *)map:(id (^)(id value))map; @end diff --git a/src/objective-c/RxLibrary/GRXWriter.h b/src/objective-c/RxLibrary/GRXWriter.h index b1c994aa382..ff81268446a 100644 --- a/src/objective-c/RxLibrary/GRXWriter.h +++ b/src/objective-c/RxLibrary/GRXWriter.h @@ -35,73 +35,87 @@ #import "GRXWriteable.h" -// States of a writer. +/** States of a writer. */ typedef NS_ENUM(NSInteger, GRXWriterState) { - // The writer has not yet been given a writeable to which it can push its values. To have a writer - // transition to the Started state, send it a startWithWriteable: message. - // - // A writer's state cannot be manually set to this value. + /** + * The writer has not yet been given a writeable to which it can push its values. To have a writer + * transition to the Started state, send it a startWithWriteable: message. + * + * A writer's state cannot be manually set to this value. + */ GRXWriterStateNotStarted, - // The writer might push values to the writeable at any moment. + /** The writer might push values to the writeable at any moment. */ GRXWriterStateStarted, - // The writer is temporarily paused, and won't send any more values to the writeable unless its - // state is set back to Started. The writer might still transition to the Finished state at any - // moment, and is allowed to send writesFinishedWithError: to its writeable. + /** + * The writer is temporarily paused, and won't send any more values to the writeable unless its + * state is set back to Started. The writer might still transition to the Finished state at any + * moment, and is allowed to send writesFinishedWithError: to its writeable. + */ GRXWriterStatePaused, - // The writer has released its writeable and won't interact with it anymore. - // - // One seldomly wants to set a writer's state to this value, as its writeable isn't notified with - // a writesFinishedWithError: message. Instead, sending finishWithError: to the writer will make - // it notify the writeable and then transition to this state. + /** + * The writer has released its writeable and won't interact with it anymore. + * + * One seldomly wants to set a writer's state to this value, as its writeable isn't notified with + * a writesFinishedWithError: message. Instead, sending finishWithError: to the writer will make + * it notify the writeable and then transition to this state. + */ GRXWriterStateFinished }; -// An GRXWriter object can produce, on demand, a sequence of values. The sequence may be produced -// asynchronously, and it may consist of any number of elements, including none or an infinite -// number. -// -// GRXWriter is the active dual of NSEnumerator. The difference between them is thus whether the -// object plays an active or passive role during usage: A user of NSEnumerator pulls values off it, -// and passes the values to a writeable. A user of GRXWriter, though, just gives it a writeable, and -// the GRXWriter instance pushes values to the writeable. This makes this protocol suitable to -// represent a sequence of future values, as well as collections with internal iteration. -// -// An instance of GRXWriter can start producing values after a writeable is passed to it. It can -// also be commanded to finish the sequence immediately (with an optional error). Finally, it can be -// asked to pause, and resumed later. All GRXWriter objects support pausing and early termination. -// -// Thread-safety: -// -// State transitions take immediate effect if the object is used from a single thread. Subclasses -// might offer stronger guarantees. -// -// Unless otherwise indicated by a conforming subclass, no messages should be sent concurrently to a -// GRXWriter. I.e., conforming classes aren't required to be thread-safe. +/** + * An GRXWriter object can produce, on demand, a sequence of values. The sequence may be produced + * asynchronously, and it may consist of any number of elements, including none or an infinite + * number. + * + * GRXWriter is the active dual of NSEnumerator. The difference between them is thus whether the + * object plays an active or passive role during usage: A user of NSEnumerator pulls values off it, + * and passes the values to a writeable. A user of GRXWriter, though, just gives it a writeable, and + * the GRXWriter instance pushes values to the writeable. This makes this protocol suitable to + * represent a sequence of future values, as well as collections with internal iteration. + * + * An instance of GRXWriter can start producing values after a writeable is passed to it. It can + * also be commanded to finish the sequence immediately (with an optional error). Finally, it can be + * asked to pause, and resumed later. All GRXWriter objects support pausing and early termination. + * + * Thread-safety: + * + * State transitions take immediate effect if the object is used from a single thread. Subclasses + * might offer stronger guarantees. + * + * Unless otherwise indicated by a conforming subclass, no messages should be sent concurrently to a + * GRXWriter. I.e., conforming classes aren't required to be thread-safe. + */ @interface GRXWriter : NSObject -// This property can be used to query the current state of the writer, which determines how it might -// currently use its writeable. Some state transitions can be triggered by setting this property to -// the corresponding value, and that's useful for advanced use cases like pausing an writer. For -// more details, see the documentation of the enum further down. +/** + * This property can be used to query the current state of the writer, which determines how it might + * currently use its writeable. Some state transitions can be triggered by setting this property to + * the corresponding value, and that's useful for advanced use cases like pausing an writer. For + * more details, see the documentation of the enum further down. + */ @property(nonatomic) GRXWriterState state; -// Transition to the Started state, and start sending messages to the writeable (a reference to it -// is retained). Messages to the writeable may be sent before the method returns, or they may be -// sent later in the future. See GRXWriteable.h for the different messages a writeable can receive. -// -// If this writer draws its values from an external source (e.g. from the filesystem or from a -// server), calling this method will commonly trigger side effects (like network connections). -// -// This method might only be called on writers in the NotStarted state. +/** + * Transition to the Started state, and start sending messages to the writeable (a reference to it + * is retained). Messages to the writeable may be sent before the method returns, or they may be + * sent later in the future. See GRXWriteable.h for the different messages a writeable can receive. + * + * If this writer draws its values from an external source (e.g. from the filesystem or from a + * server), calling this method will commonly trigger side effects (like network connections). + * + * This method might only be called on writers in the NotStarted state. + */ - (void)startWithWriteable:(id)writeable; -// Send writesFinishedWithError:errorOrNil to the writeable. Then release the reference to it and -// transition to the Finished state. -// -// This method might only be called on writers in the Started or Paused state. +/** + * Send writesFinishedWithError:errorOrNil to the writeable. Then release the reference to it and + * transition to the Finished state. + * + * This method might only be called on writers in the Started or Paused state. + */ - (void)finishWithError:(NSError *)errorOrNil; @end diff --git a/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h b/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h index 400e834c6ae..0622f7067c0 100644 --- a/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h +++ b/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h @@ -35,17 +35,23 @@ @interface NSEnumerator (GRXUtil) -// Returns a NSEnumerator instance that iterates through the elements of the passed container that -// supports fast enumeration. Note that this negates the speed benefits of fast enumeration over -// NSEnumerator. It's only intended for the rare cases when one needs the latter and only has the -// former, e.g. for iteration that needs to be paused and resumed later. +/** + * Returns a NSEnumerator instance that iterates through the elements of the passed container that + * supports fast enumeration. Note that this negates the speed benefits of fast enumeration over + * NSEnumerator. It's only intended for the rare cases when one needs the latter and only has the + * former, e.g. for iteration that needs to be paused and resumed later. + */ + (NSEnumerator *)grx_enumeratorWithContainer:(id)container; -// Returns a NSEnumerator instance that provides a single object before finishing. The value is then -// released. +/** + * Returns a NSEnumerator instance that provides a single object before finishing. The value is then + * released. + */ + (NSEnumerator *)grx_enumeratorWithSingleValue:(id)value; -// Returns a NSEnumerator instance that delegates the invocations of nextObject to the passed block. -// When the block first returns nil, it is released. +/** + * Returns a NSEnumerator instance that delegates the invocations of nextObject to the passed block. + * When the block first returns nil, it is released. + */ + (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block; @end diff --git a/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h b/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h index 34cfc4d8a77..fb50c37863a 100644 --- a/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h +++ b/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h @@ -33,10 +33,14 @@ #import -// Concrete subclass of NSEnumerator that delegates the invocations of nextObject to a block passed -// on initialization. +/** + * Concrete subclass of NSEnumerator that delegates the invocations of nextObject to a block passed + * on initialization. + */ @interface GRXNSBlockEnumerator : NSEnumerator -// The first time the passed block returns nil, the enumeration will end and the block will be -// released. +/** + * The first time the passed block returns nil, the enumeration will end and the block will be + * released. + */ - (instancetype)initWithValueSupplier:(id (^)())block; @end diff --git a/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.h b/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.h index 15650292055..62c27dbc7f3 100644 --- a/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.h +++ b/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.h @@ -33,11 +33,15 @@ #import -// This is a bridge to interact through NSEnumerator's interface with objects that only conform to -// NSFastEnumeration. (There's nothing specifically fast about it - you certainly don't win any -// speed by using this instead of a NSEnumerator provided by your container). +/** + * This is a bridge to interact through NSEnumerator's interface with objects that only conform to + * NSFastEnumeration. (There's nothing specifically fast about it - you certainly don't win any + * speed by using this instead of a NSEnumerator provided by your container). + */ @interface GRXNSFastEnumerator : NSEnumerator -// After the iteration of the container (via the NSFastEnumeration protocol) is over, the container -// is released. If the container is modified during enumeration, an exception is thrown. +/** + * After the iteration of the container (via the NSFastEnumeration protocol) is over, the container + * is released. If the container is modified during enumeration, an exception is thrown. + */ - (instancetype)initWithContainer:(id)container; @end diff --git a/src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.h b/src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.h index 12aa51e2139..24a21a1b22c 100644 --- a/src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.h +++ b/src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.h @@ -33,9 +33,11 @@ #import -// Concrete subclass of NSEnumerator whose instances return a single object before finishing. +/** Concrete subclass of NSEnumerator whose instances return a single object before finishing. */ @interface GRXNSScalarEnumerator : NSEnumerator -// Param value: the single object this instance will produce. After the first invocation of -// nextObject, the value is released. +/** + * Param value: the single object this instance will produce. After the first invocation of + * nextObject, the value is released. + */ - (instancetype)initWithValue:(id)value; @end diff --git a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h index 43b87068647..01a15e2a430 100644 --- a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h +++ b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h @@ -33,7 +33,7 @@ #import "RxLibrary/GRXForwardingWriter.h" -// A "proxy" writer that transforms all the values of its input writer by using a mapping function. +/** A "proxy" writer that transforms all the values of its input writer by using a mapping function. */ @interface GRXMappingWriter : GRXForwardingWriter - (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map NS_DESIGNATED_INITIALIZER; diff --git a/src/objective-c/change-comments.py b/src/objective-c/change-comments.py new file mode 100755 index 00000000000..9aa0e0c9f5a --- /dev/null +++ b/src/objective-c/change-comments.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python2.7 +# 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. + +"""Change comments style of source files from // to /** */""" + +import re +import sys + + +if len(sys.argv) < 2: + print("Please provide at least one source file name as argument.") + sys.exit() + +for file_name in sys.argv[1:]: + + print("Modifying format of {file} comments in place...".format( + file=file_name, + )) + + + # Input + + with open(file_name, "r") as input_file: + lines = input_file.readlines() + + def peek(): + return lines[0] + + def read_line(): + return lines.pop(0) + + def more_input_available(): + return lines + + + # Output + + output_lines = [] + + def write(line): + output_lines.append(line) + + def flush_output(): + with open(file_name, "w") as output_file: + for line in output_lines: + output_file.write(line) + + + # Pattern matching + + comment_regex = r'^(\s*)//\s(.*)$' + + def is_comment(line): + return re.search(comment_regex, line) + + def isnt_comment(line): + return not is_comment(line) + + def next_line(predicate): + return more_input_available() and predicate(peek()) + + + # Transformation + + def indentation_of(line): + match = re.search(comment_regex, line) + return match.group(1) + + def content(line): + match = re.search(comment_regex, line) + return match.group(2) + + def format_as_block(comment_block): + if len(comment_block) == 0: + return [] + + indent = indentation_of(comment_block[0]) + + if len(comment_block) == 1: + return [indent + "/** " + content(comment_block[0]) + " */\n"] + + block = ["/**"] + [" * " + content(line) for line in comment_block] + [" */"] + return [indent + line.rstrip() + "\n" for line in block] + + + # Main algorithm + + while more_input_available(): + while next_line(isnt_comment): + write(read_line()) + + comment_block = [] + # Get all lines in the same comment block. We could restrict the indentation + # to be the same as the first line of the block, but it's probably ok. + while (next_line(is_comment)): + comment_block.append(read_line()) + + for line in format_as_block(comment_block): + write(line) + + flush_output() diff --git a/src/objective-c/format-all-comments.sh b/src/objective-c/format-all-comments.sh new file mode 100644 index 00000000000..e6b6b5a0b49 --- /dev/null +++ b/src/objective-c/format-all-comments.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# 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. + +find . -type f -name "*.h" ! -path "*/Pods/*" ! -path "./generated_libraries/*" ! -path "./examples/*" ! -path "./tests/*" | xargs ./change-comments.py diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 09a55e07045..00c4b8830d3 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -42,9 +42,6 @@ #import #import -// These are a few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall) -// rather than a generated proto library on top of it. - static NSString * const kHostAddress = @"localhost:5050"; static NSString * const kPackage = @"grpc.testing"; static NSString * const kService = @"TestService"; @@ -53,11 +50,10 @@ static ProtoMethod *kInexistentMethod; static ProtoMethod *kEmptyCallMethod; static ProtoMethod *kUnaryCallMethod; -// This is an observer class for testing that responseMetadata is KVO-compliant - +/** Observer class for testing that responseMetadata is KVO-compliant */ @interface PassthroughObserver : NSObject - -- (instancetype) initWithCallback:(void (^)(NSString*, id, NSDictionary*))callback; +- (instancetype) initWithCallback:(void (^)(NSString*, id, NSDictionary*))callback + NS_DESIGNATED_INITIALIZER; - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; @@ -67,23 +63,38 @@ static ProtoMethod *kUnaryCallMethod; void (^_callback)(NSString*, id, NSDictionary*); } +- (instancetype)init { + return [self initWithCallback:nil]; +} + - (instancetype)initWithCallback:(void (^)(NSString *, id, NSDictionary *))callback { - self = [super init]; - if (self) { + if (!callback) { + return nil; + } + if ((self = [super init])) { _callback = callback; } return self; - } -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { _callback(keyPath, object, change); [object removeObserver:self forKeyPath:keyPath]; } @end +# pragma mark Tests + +/** + * A few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall) rather than + * a generated proto library on top of it. Its RPCs are sent to a local cleartext server. + * + * TODO(jcanizales): Run them also against a local SSL server and against a remote server. + */ @interface GRPCClientTests : XCTestCase @end @@ -180,6 +191,7 @@ static ProtoMethod *kUnaryCallMethod; [self waitForExpectationsWithTimeout:8 handler:nil]; } +// TODO(jcanizales): Activate this test against the remote server. - (void)testMetadata { __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."]; diff --git a/src/objective-c/tests/InteropTests.h b/src/objective-c/tests/InteropTests.h index 1045c3d1248..6d54343b135 100644 --- a/src/objective-c/tests/InteropTests.h +++ b/src/objective-c/tests/InteropTests.h @@ -33,11 +33,17 @@ #import -// Implements tests as described here: -// https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md - +/** + * Implements tests as described here: + * https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md + * + * This is an abstract class that needs to be subclassed. See |+host|. + */ @interface InteropTests : XCTestCase -// Returns @"grpc-test.sandbox.google.com". -// Override in a subclass to perform the same tests against a different address. +/** + * Host to send the RPCs to. The base implementation returns nil, which would make all tests to + * fail. + * Override in a subclass to perform these tests against a specific address. + */ + (NSString *)host; @end diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index af58e2bd048..26877b1ae84 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -78,21 +78,20 @@ #pragma mark Tests -static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; - @implementation InteropTests { RMTTestService *_service; } + (NSString *)host { - return kRemoteSSLHost; + return nil; } - (void)setUp { - _service = [RMTTestService serviceWithHost:self.class.host]; + _service = self.class.host ? [RMTTestService serviceWithHost:self.class.host] : nil; } - (void)testEmptyUnaryRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"]; RMTEmpty *request = [RMTEmpty message]; @@ -110,6 +109,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testLargeUnaryRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -132,6 +132,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testClientStreamingRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ClientStreaming"]; RMTStreamingInputCallRequest *request1 = [RMTStreamingInputCallRequest message]; @@ -164,6 +165,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testServerStreamingRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ServerStreaming"]; NSArray *expectedSizes = @[@31415, @9, @2653, @58979]; @@ -200,6 +202,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testPingPongRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"]; NSArray *requests = @[@27182, @8, @1828, @45904]; @@ -243,6 +246,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testEmptyStreamRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"]; [_service fullDuplexCallWithRequestsWriter:[GRXWriter emptyWriter] eventHandler:^(BOOL done, @@ -256,6 +260,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testCancelAfterBeginRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"]; // A buffered pipe to which we never write any value acts as a writer that just hangs. @@ -273,6 +278,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; } - (void)testCancelAfterFirstResponseRPC { + XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterFirstResponse"]; // A buffered pipe to which we write a single value but never close diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m index 2d7d3c4b2c0..56927a8af6d 100644 --- a/src/objective-c/tests/InteropTestsLocalCleartext.m +++ b/src/objective-c/tests/InteropTestsLocalCleartext.m @@ -31,15 +31,13 @@ * */ -// Repeat of the tests in InteropTests.m, but sending the RPCs to a local cleartext server instead -// of the remote SSL one. - #import #import "InteropTests.h" static NSString * const kLocalCleartextHost = @"localhost:5050"; +/** Tests in InteropTests.m, sending the RPCs to a local cleartext server. */ @interface InteropTestsLocalCleartext : InteropTests @end diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index f69f806dcf5..9d7afefbfe3 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -31,15 +31,13 @@ * */ -// Repeat of the tests in InteropTests.m, but sending the RPCs to a local SSL server instead of the -// remote one. - #import #import "InteropTests.h" static NSString * const kLocalSSLHost = @"localhost:5051"; +/** Tests in InteropTests.m, sending the RPCs to a local SSL server. */ @interface InteropTestsLocalSSL : InteropTests @end diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m new file mode 100644 index 00000000000..a67be98431e --- /dev/null +++ b/src/objective-c/tests/InteropTestsRemote.m @@ -0,0 +1,50 @@ +/* + * + * 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 + +#import "InteropTests.h" + +static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; + +/** Tests in InteropTests.m, sending the RPCs to a remote SSL server. */ +@interface InteropTestsRemote : InteropTests +@end + +@implementation InteropTestsRemote + ++ (NSString *)host { + return kRemoteSSLHost; +} + +@end diff --git a/src/objective-c/tests/LocalClearTextTests.m b/src/objective-c/tests/LocalClearTextTests.m deleted file mode 100644 index 976fff55bcc..00000000000 --- a/src/objective-c/tests/LocalClearTextTests.m +++ /dev/null @@ -1,164 +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. - * - */ - -#import -#import - -#import -#import -#import -#import -#import -#import - -// These tests require a gRPC "RouteGuide" sample server to be running locally. You can compile and -// run one by following the instructions here: https://github.com/grpc/grpc/blob/master/examples/cpp/cpptutorial.md#try-it-out -// Be sure to have the C gRPC library installed in your system (for example, by having followed the -// instructions at https://github.com/grpc/homebrew-grpc - -static NSString * const kRouteGuideHost = @"http://localhost:50051"; -static NSString * const kPackage = @"routeguide"; -static NSString * const kService = @"RouteGuide"; - -@interface LocalClearTextTests : XCTestCase -@end - -@implementation LocalClearTextTests - -// This test currently fails: see Issue #1907. -//- (void)testConnectionToLocalServer { -// __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."]; -// -// // This method isn't implemented by the local server. -// GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:kPackage -// interface:kService -// method:@"EmptyCall"]; -// -// GRXWriter *requestsWriter = [GRXWriter writerWithValue:[NSData data]]; -// -// GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost -// method:method -// requestsWriter:requestsWriter]; -// -// id responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { -// XCTFail(@"Received unexpected response: %@", value); -// } completionHandler:^(NSError *errorOrNil) { -// XCTAssertNotNil(errorOrNil, @"Finished without error!"); -// XCTAssertEqual(errorOrNil.code, 12, @"Finished with unexpected error: %@", errorOrNil); -// [expectation fulfill]; -// }]; -// -// [call startWithWriteable:responsesWriteable]; -// -// [self waitForExpectationsWithTimeout:8.0 handler:nil]; -//} - -- (void)testEmptyRPC { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; - __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; - - ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage - service:kService - method:@"RecordRoute"]; - - GRXWriter *requestsWriter = [GRXWriter emptyWriter]; - - GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost - path:method.HTTPPath - requestsWriter:requestsWriter]; - - id responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; - - [call startWithWriteable:responsesWriteable]; - - [self waitForExpectationsWithTimeout:2.0 handler:nil]; -} - -- (void)testSimpleProtoRPC { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Response received."]; - __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; - - ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage - service:kService - method:@"GetFeature"]; - - RGDPoint *point = [RGDPoint message]; - point.latitude = 28E7; - point.longitude = -15E7; - GRXWriter *requestsWriter = [GRXWriter writerWithValue:[point data]]; - - GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost - path:method.HTTPPath - requestsWriter:requestsWriter]; - - id responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - RGDFeature *feature = [RGDFeature parseFromData:value error:NULL]; - XCTAssertEqualObjects(point, feature.location); - XCTAssertNotNil(feature.name, @"Response's name is nil."); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; - - [call startWithWriteable:responsesWriteable]; - - [self waitForExpectationsWithTimeout:2.0 handler:nil]; -} - -- (void)testSimpleProtoRPCUsingGeneratedService { - __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; - - RGDPoint *point = [RGDPoint message]; - point.latitude = 28E7; - point.longitude = -15E7; - - RGDRouteGuide *service = [[RGDRouteGuide alloc] initWithHost:kRouteGuideHost]; - [service getFeatureWithRequest:point handler:^(RGDFeature *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertEqualObjects(point, response.location); - XCTAssertNotNil(response.name, @"Response's name is nil."); - [completion fulfill]; - }]; - - [self waitForExpectationsWithTimeout:2.0 handler:nil]; -} -@end diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 2aa837f764e..2a9b894cf63 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -6,10 +6,26 @@ pod 'gRPC', :path => "../../.." pod 'RemoteTest', :path => "../generated_libraries/RemoteTestClient" pod 'RouteGuide', :path => "../generated_libraries/RouteGuideClient" -link_with 'AllTests' +link_with 'AllTests', + 'RxLibraryUnitTests', + 'InteropTests', + 'InteropTestsLocalSSL', + 'InteropTestsLocalCleartext' target 'Tests' do end target 'AllTests' do end + +target 'RxLibraryUnitTests' do +end + +target 'InteropTestsRemote' do +end + +target 'InteropTestsLocalSSL' do +end + +target 'InteropTestsLocalCleartext' do +end diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 3a1c3d940a9..b0429617c01 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -7,16 +7,33 @@ objects = { /* Begin PBXBuildFile section */ + 036D953EE34B1FD523647ACD /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; }; + 08A8BB02D19A53D902B214B8 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; }; + 50267643BA114A2A724D4FDF /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; }; 6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; }; - 63175DFF1B1B9FAF00027841 /* LocalClearTextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63175DFE1B1B9FAF00027841 /* LocalClearTextTests.m */; }; 63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; - 63423F511B151B77006CF63C /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; }; 635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; }; 635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; }; 63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; }; + 6379CC4D1BE1662A001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; settings = {ASSET_TAGS = (); }; }; + 6379CC4E1BE1662B001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; settings = {ASSET_TAGS = (); }; }; + 6379CC501BE16703001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; settings = {ASSET_TAGS = (); }; }; + 6379CC511BE1683B001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; settings = {ASSET_TAGS = (); }; }; + 6379CC531BE17709001BC0A1 /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; settings = {ASSET_TAGS = (); }; }; + 63DC84181BE15179000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; }; + 63DC841E1BE15180000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; settings = {ASSET_TAGS = (); }; }; + 63DC84281BE15267000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; }; + 63DC842E1BE15278000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; settings = {ASSET_TAGS = (); }; }; + 63DC842F1BE1527D000708E8 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; settings = {ASSET_TAGS = (); }; }; + 63DC84391BE15294000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; }; + 63DC84481BE152B5000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; }; + 63DC844E1BE15350000708E8 /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; settings = {ASSET_TAGS = (); }; }; + 63DC844F1BE15353000708E8 /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; settings = {ASSET_TAGS = (); }; }; + 63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; settings = {ASSET_TAGS = (); }; }; 63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; }; 63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; 7D8A186224D39101F90230F6 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; }; + DCFAE001609CCBFE69DFA6A1 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -27,6 +44,34 @@ remoteGlobalIDString = 635697C61B14FC11007A7283; remoteInfo = Tests; }; + 63DC84191BE15179000708E8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; + 63DC84291BE15267000708E8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; + 63DC843A1BE15294000708E8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; + 63DC84491BE152B5000708E8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -45,7 +90,6 @@ 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GRPCClientTests.m; sourceTree = ""; }; - 63175DFE1B1B9FAF00027841 /* LocalClearTextTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalClearTextTests.m; sourceTree = ""; }; 63423F441B150A5F006CF63C /* AllTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AllTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = ""; }; 635697C71B14FC11007A7283 /* libTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTests.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -53,6 +97,11 @@ 635697D81B14FC11007A7283 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTests.m; sourceTree = ""; }; 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalCleartext.m; sourceTree = ""; }; + 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemote.m; sourceTree = ""; }; + 63DC84131BE15179000708E8 /* RxLibraryUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxLibraryUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemote.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalSSL.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalCleartext.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = ""; }; 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = ""; }; 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = ""; }; @@ -76,6 +125,42 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 63DC84101BE15179000708E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC84181BE15179000708E8 /* libTests.a in Frameworks */, + 036D953EE34B1FD523647ACD /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84201BE15267000708E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC84281BE15267000708E8 /* libTests.a in Frameworks */, + DCFAE001609CCBFE69DFA6A1 /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84311BE15294000708E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC84391BE15294000708E8 /* libTests.a in Frameworks */, + 08A8BB02D19A53D902B214B8 /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84401BE152B5000708E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC84481BE152B5000708E8 /* libTests.a in Frameworks */, + 50267643BA114A2A724D4FDF /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -112,6 +197,10 @@ children = ( 635697C71B14FC11007A7283 /* libTests.a */, 63423F441B150A5F006CF63C /* AllTests.xctest */, + 63DC84131BE15179000708E8 /* RxLibraryUnitTests.xctest */, + 63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */, + 63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */, + 63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */, ); name = Products; sourceTree = ""; @@ -122,10 +211,10 @@ 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */, 63E240CC1B6C4D3A005F3B0E /* InteropTests.h */, 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */, + 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */, 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */, 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */, 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */, - 63175DFE1B1B9FAF00027841 /* LocalClearTextTests.m */, 635697CC1B14FC11007A7283 /* Tests.m */, 635697D71B14FC11007A7283 /* Supporting Files */, ); @@ -152,6 +241,7 @@ 63423F411B150A5F006CF63C /* Frameworks */, 63423F421B150A5F006CF63C /* Resources */, A441F71824DCB9D0CA297748 /* Copy Pods Resources */, + 5F14F59509E10C2852014F9E /* Embed Pods Frameworks */, ); buildRules = ( ); @@ -180,6 +270,90 @@ productReference = 635697C71B14FC11007A7283 /* libTests.a */; productType = "com.apple.product-type.library.static"; }; + 63DC84121BE15179000708E8 /* RxLibraryUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 63DC841B1BE15179000708E8 /* Build configuration list for PBXNativeTarget "RxLibraryUnitTests" */; + buildPhases = ( + B2986CEEE8CDD4901C97598B /* Check Pods Manifest.lock */, + 63DC840F1BE15179000708E8 /* Sources */, + 63DC84101BE15179000708E8 /* Frameworks */, + 63DC84111BE15179000708E8 /* Resources */, + 4F5690DC0E6AD6663FE78B8B /* Embed Pods Frameworks */, + C977426A8727267BBAC7D48E /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 63DC841A1BE15179000708E8 /* PBXTargetDependency */, + ); + name = RxLibraryUnitTests; + productName = RxLibraryUnitTests; + productReference = 63DC84131BE15179000708E8 /* RxLibraryUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 63DC84221BE15267000708E8 /* InteropTestsRemote */ = { + isa = PBXNativeTarget; + buildConfigurationList = 63DC842B1BE15267000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsRemote" */; + buildPhases = ( + 4C406327D3907A5E5FBA8AC9 /* Check Pods Manifest.lock */, + 63DC841F1BE15267000708E8 /* Sources */, + 63DC84201BE15267000708E8 /* Frameworks */, + 63DC84211BE15267000708E8 /* Resources */, + 900B6EDD4D16BE7D765C3885 /* Embed Pods Frameworks */, + C2E09DC4BD239F71160F0CC1 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 63DC842A1BE15267000708E8 /* PBXTargetDependency */, + ); + name = InteropTestsRemote; + productName = InteropTests; + productReference = 63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 63DC84331BE15294000708E8 /* InteropTestsLocalSSL */ = { + isa = PBXNativeTarget; + buildConfigurationList = 63DC843C1BE15294000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSL" */; + buildPhases = ( + 5C20DCCB71C3991E6FE78C22 /* Check Pods Manifest.lock */, + 63DC84301BE15294000708E8 /* Sources */, + 63DC84311BE15294000708E8 /* Frameworks */, + 63DC84321BE15294000708E8 /* Resources */, + C591129ACE9F6CC5EE03FCDE /* Embed Pods Frameworks */, + 693DD0B453431D64EA24FD66 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 63DC843B1BE15294000708E8 /* PBXTargetDependency */, + ); + name = InteropTestsLocalSSL; + productName = InteropTestsLocalSSL; + productReference = 63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */ = { + isa = PBXNativeTarget; + buildConfigurationList = 63DC844B1BE152B5000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartext" */; + buildPhases = ( + 7418AC7B3844B29E48D24FC7 /* Check Pods Manifest.lock */, + 63DC843F1BE152B5000708E8 /* Sources */, + 63DC84401BE152B5000708E8 /* Frameworks */, + 63DC84411BE152B5000708E8 /* Resources */, + A8E3AC66DF770B774114A30E /* Embed Pods Frameworks */, + 8AD3130D3C58A0FB32FF2A36 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 63DC844A1BE152B5000708E8 /* PBXTargetDependency */, + ); + name = InteropTestsLocalCleartext; + productName = InteropTestsLocalCleartext; + productReference = 63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -195,6 +369,18 @@ 635697C61B14FC11007A7283 = { CreatedOnToolsVersion = 6.3.1; }; + 63DC84121BE15179000708E8 = { + CreatedOnToolsVersion = 7.0.1; + }; + 63DC84221BE15267000708E8 = { + CreatedOnToolsVersion = 7.0.1; + }; + 63DC84331BE15294000708E8 = { + CreatedOnToolsVersion = 7.0.1; + }; + 63DC84421BE152B5000708E8 = { + CreatedOnToolsVersion = 7.0.1; + }; }; }; buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */; @@ -211,6 +397,10 @@ targets = ( 635697C61B14FC11007A7283 /* Tests */, 63423F431B150A5F006CF63C /* AllTests */, + 63DC84121BE15179000708E8 /* RxLibraryUnitTests */, + 63DC84221BE15267000708E8 /* InteropTestsRemote */, + 63DC84331BE15294000708E8 /* InteropTestsLocalSSL */, + 63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */, ); }; /* End PBXProject section */ @@ -224,9 +414,158 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 63DC84111BE15179000708E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84211BE15267000708E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84321BE15294000708E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6379CC531BE17709001BC0A1 /* TestCertificates.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84411BE152B5000708E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 4C406327D3907A5E5FBA8AC9 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 4F5690DC0E6AD6663FE78B8B /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 5C20DCCB71C3991E6FE78C22 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 5F14F59509E10C2852014F9E /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 693DD0B453431D64EA24FD66 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 7418AC7B3844B29E48D24FC7 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 8AD3130D3C58A0FB32FF2A36 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 900B6EDD4D16BE7D765C3885 /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 914ADDD7106BA9BB8A7E569F /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -257,6 +596,81 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; showEnvVarsInLog = 0; }; + A8E3AC66DF770B774114A30E /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B2986CEEE8CDD4901C97598B /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + C2E09DC4BD239F71160F0CC1 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + C591129ACE9F6CC5EE03FCDE /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C977426A8727267BBAC7D48E /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -265,11 +679,11 @@ buildActionMask = 2147483647; files = ( 63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */, - 63175DFF1B1B9FAF00027841 /* LocalClearTextTests.m in Sources */, - 63423F511B151B77006CF63C /* RxLibraryUnitTests.m in Sources */, + 6379CC511BE1683B001BC0A1 /* InteropTestsRemote.m in Sources */, 63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */, 6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */, 635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */, + 63DC842E1BE15278000708E8 /* RxLibraryUnitTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -281,6 +695,42 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 63DC840F1BE15179000708E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC841E1BE15180000708E8 /* RxLibraryUnitTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC841F1BE15267000708E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC842F1BE1527D000708E8 /* InteropTests.m in Sources */, + 6379CC501BE16703001BC0A1 /* InteropTestsRemote.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC84301BE15294000708E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC844F1BE15353000708E8 /* InteropTestsLocalSSL.m in Sources */, + 6379CC4D1BE1662A001BC0A1 /* InteropTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63DC843F1BE152B5000708E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */, + 63DC844E1BE15350000708E8 /* InteropTestsLocalCleartext.m in Sources */, + 6379CC4E1BE1662B001BC0A1 /* InteropTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -289,6 +739,26 @@ target = 635697C61B14FC11007A7283 /* Tests */; targetProxy = 63423F4B1B150A5F006CF63C /* PBXContainerItemProxy */; }; + 63DC841A1BE15179000708E8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 63DC84191BE15179000708E8 /* PBXContainerItemProxy */; + }; + 63DC842A1BE15267000708E8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 63DC84291BE15267000708E8 /* PBXContainerItemProxy */; + }; + 63DC843B1BE15294000708E8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 63DC843A1BE15294000708E8 /* PBXContainerItemProxy */; + }; + 63DC844A1BE152B5000708E8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 63DC84491BE152B5000708E8 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -418,6 +888,110 @@ }; name = Release; }; + 63DC841C1BE15179000708E8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 63DC841D1BE15179000708E8 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */; + buildSettings = { + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 63DC842C1BE15267000708E8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 63DC842D1BE15267000708E8 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */; + buildSettings = { + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 63DC843D1BE15294000708E8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 63DC843E1BE15294000708E8 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */; + buildSettings = { + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 63DC844C1BE152B5000708E8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 63DC844D1BE152B5000708E8 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */; + buildSettings = { + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -448,6 +1022,42 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 63DC841B1BE15179000708E8 /* Build configuration list for PBXNativeTarget "RxLibraryUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63DC841C1BE15179000708E8 /* Debug */, + 63DC841D1BE15179000708E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 63DC842B1BE15267000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsRemote" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63DC842C1BE15267000708E8 /* Debug */, + 63DC842D1BE15267000708E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 63DC843C1BE15294000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSL" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63DC843D1BE15294000708E8 /* Debug */, + 63DC843E1BE15294000708E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 63DC844B1BE152B5000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartext" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63DC844C1BE152B5000708E8 /* Debug */, + 63DC844D1BE152B5000708E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 635697BF1B14FC11007A7283 /* Project object */; diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme index a7e0ed110ec..e6a052a8ce1 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme @@ -23,10 +23,10 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -44,6 +44,9 @@ + + @@ -62,15 +65,18 @@ ReferencedContainer = "container:Tests.xcodeproj"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme new file mode 100644 index 00000000000..f268da1fb0c --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme new file mode 100644 index 00000000000..186d7208e04 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme new file mode 100644 index 00000000000..3abc1d42e4d --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/php/bin/run_php_cs_fixer.sh b/src/php/bin/run_php_cs_fixer.sh new file mode 100755 index 00000000000..3e11a12bc1f --- /dev/null +++ b/src/php/bin/run_php_cs_fixer.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# 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. + +set -e +command -v php-cs-fixer > /dev/null || { + echo "Cannot find php-cs-fixer. Exiting..." + exit 1 +} +cd $(dirname $0)/.. +php-cs-fixer fix lib/Grpc || true +php-cs-fixer fix tests/generated_code || true +php-cs-fixer fix tests/interop || true +php-cs-fixer fix tests/unit_tests || true diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php index a3c7a9e017a..53849d51fca 100644 --- a/src/php/lib/Grpc/AbstractCall.php +++ b/src/php/lib/Grpc/AbstractCall.php @@ -31,65 +31,79 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + namespace Grpc; -abstract class AbstractCall { +abstract class AbstractCall +{ + protected $call; + protected $deserialize; + protected $metadata; - protected $call; - protected $deserialize; - protected $metadata; + /** + * Create a new Call wrapper object. + * + * @param Channel $channel The channel to communicate on + * @param string $method The method to call on the + * remote server + * @param callback $deserialize A callback function to deserialize + * the response + * @param (optional) long $timeout Timeout in microseconds + */ + public function __construct(Channel $channel, + $method, + $deserialize, + $timeout = false) + { + if ($timeout) { + $now = Timeval::now(); + $delta = new Timeval($timeout); + $deadline = $now->add($delta); + } else { + $deadline = Timeval::infFuture(); + } + $this->call = new Call($channel, $method, $deadline); + $this->deserialize = $deserialize; + $this->metadata = null; + } - /** - * Create a new Call wrapper object. - * @param Channel $channel The channel to communicate on - * @param string $method The method to call on the remote server - * @param callback $deserialize A callback function to deserialize - * the response - * @param (optional) long $timeout Timeout in microseconds - */ - public function __construct(Channel $channel, $method, $deserialize, $timeout = false) { - if ($timeout) { - $now = Timeval::now(); - $delta = new Timeval($timeout); - $deadline = $now->add($delta); - } else { - $deadline = Timeval::infFuture(); + /** + * @return The metadata sent by the server. + */ + public function getMetadata() + { + return $this->metadata; } - $this->call = new Call($channel, $method, $deadline); - $this->deserialize = $deserialize; - $this->metadata = null; - } - /** - * @return The metadata sent by the server. - */ - public function getMetadata() { - return $this->metadata; - } + /** + * @return string The URI of the endpoint. + */ + public function getPeer() + { + return $this->call->getPeer(); + } - /** - * @return string The URI of the endpoint. - */ - public function getPeer() { - return $this->call->getPeer(); - } + /** + * Cancels the call. + */ + public function cancel() + { + $this->call->cancel(); + } - /** - * Cancels the call - */ - public function cancel() { - $this->call->cancel(); - } + /** + * Deserialize a response value to an object. + * + * @param string $value The binary value to deserialize + * + * @return The deserialized value + */ + protected function deserializeResponse($value) + { + if ($value === null) { + return; + } - /** - * Deserialize a response value to an object. - * @param string $value The binary value to deserialize - * @return The deserialized value - */ - protected function deserializeResponse($value) { - if ($value === null) { - return null; + return call_user_func($this->deserialize, $value); } - return call_user_func($this->deserialize, $value); - } } diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php index 56143145980..c26be607ffc 100755 --- a/src/php/lib/Grpc/BaseStub.php +++ b/src/php/lib/Grpc/BaseStub.php @@ -31,255 +31,308 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + namespace Grpc; /** * Base class for generated client stubs. Stub methods are expected to call * _simpleRequest or _streamRequest and return the result. */ -class BaseStub { +class BaseStub +{ + private $hostname; + private $channel; - private $hostname; - private $channel; + // a callback function + private $update_metadata; - // a callback function - private $update_metadata; + /** + * @param $hostname string + * @param $opts array + * - 'update_metadata': (optional) a callback function which takes in a + * metadata array, and returns an updated metadata array + */ + public function __construct($hostname, $opts) + { + $this->hostname = $hostname; + $this->update_metadata = null; + if (isset($opts['update_metadata'])) { + if (is_callable($opts['update_metadata'])) { + $this->update_metadata = $opts['update_metadata']; + } + unset($opts['update_metadata']); + } + $package_config = json_decode( + file_get_contents(dirname(__FILE__).'/../../composer.json'), true); + $opts['grpc.primary_user_agent'] = + 'grpc-php/'.$package_config['version']; + $this->channel = new Channel($hostname, $opts); + } - /** - * @param $hostname string - * @param $opts array - * - 'update_metadata': (optional) a callback function which takes in a - * metadata array, and returns an updated metadata array - */ - public function __construct($hostname, $opts) { - $this->hostname = $hostname; - $this->update_metadata = null; - if (isset($opts['update_metadata'])) { - if (is_callable($opts['update_metadata'])) { - $this->update_metadata = $opts['update_metadata']; - } - unset($opts['update_metadata']); + /** + * @return string The URI of the endpoint. + */ + public function getTarget() + { + return $this->channel->getTarget(); } - $package_config = json_decode( - file_get_contents(dirname(__FILE__) . '/../../composer.json'), true); - $opts['grpc.primary_user_agent'] = - 'grpc-php/' . $package_config['version']; - $this->channel = new Channel($hostname, $opts); - } - /** - * @return string The URI of the endpoint. - */ - public function getTarget() { - return $this->channel->getTarget(); - } + /** + * @param $try_to_connect bool + * + * @return int The grpc connectivity state + */ + public function getConnectivityState($try_to_connect = false) + { + return $this->channel->getConnectivityState($try_to_connect); + } - /** - * @param $try_to_connect bool - * @return int The grpc connectivity state - */ - public function getConnectivityState($try_to_connect = false) { - return $this->channel->getConnectivityState($try_to_connect); - } + /** + * @param $timeout in microseconds + * + * @return bool true if channel is ready + * @throw Exception if channel is in FATAL_ERROR state + */ + public function waitForReady($timeout) + { + $new_state = $this->getConnectivityState(true); + if ($this->_checkConnectivityState($new_state)) { + return true; + } - /** - * @param $timeout in microseconds - * @return bool true if channel is ready - * @throw Exception if channel is in FATAL_ERROR state - */ - public function waitForReady($timeout) { - $new_state = $this->getConnectivityState(true); - if ($this->_checkConnectivityState($new_state)) { - return true; - } + $now = Timeval::now(); + $delta = new Timeval($timeout); + $deadline = $now->add($delta); - $now = Timeval::now(); - $delta = new Timeval($timeout); - $deadline = $now->add($delta); + while ($this->channel->watchConnectivityState($new_state, $deadline)) { + // state has changed before deadline + $new_state = $this->getConnectivityState(); + if ($this->_checkConnectivityState($new_state)) { + return true; + } + } + // deadline has passed + $new_state = $this->getConnectivityState(); - while ($this->channel->watchConnectivityState($new_state, $deadline)) { - // state has changed before deadline - $new_state = $this->getConnectivityState(); - if ($this->_checkConnectivityState($new_state)) { - return true; - } + return $this->_checkConnectivityState($new_state); } - // deadline has passed - $new_state = $this->getConnectivityState(); - return $this->_checkConnectivityState($new_state); - } - private function _checkConnectivityState($new_state) { - if ($new_state == \Grpc\CHANNEL_READY) { - return true; + private function _checkConnectivityState($new_state) + { + if ($new_state == \Grpc\CHANNEL_READY) { + return true; + } + if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) { + throw new \Exception('Failed to connect to server'); + } + + return false; } - if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) { - // @codeCoverageIgnoreStart - throw new \Exception('Failed to connect to server'); - // @codeCoverageIgnoreEnd + + /** + * Close the communication channel associated with this stub. + */ + public function close() + { + $this->channel->close(); } - return false; - } - /** - * Close the communication channel associated with this stub - */ - public function close() { - $this->channel->close(); - } + /** + * constructs the auth uri for the jwt. + */ + private function _get_jwt_aud_uri($method) + { + $last_slash_idx = strrpos($method, '/'); + if ($last_slash_idx === false) { + throw new \InvalidArgumentException( + 'service name must have a slash'); + } + $service_name = substr($method, 0, $last_slash_idx); - /** - * constructs the auth uri for the jwt - */ - private function _get_jwt_aud_uri($method) { - $last_slash_idx = strrpos($method, '/'); - if ($last_slash_idx === false) { - throw new \InvalidArgumentException('service name must have a slash'); + return 'https://'.$this->hostname.$service_name; } - $service_name = substr($method, 0, $last_slash_idx); - return "https://" . $this->hostname . $service_name; - } - /** - * extract $timeout from $metadata - * @param $metadata The metadata map - * @return list($metadata_copy, $timeout) - */ - private function _extract_timeout_from_metadata($metadata) { - $timeout = false; - $metadata_copy = $metadata; - if (isset($metadata['timeout'])) { - $timeout = $metadata['timeout']; - unset($metadata_copy['timeout']); + /** + * extract $timeout from $metadata. + * + * @param $metadata The metadata map + * + * @return list($metadata_copy, $timeout) + */ + private function _extract_timeout_from_metadata($metadata) + { + $timeout = false; + $metadata_copy = $metadata; + if (isset($metadata['timeout'])) { + $timeout = $metadata['timeout']; + unset($metadata_copy['timeout']); + } + + return [$metadata_copy, $timeout]; } - return array($metadata_copy, $timeout); - } - /** - * validate and normalize the metadata array - * @param $metadata The metadata map - * @return $metadata Validated and key-normalized metadata map - * @throw InvalidArgumentException if key contains invalid characters - */ - private function _validate_and_normalize_metadata($metadata) { - $metadata_copy = array(); - foreach ($metadata as $key => $value) { - if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) { - throw new \InvalidArgumentException( - 'Metadata keys must be nonempty strings containing only '. - 'alphanumeric characters, hyphens and underscores'); - } - $metadata_copy[strtolower($key)] = $value; + /** + * validate and normalize the metadata array. + * + * @param $metadata The metadata map + * + * @return $metadata Validated and key-normalized metadata map + * @throw InvalidArgumentException if key contains invalid characters + */ + private function _validate_and_normalize_metadata($metadata) + { + $metadata_copy = []; + foreach ($metadata as $key => $value) { + if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) { + throw new \InvalidArgumentException( + 'Metadata keys must be nonempty strings containing only '. + 'alphanumeric characters, hyphens and underscores'); + } + $metadata_copy[strtolower($key)] = $value; + } + + return $metadata_copy; } - return $metadata_copy; - } - /* This class is intended to be subclassed by generated code, so all functions - begin with "_" to avoid name collisions. */ + /* This class is intended to be subclassed by generated code, so + * all functions begin with "_" to avoid name collisions. */ - /** - * Call a remote method that takes a single argument and has a single output - * - * @param string $method The name of the method to call - * @param $argument The argument to the method - * @param callable $deserialize A function that deserializes the response - * @param array $metadata A metadata map to send to the server - * @return SimpleSurfaceActiveCall The active call object - */ - public function _simpleRequest($method, - $argument, - callable $deserialize, - $metadata = array(), - $options = array()) { - list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata); - $call = new UnaryCall($this->channel, $method, $deserialize, $timeout); - $jwt_aud_uri = $this->_get_jwt_aud_uri($method); - if (is_callable($this->update_metadata)) { - $actual_metadata = call_user_func($this->update_metadata, + /** + * Call a remote method that takes a single argument and has a + * single output. + * + * @param string $method The name of the method to call + * @param $argument The argument to the method + * @param callable $deserialize A function that deserializes the response + * @param array $metadata A metadata map to send to the server + * + * @return SimpleSurfaceActiveCall The active call object + */ + public function _simpleRequest($method, + $argument, + callable $deserialize, + $metadata = [], + $options = []) + { + list($actual_metadata, $timeout) = + $this->_extract_timeout_from_metadata($metadata); + $call = new UnaryCall($this->channel, + $method, + $deserialize, + $timeout); + $jwt_aud_uri = $this->_get_jwt_aud_uri($method); + if (is_callable($this->update_metadata)) { + $actual_metadata = call_user_func($this->update_metadata, $actual_metadata, $jwt_aud_uri); + } + $actual_metadata = $this->_validate_and_normalize_metadata( + $actual_metadata); + $call->start($argument, $actual_metadata, $options); + + return $call; } - $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata); - $call->start($argument, $actual_metadata, $options); - return $call; - } - /** - * Call a remote method that takes a stream of arguments and has a single - * output - * - * @param string $method The name of the method to call - * @param $arguments An array or Traversable of arguments to stream to the - * server - * @param callable $deserialize A function that deserializes the response - * @param array $metadata A metadata map to send to the server - * @return ClientStreamingSurfaceActiveCall The active call object - */ - public function _clientStreamRequest($method, - callable $deserialize, - $metadata = array()) { - list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata); - $call = new ClientStreamingCall($this->channel, $method, $deserialize, $timeout); - $jwt_aud_uri = $this->_get_jwt_aud_uri($method); - if (is_callable($this->update_metadata)) { - $actual_metadata = call_user_func($this->update_metadata, + /** + * Call a remote method that takes a stream of arguments and has a single + * output. + * + * @param string $method The name of the method to call + * @param $arguments An array or Traversable of arguments to stream to the + * server + * @param callable $deserialize A function that deserializes the response + * @param array $metadata A metadata map to send to the server + * + * @return ClientStreamingSurfaceActiveCall The active call object + */ + public function _clientStreamRequest($method, + callable $deserialize, + $metadata = []) + { + list($actual_metadata, $timeout) = + $this->_extract_timeout_from_metadata($metadata); + $call = new ClientStreamingCall($this->channel, + $method, + $deserialize, + $timeout); + $jwt_aud_uri = $this->_get_jwt_aud_uri($method); + if (is_callable($this->update_metadata)) { + $actual_metadata = call_user_func($this->update_metadata, $actual_metadata, $jwt_aud_uri); + } + $actual_metadata = $this->_validate_and_normalize_metadata( + $actual_metadata); + $call->start($actual_metadata); + + return $call; } - $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata); - $call->start($actual_metadata); - return $call; - } - /** - * Call a remote method that takes a single argument and returns a stream of - * responses - * - * @param string $method The name of the method to call - * @param $argument The argument to the method - * @param callable $deserialize A function that deserializes the responses - * @param array $metadata A metadata map to send to the server - * @return ServerStreamingSurfaceActiveCall The active call object - */ - public function _serverStreamRequest($method, - $argument, - callable $deserialize, - $metadata = array(), - $options = array()) { - list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata); - $call = new ServerStreamingCall($this->channel, $method, $deserialize, $timeout); - $jwt_aud_uri = $this->_get_jwt_aud_uri($method); - if (is_callable($this->update_metadata)) { - $actual_metadata = call_user_func($this->update_metadata, + /** + * Call a remote method that takes a single argument and returns a stream of + * responses. + * + * @param string $method The name of the method to call + * @param $argument The argument to the method + * @param callable $deserialize A function that deserializes the responses + * @param array $metadata A metadata map to send to the server + * + * @return ServerStreamingSurfaceActiveCall The active call object + */ + public function _serverStreamRequest($method, + $argument, + callable $deserialize, + $metadata = [], + $options = []) + { + list($actual_metadata, $timeout) = + $this->_extract_timeout_from_metadata($metadata); + $call = new ServerStreamingCall($this->channel, + $method, + $deserialize, + $timeout); + $jwt_aud_uri = $this->_get_jwt_aud_uri($method); + if (is_callable($this->update_metadata)) { + $actual_metadata = call_user_func($this->update_metadata, $actual_metadata, $jwt_aud_uri); + } + $actual_metadata = $this->_validate_and_normalize_metadata( + $actual_metadata); + $call->start($argument, $actual_metadata, $options); + + return $call; } - $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata); - $call->start($argument, $actual_metadata, $options); - return $call; - } - /** - * Call a remote method with messages streaming in both directions - * - * @param string $method The name of the method to call - * @param callable $deserialize A function that deserializes the responses - * @param array $metadata A metadata map to send to the server - * @return BidiStreamingSurfaceActiveCall The active call object - */ - public function _bidiRequest($method, - callable $deserialize, - $metadata = array()) { - list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata); - $call = new BidiStreamingCall($this->channel, $method, $deserialize, $timeout); - $jwt_aud_uri = $this->_get_jwt_aud_uri($method); - if (is_callable($this->update_metadata)) { - $actual_metadata = call_user_func($this->update_metadata, + /** + * Call a remote method with messages streaming in both directions. + * + * @param string $method The name of the method to call + * @param callable $deserialize A function that deserializes the responses + * @param array $metadata A metadata map to send to the server + * + * @return BidiStreamingSurfaceActiveCall The active call object + */ + public function _bidiRequest($method, + callable $deserialize, + $metadata = []) + { + list($actual_metadata, $timeout) = + $this->_extract_timeout_from_metadata($metadata); + $call = new BidiStreamingCall($this->channel, + $method, + $deserialize, + $timeout); + $jwt_aud_uri = $this->_get_jwt_aud_uri($method); + if (is_callable($this->update_metadata)) { + $actual_metadata = call_user_func($this->update_metadata, $actual_metadata, $jwt_aud_uri); + } + $actual_metadata = $this->_validate_and_normalize_metadata( + $actual_metadata); + $call->start($actual_metadata); + + return $call; } - $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata); - $call->start($actual_metadata); - return $call; - } } diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php index c432fd52d8d..bf813c12e76 100644 --- a/src/php/lib/Grpc/BidiStreamingCall.php +++ b/src/php/lib/Grpc/BidiStreamingCall.php @@ -31,68 +31,87 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + namespace Grpc; /** * Represents an active call that allows for sending and recieving messages in * streams in any order. */ -class BidiStreamingCall extends AbstractCall { - /** - * Start the call - * @param array $metadata Metadata to send with the call, if applicable - */ - public function start($metadata = array()) { - $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]); - } +class BidiStreamingCall extends AbstractCall +{ + /** + * Start the call. + * + * @param array $metadata Metadata to send with the call, if applicable + */ + public function start($metadata = []) + { + $this->call->startBatch([ + OP_SEND_INITIAL_METADATA => $metadata, + ]); + } + + /** + * Reads the next value from the server. + * + * @return The next value from the server, or null if there is none + */ + public function read() + { + $batch = [OP_RECV_MESSAGE => true]; + if ($this->metadata === null) { + $batch[OP_RECV_INITIAL_METADATA] = true; + } + $read_event = $this->call->startBatch($batch); + if ($this->metadata === null) { + $this->metadata = $read_event->metadata; + } - /** - * Reads the next value from the server. - * @return The next value from the server, or null if there is none - */ - public function read() { - $batch = [OP_RECV_MESSAGE => true]; - if ($this->metadata === null) { - $batch[OP_RECV_INITIAL_METADATA] = true; + return $this->deserializeResponse($read_event->message); } - $read_event = $this->call->startBatch($batch); - if ($this->metadata === null) { - $this->metadata = $read_event->metadata; + + /** + * Write a single message to the server. This cannot be called after + * writesDone is called. + * + * @param ByteBuffer $data The data to write + * @param array $options an array of options, possible keys: + * 'flags' => a number + */ + public function write($data, $options = []) + { + $message_array = ['message' => $data->serialize()]; + if (isset($options['flags'])) { + $message_array['flags'] = $options['flags']; + } + $this->call->startBatch([ + OP_SEND_MESSAGE => $message_array, + ]); } - return $this->deserializeResponse($read_event->message); - } - /** - * Write a single message to the server. This cannot be called after - * writesDone is called. - * @param ByteBuffer $data The data to write - * @param array $options an array of options, possible keys: - * 'flags' => a number - */ - public function write($data, $options = array()) { - $message_array = ['message' => $data->serialize()]; - if (isset($options['flags'])) { - $message_array['flags'] = $options['flags']; + /** + * Indicate that no more writes will be sent. + */ + public function writesDone() + { + $this->call->startBatch([ + OP_SEND_CLOSE_FROM_CLIENT => true, + ]); } - $this->call->startBatch([OP_SEND_MESSAGE => $message_array]); - } - /** - * Indicate that no more writes will be sent. - */ - public function writesDone() { - $this->call->startBatch([OP_SEND_CLOSE_FROM_CLIENT => true]); - } + /** + * Wait for the server to send the status, and return it. + * + * @return object The status object, with integer $code, string $details, + * and array $metadata members + */ + public function getStatus() + { + $status_event = $this->call->startBatch([ + OP_RECV_STATUS_ON_CLIENT => true, + ]); - /** - * Wait for the server to send the status, and return it. - * @return object The status object, with integer $code, string $details, - * and array $metadata members - */ - public function getStatus() { - $status_event = $this->call->startBatch([ - OP_RECV_STATUS_ON_CLIENT => true - ]); - return $status_event->status; - } -} \ No newline at end of file + return $status_event->status; + } +} diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php index b96c17e751d..500cfe0d7a0 100644 --- a/src/php/lib/Grpc/ClientStreamingCall.php +++ b/src/php/lib/Grpc/ClientStreamingCall.php @@ -31,47 +31,61 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + namespace Grpc; /** * Represents an active call that sends a stream of messages and then gets a * single response. */ -class ClientStreamingCall extends AbstractCall { - /** - * Start the call. - * @param array $metadata Metadata to send with the call, if applicable - */ - public function start($metadata = array()) { - $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]); - } +class ClientStreamingCall extends AbstractCall +{ + /** + * Start the call. + * + * @param array $metadata Metadata to send with the call, if applicable + */ + public function start($metadata = []) + { + $this->call->startBatch([ + OP_SEND_INITIAL_METADATA => $metadata, + ]); + } - /** - * Write a single message to the server. This cannot be called after - * wait is called. - * @param ByteBuffer $data The data to write - * @param array $options an array of options, possible keys: - * 'flags' => a number - */ - public function write($data, $options = array()) { - $message_array = ['message' => $data->serialize()]; - if (isset($options['flags'])) { - $message_array['flags'] = $options['flags']; + /** + * Write a single message to the server. This cannot be called after + * wait is called. + * + * @param ByteBuffer $data The data to write + * @param array $options an array of options, possible keys: + * 'flags' => a number + */ + public function write($data, $options = []) + { + $message_array = ['message' => $data->serialize()]; + if (isset($options['flags'])) { + $message_array['flags'] = $options['flags']; + } + $this->call->startBatch([ + OP_SEND_MESSAGE => $message_array, + ]); } - $this->call->startBatch([OP_SEND_MESSAGE => $message_array]); - } - /** - * Wait for the server to respond with data and a status - * @return [response data, status] - */ - public function wait() { - $event = $this->call->startBatch([ - OP_SEND_CLOSE_FROM_CLIENT => true, - OP_RECV_INITIAL_METADATA => true, - OP_RECV_MESSAGE => true, - OP_RECV_STATUS_ON_CLIENT => true]); - $this->metadata = $event->metadata; - return array($this->deserializeResponse($event->message), $event->status); - } -} \ No newline at end of file + /** + * Wait for the server to respond with data and a status. + * + * @return [response data, status] + */ + public function wait() + { + $event = $this->call->startBatch([ + OP_SEND_CLOSE_FROM_CLIENT => true, + OP_RECV_INITIAL_METADATA => true, + OP_RECV_MESSAGE => true, + OP_RECV_STATUS_ON_CLIENT => true, + ]); + $this->metadata = $event->metadata; + + return [$this->deserializeResponse($event->message), $event->status]; + } +} diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php index a93c1a5d5e0..da48523717e 100644 --- a/src/php/lib/Grpc/ServerStreamingCall.php +++ b/src/php/lib/Grpc/ServerStreamingCall.php @@ -31,53 +31,66 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + namespace Grpc; /** * Represents an active call that sends a single message and then gets a stream - * of reponses + * of reponses. */ -class ServerStreamingCall extends AbstractCall { - /** - * Start the call - * @param $data The data to send - * @param array $metadata Metadata to send with the call, if applicable - * @param array $options an array of options, possible keys: - * 'flags' => a number - */ - public function start($data, $metadata = array(), $options = array()) { - $message_array = ['message' => $data->serialize()]; - if (isset($options['flags'])) { - $message_array['flags'] = $options['flags']; +class ServerStreamingCall extends AbstractCall +{ + /** + * Start the call. + * + * @param $data The data to send + * @param array $metadata Metadata to send with the call, if applicable + * @param array $options an array of options, possible keys: + * 'flags' => a number + */ + public function start($data, $metadata = [], $options = []) + { + $message_array = ['message' => $data->serialize()]; + if (isset($options['flags'])) { + $message_array['flags'] = $options['flags']; + } + $event = $this->call->startBatch([ + OP_SEND_INITIAL_METADATA => $metadata, + OP_RECV_INITIAL_METADATA => true, + OP_SEND_MESSAGE => $message_array, + OP_SEND_CLOSE_FROM_CLIENT => true, + ]); + $this->metadata = $event->metadata; } - $event = $this->call->startBatch([ - OP_SEND_INITIAL_METADATA => $metadata, - OP_RECV_INITIAL_METADATA => true, - OP_SEND_MESSAGE => $message_array, - OP_SEND_CLOSE_FROM_CLIENT => true]); - $this->metadata = $event->metadata; - } - /** - * @return An iterator of response values - */ - public function responses() { - $response = $this->call->startBatch([OP_RECV_MESSAGE => true])->message; - while($response !== null) { - yield $this->deserializeResponse($response); - $response = $this->call->startBatch([OP_RECV_MESSAGE => true])->message; + /** + * @return An iterator of response values + */ + public function responses() + { + $response = $this->call->startBatch([ + OP_RECV_MESSAGE => true, + ])->message; + while ($response !== null) { + yield $this->deserializeResponse($response); + $response = $this->call->startBatch([ + OP_RECV_MESSAGE => true, + ])->message; + } } - } - /** - * Wait for the server to send the status, and return it. - * @return object The status object, with integer $code, string $details, - * and array $metadata members - */ - public function getStatus() { - $status_event = $this->call->startBatch([ - OP_RECV_STATUS_ON_CLIENT => true - ]); - return $status_event->status; - } + /** + * Wait for the server to send the status, and return it. + * + * @return object The status object, with integer $code, string $details, + * and array $metadata members + */ + public function getStatus() + { + $status_event = $this->call->startBatch([ + OP_RECV_STATUS_ON_CLIENT => true, + ]); + + return $status_event->status; + } } diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php index 38af6b1d745..b57903d6d07 100644 --- a/src/php/lib/Grpc/UnaryCall.php +++ b/src/php/lib/Grpc/UnaryCall.php @@ -31,41 +31,50 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + namespace Grpc; /** * Represents an active call that sends a single message and then gets a single * response. */ -class UnaryCall extends AbstractCall { - /** - * Start the call - * @param $data The data to send - * @param array $metadata Metadata to send with the call, if applicable - * @param array $options an array of options, possible keys: - * 'flags' => a number - */ - public function start($data, $metadata = array(), $options = array()) { - $message_array = ['message' => $data->serialize()]; - if (isset($options['flags'])) { - $message_array['flags'] = $options['flags']; +class UnaryCall extends AbstractCall +{ + /** + * Start the call. + * + * @param $data The data to send + * @param array $metadata Metadata to send with the call, if applicable + * @param array $options an array of options, possible keys: + * 'flags' => a number + */ + public function start($data, $metadata = [], $options = []) + { + $message_array = ['message' => $data->serialize()]; + if (isset($options['flags'])) { + $message_array['flags'] = $options['flags']; + } + $event = $this->call->startBatch([ + OP_SEND_INITIAL_METADATA => $metadata, + OP_RECV_INITIAL_METADATA => true, + OP_SEND_MESSAGE => $message_array, + OP_SEND_CLOSE_FROM_CLIENT => true, + ]); + $this->metadata = $event->metadata; } - $event = $this->call->startBatch([ - OP_SEND_INITIAL_METADATA => $metadata, - OP_RECV_INITIAL_METADATA => true, - OP_SEND_MESSAGE => $message_array, - OP_SEND_CLOSE_FROM_CLIENT => true]); - $this->metadata = $event->metadata; - } - /** - * Wait for the server to respond with data and a status - * @return [response data, status] - */ - public function wait() { - $event = $this->call->startBatch([ - OP_RECV_MESSAGE => true, - OP_RECV_STATUS_ON_CLIENT => true]); - return array($this->deserializeResponse($event->message), $event->status); - } + /** + * Wait for the server to respond with data and a status. + * + * @return [response data, status] + */ + public function wait() + { + $event = $this->call->startBatch([ + OP_RECV_MESSAGE => true, + OP_RECV_STATUS_ON_CLIENT => true, + ]); + + return [$this->deserializeResponse($event->message), $event->status]; + } } diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php index 1819e401f6f..4a0bd6a1f1d 100644 --- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php +++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php @@ -31,184 +31,212 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php'); -require_once dirname(__FILE__) . '/math.php'; - -abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { - /* These tests require that a server exporting the math service must be - * running on $GRPC_TEST_HOST */ - protected static $client; - protected static $timeout; - - public function testWaitForNotReady() { - $this->assertFalse(self::$client->waitForReady(1)); - } - - public function testWaitForReady() { - $this->assertTrue(self::$client->waitForReady(250000)); - } - - public function testAlreadyReady() { - $this->assertTrue(self::$client->waitForReady(250000)); - $this->assertTrue(self::$client->waitForReady(100)); - } - - public function testGetTarget() { - $this->assertTrue(is_string(self::$client->getTarget())); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testClose() { - self::$client->close(); - $div_arg = new math\DivArgs(); - $call = self::$client->Div($div_arg); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testInvalidMetadata() { - $div_arg = new math\DivArgs(); - $call = self::$client->Div($div_arg, array(' ' => 'abc123')); - } - - public function testGetCallMetadata() { - $div_arg = new math\DivArgs(); - $call = self::$client->Div($div_arg); - $this->assertTrue(is_array($call->getMetadata())); - } - - public function testTimeout() { - $div_arg = new math\DivArgs(); - $call = self::$client->Div($div_arg, array('timeout' => 100)); - list($response, $status) = $call->wait(); - $this->assertSame(\Grpc\STATUS_DEADLINE_EXCEEDED, $status->code); - } - - public function testCancel() { - $div_arg = new math\DivArgs(); - $call = self::$client->Div($div_arg); - $call->cancel(); - list($response, $status) = $call->wait(); - $this->assertSame(\Grpc\STATUS_CANCELLED, $status->code); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testInvalidMethodName() { - $invalid_client = new DummyInvalidClient('host', array()); - $div_arg = new math\DivArgs(); - $invalid_client->InvalidUnaryCall($div_arg); - } - - public function testWriteFlags() { - $div_arg = new math\DivArgs(); - $div_arg->setDividend(7); - $div_arg->setDivisor(4); - $call = self::$client->Div($div_arg, array(), array('flags' => Grpc\WRITE_NO_COMPRESS)); - $this->assertTrue(is_string($call->getPeer())); - list($response, $status) = $call->wait(); - $this->assertSame(1, $response->getQuotient()); - $this->assertSame(3, $response->getRemainder()); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testWriteFlagsServerStreaming() { - $fib_arg = new math\FibArgs(); - $fib_arg->setLimit(7); - $call = self::$client->Fib($fib_arg, array(), array('flags' => Grpc\WRITE_NO_COMPRESS)); - $result_array = iterator_to_array($call->responses()); - $status = $call->getStatus(); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testWriteFlagsClientStreaming() { - $call = self::$client->Sum(); - $num = new math\Num(); - $num->setNum(1); - $call->write($num, array('flags' => Grpc\WRITE_NO_COMPRESS)); - list($response, $status) = $call->wait(); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testWriteFlagsBidiStreaming() { - $call = self::$client->DivMany(); - $div_arg = new math\DivArgs(); - $div_arg->setDividend(7); - $div_arg->setDivisor(4); - $call->write($div_arg, array('flags' => Grpc\WRITE_NO_COMPRESS)); - $response = $call->read(); - $call->writesDone(); - $status = $call->getStatus(); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testSimpleRequest() { - $div_arg = new math\DivArgs(); - $div_arg->setDividend(7); - $div_arg->setDivisor(4); - $call = self::$client->Div($div_arg); - $this->assertTrue(is_string($call->getPeer())); - list($response, $status) = $call->wait(); - $this->assertSame(1, $response->getQuotient()); - $this->assertSame(3, $response->getRemainder()); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testServerStreaming() { - $fib_arg = new math\FibArgs(); - $fib_arg->setLimit(7); - $call = self::$client->Fib($fib_arg); - $this->assertTrue(is_string($call->getPeer())); - $result_array = iterator_to_array($call->responses()); - $extract_num = function($num){ - return $num->getNum(); - }; - $values = array_map($extract_num, $result_array); - $this->assertSame([1, 1, 2, 3, 5, 8, 13], $values); - $status = $call->getStatus(); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testClientStreaming() { - $call = self::$client->Sum(); - $this->assertTrue(is_string($call->getPeer())); - for ($i = 0; $i < 7; $i++) { - $num = new math\Num(); - $num->setNum($i); - $call->write($num); - } - list($response, $status) = $call->wait(); - $this->assertSame(21, $response->getNum()); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } - - public function testBidiStreaming() { - $call = self::$client->DivMany(); - $this->assertTrue(is_string($call->getPeer())); - for ($i = 0; $i < 7; $i++) { - $div_arg = new math\DivArgs(); - $div_arg->setDividend(2 * $i + 1); - $div_arg->setDivisor(2); - $call->write($div_arg); - $response = $call->read(); - $this->assertSame($i, $response->getQuotient()); - $this->assertSame(1, $response->getRemainder()); - } - $call->writesDone(); - $status = $call->getStatus(); - $this->assertSame(\Grpc\STATUS_OK, $status->code); - } +require_once realpath(dirname(__FILE__).'/../../vendor/autoload.php'); +require_once dirname(__FILE__).'/math.php'; + +abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase +{ + /** + * These tests require that a server exporting the math service must be + * running on $GRPC_TEST_HOST. + */ + protected static $client; + protected static $timeout; + + public function testWaitForNotReady() + { + $this->assertFalse(self::$client->waitForReady(1)); + } + + public function testWaitForReady() + { + $this->assertTrue(self::$client->waitForReady(250000)); + } + + public function testAlreadyReady() + { + $this->assertTrue(self::$client->waitForReady(250000)); + $this->assertTrue(self::$client->waitForReady(100)); + } + + public function testGetTarget() + { + $this->assertTrue(is_string(self::$client->getTarget())); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testClose() + { + self::$client->close(); + $div_arg = new math\DivArgs(); + $call = self::$client->Div($div_arg); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testInvalidMetadata() + { + $div_arg = new math\DivArgs(); + $call = self::$client->Div($div_arg, [' ' => 'abc123']); + } + + public function testGetCallMetadata() + { + $div_arg = new math\DivArgs(); + $call = self::$client->Div($div_arg); + $this->assertTrue(is_array($call->getMetadata())); + } + + public function testTimeout() + { + $div_arg = new math\DivArgs(); + $call = self::$client->Div($div_arg, ['timeout' => 100]); + list($response, $status) = $call->wait(); + $this->assertSame(\Grpc\STATUS_DEADLINE_EXCEEDED, $status->code); + } + + public function testCancel() + { + $div_arg = new math\DivArgs(); + $call = self::$client->Div($div_arg); + $call->cancel(); + list($response, $status) = $call->wait(); + $this->assertSame(\Grpc\STATUS_CANCELLED, $status->code); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testInvalidMethodName() + { + $invalid_client = new DummyInvalidClient('host', []); + $div_arg = new math\DivArgs(); + $invalid_client->InvalidUnaryCall($div_arg); + } + + public function testWriteFlags() + { + $div_arg = new math\DivArgs(); + $div_arg->setDividend(7); + $div_arg->setDivisor(4); + $call = self::$client->Div($div_arg, [], + ['flags' => Grpc\WRITE_NO_COMPRESS]); + $this->assertTrue(is_string($call->getPeer())); + list($response, $status) = $call->wait(); + $this->assertSame(1, $response->getQuotient()); + $this->assertSame(3, $response->getRemainder()); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testWriteFlagsServerStreaming() + { + $fib_arg = new math\FibArgs(); + $fib_arg->setLimit(7); + $call = self::$client->Fib($fib_arg, [], + ['flags' => Grpc\WRITE_NO_COMPRESS]); + $result_array = iterator_to_array($call->responses()); + $status = $call->getStatus(); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testWriteFlagsClientStreaming() + { + $call = self::$client->Sum(); + $num = new math\Num(); + $num->setNum(1); + $call->write($num, ['flags' => Grpc\WRITE_NO_COMPRESS]); + list($response, $status) = $call->wait(); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testWriteFlagsBidiStreaming() + { + $call = self::$client->DivMany(); + $div_arg = new math\DivArgs(); + $div_arg->setDividend(7); + $div_arg->setDivisor(4); + $call->write($div_arg, ['flags' => Grpc\WRITE_NO_COMPRESS]); + $response = $call->read(); + $call->writesDone(); + $status = $call->getStatus(); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testSimpleRequest() + { + $div_arg = new math\DivArgs(); + $div_arg->setDividend(7); + $div_arg->setDivisor(4); + $call = self::$client->Div($div_arg); + $this->assertTrue(is_string($call->getPeer())); + list($response, $status) = $call->wait(); + $this->assertSame(1, $response->getQuotient()); + $this->assertSame(3, $response->getRemainder()); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testServerStreaming() + { + $fib_arg = new math\FibArgs(); + $fib_arg->setLimit(7); + $call = self::$client->Fib($fib_arg); + $this->assertTrue(is_string($call->getPeer())); + $result_array = iterator_to_array($call->responses()); + $extract_num = function ($num) { + return $num->getNum(); + }; + $values = array_map($extract_num, $result_array); + $this->assertSame([1, 1, 2, 3, 5, 8, 13], $values); + $status = $call->getStatus(); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testClientStreaming() + { + $call = self::$client->Sum(); + $this->assertTrue(is_string($call->getPeer())); + for ($i = 0; $i < 7; ++$i) { + $num = new math\Num(); + $num->setNum($i); + $call->write($num); + } + list($response, $status) = $call->wait(); + $this->assertSame(21, $response->getNum()); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } + + public function testBidiStreaming() + { + $call = self::$client->DivMany(); + $this->assertTrue(is_string($call->getPeer())); + for ($i = 0; $i < 7; ++$i) { + $div_arg = new math\DivArgs(); + $div_arg->setDividend(2 * $i + 1); + $div_arg->setDivisor(2); + $call->write($div_arg); + $response = $call->read(); + $this->assertSame($i, $response->getQuotient()); + $this->assertSame(1, $response->getRemainder()); + } + $call->writesDone(); + $status = $call->getStatus(); + $this->assertSame(\Grpc\STATUS_OK, $status->code); + } } -class DummyInvalidClient extends \Grpc\BaseStub { - public function InvalidUnaryCall(\math\DivArgs $argument, - $metadata = array(), - $options = array()) { - return $this->_simpleRequest('invalidMethodName', $argument, - function() {}, $metadata, $options); - } +class DummyInvalidClient extends \Grpc\BaseStub +{ + public function InvalidUnaryCall(\math\DivArgs $argument, + $metadata = [], + $options = []) + { + return $this->_simpleRequest('invalidMethodName', + $argument, + function () {}, + $metadata, + $options); + } } diff --git a/src/php/tests/generated_code/GeneratedCodeTest.php b/src/php/tests/generated_code/GeneratedCodeTest.php index 64bcf45b4a0..7043e8e1d1b 100755 --- a/src/php/tests/generated_code/GeneratedCodeTest.php +++ b/src/php/tests/generated_code/GeneratedCodeTest.php @@ -31,15 +31,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -require_once dirname(__FILE__) . '/AbstractGeneratedCodeTest.php'; +require_once dirname(__FILE__).'/AbstractGeneratedCodeTest.php'; -class GeneratedCodeTest extends AbstractGeneratedCodeTest { - public function setUp() { - self::$client = new math\MathClient( +class GeneratedCodeTest extends AbstractGeneratedCodeTest +{ + public function setUp() + { + self::$client = new math\MathClient( getenv('GRPC_TEST_HOST'), []); - } + } - public static function tearDownAfterClass() { - self::$client->close(); - } + public static function tearDownAfterClass() + { + self::$client->close(); + } } diff --git a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php index 09c09cf3535..5a20e684c73 100644 --- a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php +++ b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php @@ -31,21 +31,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -require_once dirname(__FILE__) . '/AbstractGeneratedCodeTest.php'; +require_once dirname(__FILE__).'/AbstractGeneratedCodeTest.php'; -class GeneratedCodeWithCallbackTest extends AbstractGeneratedCodeTest { - public function setUp() { - self::$client = new math\MathClient( - getenv('GRPC_TEST_HOST'), ['update_metadata' => - function($a_hash, - $client = array()) { - $a_copy = $a_hash; - $a_copy['foo'] = ['bar']; - return $a_copy; - }]); - } +class GeneratedCodeWithCallbackTest extends AbstractGeneratedCodeTest +{ + public function setUp() + { + self::$client = new math\MathClient( + getenv('GRPC_TEST_HOST'), + ['update_metadata' => function ($a_hash, + $client = []) { + $a_copy = $a_hash; + $a_copy['foo'] = ['bar']; - public static function tearDownAfterClass() { - self::$client->close(); - } + return $a_copy; + }]); + } + + public static function tearDownAfterClass() + { + self::$client->close(); + } } diff --git a/src/php/tests/generated_code/math_client.php b/src/php/tests/generated_code/math_client.php index 7bc78287be8..76ccabc0684 100644 --- a/src/php/tests/generated_code/math_client.php +++ b/src/php/tests/generated_code/math_client.php @@ -36,31 +36,32 @@ include 'vendor/autoload.php'; include 'tests/generated_code/math.php'; -function p($line) { - print("$line
\n"); +function p($line) +{ + print("$line
\n"); } -$host = "localhost:50051"; +$host = 'localhost:50051'; p("Connecting to host: $host"); $client = new math\MathClient($host, []); -p("Client class: ".get_class($client)); +p('Client class: '.get_class($client)); p(''); -p("Running unary call test:"); +p('Running unary call test:'); $dividend = 7; $divisor = 4; $div_arg = new math\DivArgs(); $div_arg->setDividend($dividend); $div_arg->setDivisor($divisor); $call = $client->Div($div_arg); -p("Call peer: ".$call->getPeer()); +p('Call peer: '.$call->getPeer()); p("Dividing $dividend by $divisor"); list($response, $status) = $call->wait(); -p("quotient = ".$response->getQuotient()); -p("remainder = ".$response->getRemainder()); +p('quotient = '.$response->getQuotient()); +p('remainder = '.$response->getRemainder()); p(''); -p("Running server streaming test:"); +p('Running server streaming test:'); $limit = 7; $fib_arg = new math\FibArgs(); $fib_arg->setLimit($limit); @@ -68,35 +69,35 @@ $call = $client->Fib($fib_arg); $result_array = iterator_to_array($call->responses()); $result = ''; foreach ($result_array as $num) { - $result .= ' '.$num->getNum(); + $result .= ' '.$num->getNum(); } p("The first $limit Fibonacci numbers are:".$result); p(''); -p("Running client streaming test:"); +p('Running client streaming test:'); $call = $client->Sum(); -for ($i = 0; $i <= $limit; $i++) { - $num = new math\Num(); - $num->setNum($i); - $call->write($num); +for ($i = 0; $i <= $limit; ++$i) { + $num = new math\Num(); + $num->setNum($i); + $call->write($num); } list($response, $status) = $call->wait(); -p(sprintf("The first %d positive integers sum to: %d", +p(sprintf('The first %d positive integers sum to: %d', $limit, $response->getNum())); p(''); -p("Running bidi-streaming test:"); +p('Running bidi-streaming test:'); $call = $client->DivMany(); -for ($i = 0; $i < 7; $i++) { - $div_arg = new math\DivArgs(); - $dividend = 2 * $i + 1; - $divisor = 3; - $div_arg->setDividend($dividend); - $div_arg->setDivisor($divisor); - $call->write($div_arg); - p("client writing: $dividend / $divisor"); - $response = $call->read(); - p(sprintf("server writing: quotient = %d, remainder = %d", +for ($i = 0; $i < 7; ++$i) { + $div_arg = new math\DivArgs(); + $dividend = 2 * $i + 1; + $divisor = 3; + $div_arg->setDividend($dividend); + $div_arg->setDivisor($divisor); + $call->write($div_arg); + p("client writing: $dividend / $divisor"); + $response = $call->read(); + p(sprintf('server writing: quotient = %d, remainder = %d', $response->getQuotient(), $response->getRemainder())); } $call->writesDone(); diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 03ce2ac7001..3019866561e 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -31,7 +31,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php'); +require_once realpath(dirname(__FILE__).'/../../vendor/autoload.php'); require 'empty.php'; require 'messages.php'; require 'test.php'; @@ -41,394 +41,427 @@ use GuzzleHttp\ClientInterface; /** * Assertion function that always exits with an error code if the assertion is - * falsy + * falsy. + * * @param $value Assertion value. Should be true. * @param $error_message Message to display if the assertion is false */ -function hardAssert($value, $error_message) { - if (!$value) { - echo $error_message . "\n"; - exit(1); - } +function hardAssert($value, $error_message) +{ + if (!$value) { + echo $error_message."\n"; + exit(1); + } } /** * Run the empty_unary test. + * * @param $stub Stub object that has service methods */ -function emptyUnary($stub) { - list($result, $status) = $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait(); - hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully'); - hardAssert($result !== null, 'Call completed with a null response'); +function emptyUnary($stub) +{ + list($result, $status) = $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait(); + hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully'); + hardAssert($result !== null, 'Call completed with a null response'); } /** * Run the large_unary test. + * * @param $stub Stub object that has service methods */ -function largeUnary($stub) { - performLargeUnary($stub); +function largeUnary($stub) +{ + performLargeUnary($stub); } /** - * Shared code between large unary test and auth test + * Shared code between large unary test and auth test. + * * @param $stub Stub object that has service methods * @param $fillUsername boolean whether to fill result with username * @param $fillOauthScope boolean whether to fill result with oauth scope */ function performLargeUnary($stub, $fillUsername = false, $fillOauthScope = false, - $metadata = array()) { - $request_len = 271828; - $response_len = 314159; - - $request = new grpc\testing\SimpleRequest(); - $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); - $request->setResponseSize($response_len); - $payload = new grpc\testing\Payload(); - $payload->setType(grpc\testing\PayloadType::COMPRESSABLE); - $payload->setBody(str_repeat("\0", $request_len)); - $request->setPayload($payload); - $request->setFillUsername($fillUsername); - $request->setFillOauthScope($fillOauthScope); - - list($result, $status) = $stub->UnaryCall($request, $metadata)->wait(); - hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully'); - hardAssert($result !== null, 'Call returned a null response'); - $payload = $result->getPayload(); - hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE, + $metadata = []) +{ + $request_len = 271828; + $response_len = 314159; + + $request = new grpc\testing\SimpleRequest(); + $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); + $request->setResponseSize($response_len); + $payload = new grpc\testing\Payload(); + $payload->setType(grpc\testing\PayloadType::COMPRESSABLE); + $payload->setBody(str_repeat("\0", $request_len)); + $request->setPayload($payload); + $request->setFillUsername($fillUsername); + $request->setFillOauthScope($fillOauthScope); + + list($result, $status) = $stub->UnaryCall($request, $metadata)->wait(); + hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully'); + hardAssert($result !== null, 'Call returned a null response'); + $payload = $result->getPayload(); + hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE, 'Payload had the wrong type'); - hardAssert(strlen($payload->getBody()) === $response_len, + hardAssert(strlen($payload->getBody()) === $response_len, 'Payload had the wrong length'); - hardAssert($payload->getBody() === str_repeat("\0", $response_len), + hardAssert($payload->getBody() === str_repeat("\0", $response_len), 'Payload had the wrong content'); - return $result; + + return $result; } /** * Run the service account credentials auth test. + * * @param $stub Stub object that has service methods * @param $args array command line args */ -function serviceAccountCreds($stub, $args) { - if (!array_key_exists('oauth_scope', $args)) { - throw new Exception('Missing oauth scope'); - } - $jsonKey = json_decode( - file_get_contents(getenv(CredentialsLoader::ENV_VAR)), - true); - $result = performLargeUnary($stub, $fillUsername=true, $fillOauthScope=true); - hardAssert($result->getUsername() == $jsonKey['client_email'], +function serviceAccountCreds($stub, $args) +{ + if (!array_key_exists('oauth_scope', $args)) { + throw new Exception('Missing oauth scope'); + } + $jsonKey = json_decode( + file_get_contents(getenv(CredentialsLoader::ENV_VAR)), + true); + $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true); + hardAssert($result->getUsername() == $jsonKey['client_email'], 'invalid email returned'); - hardAssert(strpos($args['oauth_scope'], $result->getOauthScope()) !== false, + hardAssert(strpos($args['oauth_scope'], $result->getOauthScope()) !== false, 'invalid oauth scope returned'); } /** * Run the compute engine credentials auth test. - * Has not been run from gcloud as of 2015-05-05 + * Has not been run from gcloud as of 2015-05-05. + * * @param $stub Stub object that has service methods * @param $args array command line args */ -function computeEngineCreds($stub, $args) { - if (!array_key_exists('oauth_scope', $args)) { - throw new Exception('Missing oauth scope'); - } - if (!array_key_exists('default_service_account', $args)) { - throw new Exception('Missing default_service_account'); - } - $result = performLargeUnary($stub, $fillUsername=true, $fillOauthScope=true); - hardAssert($args['default_service_account'] == $result->getUsername(), +function computeEngineCreds($stub, $args) +{ + if (!array_key_exists('oauth_scope', $args)) { + throw new Exception('Missing oauth scope'); + } + if (!array_key_exists('default_service_account', $args)) { + throw new Exception('Missing default_service_account'); + } + $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true); + hardAssert($args['default_service_account'] == $result->getUsername(), 'invalid email returned'); } /** * Run the jwt token credentials auth test. + * * @param $stub Stub object that has service methods * @param $args array command line args */ -function jwtTokenCreds($stub, $args) { - $jsonKey = json_decode( - file_get_contents(getenv(CredentialsLoader::ENV_VAR)), - true); - $result = performLargeUnary($stub, $fillUsername=true, $fillOauthScope=true); - hardAssert($result->getUsername() == $jsonKey['client_email'], +function jwtTokenCreds($stub, $args) +{ + $jsonKey = json_decode( + file_get_contents(getenv(CredentialsLoader::ENV_VAR)), + true); + $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true); + hardAssert($result->getUsername() == $jsonKey['client_email'], 'invalid email returned'); } /** * Run the oauth2_auth_token auth test. + * * @param $stub Stub object that has service methods * @param $args array command line args */ -function oauth2AuthToken($stub, $args) { - $jsonKey = json_decode( - file_get_contents(getenv(CredentialsLoader::ENV_VAR)), - true); - $result = performLargeUnary($stub, $fillUsername=true, $fillOauthScope=true); - hardAssert($result->getUsername() == $jsonKey['client_email'], +function oauth2AuthToken($stub, $args) +{ + $jsonKey = json_decode( + file_get_contents(getenv(CredentialsLoader::ENV_VAR)), + true); + $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true); + hardAssert($result->getUsername() == $jsonKey['client_email'], 'invalid email returned'); } /** * Run the per_rpc_creds auth test. + * * @param $stub Stub object that has service methods * @param $args array command line args */ -function perRpcCreds($stub, $args) { - $jsonKey = json_decode( - file_get_contents(getenv(CredentialsLoader::ENV_VAR)), - true); - $auth_credentials = ApplicationDefaultCredentials::getCredentials( - $args['oauth_scope'] - ); - $token = $auth_credentials->fetchAuthToken(); - $metadata = array(CredentialsLoader::AUTH_METADATA_KEY => - array(sprintf("%s %s", - $token['token_type'], - $token['access_token']))); - $result = performLargeUnary($stub, $fillUsername=true, $fillOauthScope=true, +function perRpcCreds($stub, $args) +{ + $jsonKey = json_decode( + file_get_contents(getenv(CredentialsLoader::ENV_VAR)), + true); + $auth_credentials = ApplicationDefaultCredentials::getCredentials( + $args['oauth_scope'] + ); + $token = $auth_credentials->fetchAuthToken(); + $metadata = [CredentialsLoader::AUTH_METADATA_KEY => [sprintf('%s %s', + $token['token_type'], + $token['access_token'])]]; + $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true, $metadata); - hardAssert($result->getUsername() == $jsonKey['client_email'], + hardAssert($result->getUsername() == $jsonKey['client_email'], 'invalid email returned'); } /** * Run the client_streaming test. + * * @param $stub Stub object that has service methods */ -function clientStreaming($stub) { - $request_lengths = array(27182, 8, 1828, 45904); - - $requests = array_map( - function($length) { - $request = new grpc\testing\StreamingInputCallRequest(); - $payload = new grpc\testing\Payload(); - $payload->setBody(str_repeat("\0", $length)); - $request->setPayload($payload); - return $request; - }, $request_lengths); - - $call = $stub->StreamingInputCall(); - foreach ($requests as $request) { - $call->write($request); - } - list($result, $status) = $call->wait(); - hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully'); - hardAssert($result->getAggregatedPayloadSize() === 74922, +function clientStreaming($stub) +{ + $request_lengths = [27182, 8, 1828, 45904]; + + $requests = array_map( + function ($length) { + $request = new grpc\testing\StreamingInputCallRequest(); + $payload = new grpc\testing\Payload(); + $payload->setBody(str_repeat("\0", $length)); + $request->setPayload($payload); + + return $request; + }, $request_lengths); + + $call = $stub->StreamingInputCall(); + foreach ($requests as $request) { + $call->write($request); + } + list($result, $status) = $call->wait(); + hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully'); + hardAssert($result->getAggregatedPayloadSize() === 74922, 'aggregated_payload_size was incorrect'); } /** * Run the server_streaming test. + * * @param $stub Stub object that has service methods. */ -function serverStreaming($stub) { - $sizes = array(31415, 9, 2653, 58979); - - $request = new grpc\testing\StreamingOutputCallRequest(); - $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); - foreach($sizes as $size) { - $response_parameters = new grpc\testing\ResponseParameters(); - $response_parameters->setSize($size); - $request->addResponseParameters($response_parameters); - } +function serverStreaming($stub) +{ + $sizes = [31415, 9, 2653, 58979]; - $call = $stub->StreamingOutputCall($request); - $i = 0; - foreach($call->responses() as $value) { - hardAssert($i < 4, 'Too many responses'); - $payload = $value->getPayload(); - hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE, - 'Payload ' . $i . ' had the wrong type'); - hardAssert(strlen($payload->getBody()) === $sizes[$i], - 'Response ' . $i . ' had the wrong length'); - $i += 1; - } - hardAssert($call->getStatus()->code === Grpc\STATUS_OK, + $request = new grpc\testing\StreamingOutputCallRequest(); + $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); + foreach ($sizes as $size) { + $response_parameters = new grpc\testing\ResponseParameters(); + $response_parameters->setSize($size); + $request->addResponseParameters($response_parameters); + } + + $call = $stub->StreamingOutputCall($request); + $i = 0; + foreach ($call->responses() as $value) { + hardAssert($i < 4, 'Too many responses'); + $payload = $value->getPayload(); + hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE, + 'Payload '.$i.' had the wrong type'); + hardAssert(strlen($payload->getBody()) === $sizes[$i], + 'Response '.$i.' had the wrong length'); + $i += 1; + } + hardAssert($call->getStatus()->code === Grpc\STATUS_OK, 'Call did not complete successfully'); } /** * Run the ping_pong test. + * * @param $stub Stub object that has service methods. */ -function pingPong($stub) { - $request_lengths = array(27182, 8, 1828, 45904); - $response_lengths = array(31415, 9, 2653, 58979); - - $call = $stub->FullDuplexCall(); - for($i = 0; $i < 4; $i++) { - $request = new grpc\testing\StreamingOutputCallRequest(); - $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); - $response_parameters = new grpc\testing\ResponseParameters(); - $response_parameters->setSize($response_lengths[$i]); - $request->addResponseParameters($response_parameters); - $payload = new grpc\testing\Payload(); - $payload->setBody(str_repeat("\0", $request_lengths[$i])); - $request->setPayload($payload); - - $call->write($request); - $response = $call->read(); +function pingPong($stub) +{ + $request_lengths = [27182, 8, 1828, 45904]; + $response_lengths = [31415, 9, 2653, 58979]; + + $call = $stub->FullDuplexCall(); + for ($i = 0; $i < 4; ++$i) { + $request = new grpc\testing\StreamingOutputCallRequest(); + $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); + $response_parameters = new grpc\testing\ResponseParameters(); + $response_parameters->setSize($response_lengths[$i]); + $request->addResponseParameters($response_parameters); + $payload = new grpc\testing\Payload(); + $payload->setBody(str_repeat("\0", $request_lengths[$i])); + $request->setPayload($payload); - hardAssert($response !== null, 'Server returned too few responses'); - $payload = $response->getPayload(); - hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE, - 'Payload ' . $i . ' had the wrong type'); - hardAssert(strlen($payload->getBody()) === $response_lengths[$i], - 'Payload ' . $i . ' had the wrong length'); - } - $call->writesDone(); - hardAssert($call->read() === null, 'Server returned too many responses'); - hardAssert($call->getStatus()->code === Grpc\STATUS_OK, + $call->write($request); + $response = $call->read(); + + hardAssert($response !== null, 'Server returned too few responses'); + $payload = $response->getPayload(); + hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE, + 'Payload '.$i.' had the wrong type'); + hardAssert(strlen($payload->getBody()) === $response_lengths[$i], + 'Payload '.$i.' had the wrong length'); + } + $call->writesDone(); + hardAssert($call->read() === null, 'Server returned too many responses'); + hardAssert($call->getStatus()->code === Grpc\STATUS_OK, 'Call did not complete successfully'); } /** * Run the empty_stream test. + * * @param $stub Stub object that has service methods. */ -function emptyStream($stub) { - $call = $stub->FullDuplexCall(); - $call->writesDone(); - hardAssert($call->read() === null, 'Server returned too many responses'); - hardAssert($call->getStatus()->code === Grpc\STATUS_OK, +function emptyStream($stub) +{ + $call = $stub->FullDuplexCall(); + $call->writesDone(); + hardAssert($call->read() === null, 'Server returned too many responses'); + hardAssert($call->getStatus()->code === Grpc\STATUS_OK, 'Call did not complete successfully'); } /** * Run the cancel_after_begin test. + * * @param $stub Stub object that has service methods. */ -function cancelAfterBegin($stub) { - $call = $stub->StreamingInputCall(); - $call->cancel(); - list($result, $status) = $call->wait(); - hardAssert($status->code === Grpc\STATUS_CANCELLED, +function cancelAfterBegin($stub) +{ + $call = $stub->StreamingInputCall(); + $call->cancel(); + list($result, $status) = $call->wait(); + hardAssert($status->code === Grpc\STATUS_CANCELLED, 'Call status was not CANCELLED'); } /** * Run the cancel_after_first_response test. + * * @param $stub Stub object that has service methods. */ -function cancelAfterFirstResponse($stub) { - $call = $stub->FullDuplexCall(); - $request = new grpc\testing\StreamingOutputCallRequest(); - $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); - $response_parameters = new grpc\testing\ResponseParameters(); - $response_parameters->setSize(31415); - $request->addResponseParameters($response_parameters); - $payload = new grpc\testing\Payload(); - $payload->setBody(str_repeat("\0", 27182)); - $request->setPayload($payload); - - $call->write($request); - $response = $call->read(); - - $call->cancel(); - hardAssert($call->getStatus()->code === Grpc\STATUS_CANCELLED, +function cancelAfterFirstResponse($stub) +{ + $call = $stub->FullDuplexCall(); + $request = new grpc\testing\StreamingOutputCallRequest(); + $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); + $response_parameters = new grpc\testing\ResponseParameters(); + $response_parameters->setSize(31415); + $request->addResponseParameters($response_parameters); + $payload = new grpc\testing\Payload(); + $payload->setBody(str_repeat("\0", 27182)); + $request->setPayload($payload); + + $call->write($request); + $response = $call->read(); + + $call->cancel(); + hardAssert($call->getStatus()->code === Grpc\STATUS_CANCELLED, 'Call status was not CANCELLED'); } -function timeoutOnSleepingServer($stub) { - $call = $stub->FullDuplexCall(array('timeout' => 1000)); - $request = new grpc\testing\StreamingOutputCallRequest(); - $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); - $response_parameters = new grpc\testing\ResponseParameters(); - $response_parameters->setSize(8); - $request->addResponseParameters($response_parameters); - $payload = new grpc\testing\Payload(); - $payload->setBody(str_repeat("\0", 9)); - $request->setPayload($payload); - - $call->write($request); - $response = $call->read(); - - hardAssert($call->getStatus()->code === Grpc\STATUS_DEADLINE_EXCEEDED, +function timeoutOnSleepingServer($stub) +{ + $call = $stub->FullDuplexCall(['timeout' => 1000]); + $request = new grpc\testing\StreamingOutputCallRequest(); + $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); + $response_parameters = new grpc\testing\ResponseParameters(); + $response_parameters->setSize(8); + $request->addResponseParameters($response_parameters); + $payload = new grpc\testing\Payload(); + $payload->setBody(str_repeat("\0", 9)); + $request->setPayload($payload); + + $call->write($request); + $response = $call->read(); + + hardAssert($call->getStatus()->code === Grpc\STATUS_DEADLINE_EXCEEDED, 'Call status was not DEADLINE_EXCEEDED'); } -$args = getopt('', array('server_host:', 'server_port:', 'test_case:', - 'use_tls::', 'use_test_ca::', - 'server_host_override:', 'oauth_scope:', - 'default_service_account:')); +$args = getopt('', ['server_host:', 'server_port:', 'test_case:', + 'use_tls::', 'use_test_ca::', + 'server_host_override:', 'oauth_scope:', + 'default_service_account:', ]); if (!array_key_exists('server_host', $args)) { - throw new Exception('Missing argument: --server_host is required'); + throw new Exception('Missing argument: --server_host is required'); } if (!array_key_exists('server_port', $args)) { - throw new Exception('Missing argument: --server_port is required'); + throw new Exception('Missing argument: --server_port is required'); } if (!array_key_exists('test_case', $args)) { - throw new Exception('Missing argument: --test_case is required'); + throw new Exception('Missing argument: --test_case is required'); } if ($args['server_port'] == 443) { - $server_address = $args['server_host']; + $server_address = $args['server_host']; } else { - $server_address = $args['server_host'] . ':' . $args['server_port']; + $server_address = $args['server_host'].':'.$args['server_port']; } $test_case = $args['test_case']; $host_override = 'foo.test.google.fr'; if (array_key_exists('server_host_override', $args)) { - $host_override = $args['server_host_override']; + $host_override = $args['server_host_override']; } $use_tls = false; if (array_key_exists('use_tls', $args) && $args['use_tls'] != 'false') { - $use_tls = true; + $use_tls = true; } $use_test_ca = false; if (array_key_exists('use_test_ca', $args) && $args['use_test_ca'] != 'false') { - $use_test_ca = true; + $use_test_ca = true; } $opts = []; if ($use_tls) { - if ($use_test_ca) { - $ssl_credentials = Grpc\Credentials::createSsl( - file_get_contents(dirname(__FILE__) . '/../data/ca.pem')); - } else { - $ssl_credentials = Grpc\Credentials::createSsl(); - } - $opts['credentials'] = $ssl_credentials; - $opts['grpc.ssl_target_name_override'] = $host_override; + if ($use_test_ca) { + $ssl_credentials = Grpc\Credentials::createSsl( + file_get_contents(dirname(__FILE__).'/../data/ca.pem')); + } else { + $ssl_credentials = Grpc\Credentials::createSsl(); + } + $opts['credentials'] = $ssl_credentials; + $opts['grpc.ssl_target_name_override'] = $host_override; } -if (in_array($test_case, array('service_account_creds', - 'compute_engine_creds', 'jwt_token_creds'))) { - if ($test_case == 'jwt_token_creds') { - $auth_credentials = ApplicationDefaultCredentials::getCredentials(); - } else { - $auth_credentials = ApplicationDefaultCredentials::getCredentials( - $args['oauth_scope'] - ); - } - $opts['update_metadata'] = $auth_credentials->getUpdateMetadataFunc(); +if (in_array($test_case, ['service_account_creds', + 'compute_engine_creds', 'jwt_token_creds', ])) { + if ($test_case == 'jwt_token_creds') { + $auth_credentials = ApplicationDefaultCredentials::getCredentials(); + } else { + $auth_credentials = ApplicationDefaultCredentials::getCredentials( + $args['oauth_scope'] + ); + } + $opts['update_metadata'] = $auth_credentials->getUpdateMetadataFunc(); } if ($test_case == 'oauth2_auth_token') { - $auth_credentials = ApplicationDefaultCredentials::getCredentials( - $args['oauth_scope'] - ); - $token = $auth_credentials->fetchAuthToken(); - $update_metadata = - function($metadata, - $authUri = null, - ClientInterface $client = null) use ($token) { - $metadata_copy = $metadata; - $metadata_copy[CredentialsLoader::AUTH_METADATA_KEY] = - array(sprintf("%s %s", - $token['token_type'], - $token['access_token'])); - return $metadata_copy; - }; - $opts['update_metadata'] = $update_metadata; + $auth_credentials = ApplicationDefaultCredentials::getCredentials( + $args['oauth_scope'] + ); + $token = $auth_credentials->fetchAuthToken(); + $update_metadata = + function ($metadata, + $authUri = null, + ClientInterface $client = null) use ($token) { + $metadata_copy = $metadata; + $metadata_copy[CredentialsLoader::AUTH_METADATA_KEY] = + [sprintf('%s %s', + $token['token_type'], + $token['access_token'])]; + + return $metadata_copy; + }; + $opts['update_metadata'] = $update_metadata; } $stub = new grpc\testing\TestServiceClient($server_address, $opts); @@ -437,49 +470,49 @@ echo "Connecting to $server_address\n"; echo "Running test case $test_case\n"; switch ($test_case) { - case 'empty_unary': - emptyUnary($stub); - break; - case 'large_unary': - largeUnary($stub); - break; - case 'client_streaming': - clientStreaming($stub); - break; - case 'server_streaming': - serverStreaming($stub); - break; - case 'ping_pong': - pingPong($stub); - break; - case 'empty_stream': - emptyStream($stub); - break; - case 'cancel_after_begin': - cancelAfterBegin($stub); - break; - case 'cancel_after_first_response': - cancelAfterFirstResponse($stub); - break; - case 'timeout_on_sleeping_server': - timeoutOnSleepingServer($stub); - break; - case 'service_account_creds': - serviceAccountCreds($stub, $args); - break; - case 'compute_engine_creds': - computeEngineCreds($stub, $args); - break; - case 'jwt_token_creds': - jwtTokenCreds($stub, $args); - break; - case 'oauth2_auth_token': - oauth2AuthToken($stub, $args); - break; - case 'per_rpc_creds': - perRpcCreds($stub, $args); - break; - default: - echo "Unsupported test case $test_case\n"; - exit(1); + case 'empty_unary': + emptyUnary($stub); + break; + case 'large_unary': + largeUnary($stub); + break; + case 'client_streaming': + clientStreaming($stub); + break; + case 'server_streaming': + serverStreaming($stub); + break; + case 'ping_pong': + pingPong($stub); + break; + case 'empty_stream': + emptyStream($stub); + break; + case 'cancel_after_begin': + cancelAfterBegin($stub); + break; + case 'cancel_after_first_response': + cancelAfterFirstResponse($stub); + break; + case 'timeout_on_sleeping_server': + timeoutOnSleepingServer($stub); + break; + case 'service_account_creds': + serviceAccountCreds($stub, $args); + break; + case 'compute_engine_creds': + computeEngineCreds($stub, $args); + break; + case 'jwt_token_creds': + jwtTokenCreds($stub, $args); + break; + case 'oauth2_auth_token': + oauth2AuthToken($stub, $args); + break; + case 'per_rpc_creds': + perRpcCreds($stub, $args); + break; + default: + echo "Unsupported test case $test_case\n"; + exit(1); } diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php index caff15ee110..3b697b50c3b 100755 --- a/src/php/tests/unit_tests/CallTest.php +++ b/src/php/tests/unit_tests/CallTest.php @@ -31,56 +31,64 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -class CallTest extends PHPUnit_Framework_TestCase{ - static $server; - static $port; +class CallTest extends PHPUnit_Framework_TestCase +{ + public static $server; + public static $port; - public static function setUpBeforeClass() { - self::$server = new Grpc\Server([]); - self::$port = self::$server->addHttp2Port('0.0.0.0:0'); - } + public static function setUpBeforeClass() + { + self::$server = new Grpc\Server([]); + self::$port = self::$server->addHttp2Port('0.0.0.0:0'); + } - public function setUp() { - $this->channel = new Grpc\Channel('localhost:' . self::$port, []); - $this->call = new Grpc\Call($this->channel, - '/foo', - Grpc\Timeval::infFuture()); - } + public function setUp() + { + $this->channel = new Grpc\Channel('localhost:'.self::$port, []); + $this->call = new Grpc\Call($this->channel, + '/foo', + Grpc\Timeval::infFuture()); + } - public function testAddEmptyMetadata() { - $batch = [ - Grpc\OP_SEND_INITIAL_METADATA => [] - ]; - $result = $this->call->startBatch($batch); - $this->assertTrue($result->send_metadata); - } + public function testAddEmptyMetadata() + { + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => [], + ]; + $result = $this->call->startBatch($batch); + $this->assertTrue($result->send_metadata); + } - public function testAddSingleMetadata() { - $batch = [ - Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value']] - ]; - $result = $this->call->startBatch($batch); - $this->assertTrue($result->send_metadata); - } + public function testAddSingleMetadata() + { + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value']], + ]; + $result = $this->call->startBatch($batch); + $this->assertTrue($result->send_metadata); + } - public function testAddMultiValueMetadata() { - $batch = [ - Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value1', 'value2']] - ]; - $result = $this->call->startBatch($batch); - $this->assertTrue($result->send_metadata); - } + public function testAddMultiValueMetadata() + { + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value1', 'value2']], + ]; + $result = $this->call->startBatch($batch); + $this->assertTrue($result->send_metadata); + } - public function testAddSingleAndMultiValueMetadata() { - $batch = [ - Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'], - 'key2' => ['value2', 'value3']] - ]; - $result = $this->call->startBatch($batch); - $this->assertTrue($result->send_metadata); - } + public function testAddSingleAndMultiValueMetadata() + { + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'], + 'key2' => ['value2', 'value3'], ], + ]; + $result = $this->call->startBatch($batch); + $this->assertTrue($result->send_metadata); + } - public function testGetPeer() { - $this->assertTrue(is_string($this->call->getPeer())); - } + public function testGetPeer() + { + $this->assertTrue(is_string($this->call->getPeer())); + } } diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php index b65366233ad..5a38262451b 100755 --- a/src/php/tests/unit_tests/EndToEndTest.php +++ b/src/php/tests/unit_tests/EndToEndTest.php @@ -31,217 +31,228 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -class EndToEndTest extends PHPUnit_Framework_TestCase{ - public function setUp() { - $this->server = new Grpc\Server([]); - $this->port = $this->server->addHttp2Port('0.0.0.0:0'); - $this->channel = new Grpc\Channel('localhost:' . $this->port, []); - $this->server->start(); - } - - public function tearDown() { - unset($this->channel); - unset($this->server); - } - - public function testSimpleRequestBody() { - $deadline = Grpc\Timeval::infFuture(); - $status_text = 'xyz'; - $call = new Grpc\Call($this->channel, - 'dummy_method', - $deadline); - - $event = $call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_CLOSE_FROM_CLIENT => true - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_close); - - $event = $this->server->requestCall(); - $this->assertSame('dummy_method', $event->method); - $server_call = $event->call; - - $event = $server_call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_STATUS_FROM_SERVER => [ - 'metadata' => [], - 'code' => Grpc\STATUS_OK, - 'details' => $status_text - ], - Grpc\OP_RECV_CLOSE_ON_SERVER => true - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_status); - $this->assertFalse($event->cancelled); - - $event = $call->startBatch([ - Grpc\OP_RECV_INITIAL_METADATA => true, - Grpc\OP_RECV_STATUS_ON_CLIENT => true - ]); - - $status = $event->status; - $this->assertSame([], $status->metadata); - $this->assertSame(Grpc\STATUS_OK, $status->code); - $this->assertSame($status_text, $status->details); - - unset($call); - unset($server_call); - } - - public function testMessageWriteFlags() { - $deadline = Grpc\Timeval::infFuture(); - $req_text = 'message_write_flags_test'; - $status_text = 'xyz'; - $call = new Grpc\Call($this->channel, - 'dummy_method', - $deadline); - - $event = $call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_MESSAGE => ['message' => $req_text, - 'flags' => Grpc\WRITE_NO_COMPRESS], - Grpc\OP_SEND_CLOSE_FROM_CLIENT => true - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_close); - - $event = $this->server->requestCall(); - $this->assertSame('dummy_method', $event->method); - $server_call = $event->call; - - $event = $server_call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_STATUS_FROM_SERVER => [ - 'metadata' => [], - 'code' => Grpc\STATUS_OK, - 'details' => $status_text - ], - ]); - - $event = $call->startBatch([ - Grpc\OP_RECV_INITIAL_METADATA => true, - Grpc\OP_RECV_STATUS_ON_CLIENT => true - ]); - - $status = $event->status; - $this->assertSame([], $status->metadata); - $this->assertSame(Grpc\STATUS_OK, $status->code); - $this->assertSame($status_text, $status->details); - - unset($call); - unset($server_call); - } - - public function testClientServerFullRequestResponse() { - $deadline = Grpc\Timeval::infFuture(); - $req_text = 'client_server_full_request_response'; - $reply_text = 'reply:client_server_full_request_response'; - $status_text = 'status:client_server_full_response_text'; - - $call = new Grpc\Call($this->channel, - 'dummy_method', - $deadline); - - $event = $call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, - Grpc\OP_SEND_MESSAGE => ['message' => $req_text], - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_close); - $this->assertTrue($event->send_message); - - $event = $this->server->requestCall(); - $this->assertSame('dummy_method', $event->method); - $server_call = $event->call; - - $event = $server_call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], - Grpc\OP_SEND_STATUS_FROM_SERVER => [ - 'metadata' => [], - 'code' => Grpc\STATUS_OK, - 'details' => $status_text - ], - Grpc\OP_RECV_MESSAGE => true, - Grpc\OP_RECV_CLOSE_ON_SERVER => true, - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_status); - $this->assertTrue($event->send_message); - $this->assertFalse($event->cancelled); - $this->assertSame($req_text, $event->message); - - $event = $call->startBatch([ - Grpc\OP_RECV_INITIAL_METADATA => true, - Grpc\OP_RECV_MESSAGE => true, - Grpc\OP_RECV_STATUS_ON_CLIENT => true, - ]); - - $this->assertSame([], $event->metadata); - $this->assertSame($reply_text, $event->message); - $status = $event->status; - $this->assertSame([], $status->metadata); - $this->assertSame(Grpc\STATUS_OK, $status->code); - $this->assertSame($status_text, $status->details); - - unset($call); - unset($server_call); - } - - public function testGetTarget() { - $this->assertTrue(is_string($this->channel->getTarget())); - } - - public function testGetConnectivityState() { - $this->assertTrue($this->channel->getConnectivityState() == Grpc\CHANNEL_IDLE); - } - - public function testWatchConnectivityStateFailed() { - $idle_state = $this->channel->getConnectivityState(); - $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); - - $now = Grpc\Timeval::now(); - $delta = new Grpc\Timeval(500000); // should timeout - $deadline = $now->add($delta); - - $this->assertFalse($this->channel->watchConnectivityState( +class EndToEndTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->server = new Grpc\Server([]); + $this->port = $this->server->addHttp2Port('0.0.0.0:0'); + $this->channel = new Grpc\Channel('localhost:'.$this->port, []); + $this->server->start(); + } + + public function tearDown() + { + unset($this->channel); + unset($this->server); + } + + public function testSimpleRequestBody() + { + $deadline = Grpc\Timeval::infFuture(); + $status_text = 'xyz'; + $call = new Grpc\Call($this->channel, + 'dummy_method', + $deadline); + + $event = $call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + + $event = $this->server->requestCall(); + $this->assertSame('dummy_method', $event->method); + $server_call = $event->call; + + $event = $server_call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text, + ], + Grpc\OP_RECV_CLOSE_ON_SERVER => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertFalse($event->cancelled); + + $event = $call->startBatch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $status = $event->status; + $this->assertSame([], $status->metadata); + $this->assertSame(Grpc\STATUS_OK, $status->code); + $this->assertSame($status_text, $status->details); + + unset($call); + unset($server_call); + } + + public function testMessageWriteFlags() + { + $deadline = Grpc\Timeval::infFuture(); + $req_text = 'message_write_flags_test'; + $status_text = 'xyz'; + $call = new Grpc\Call($this->channel, + 'dummy_method', + $deadline); + + $event = $call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_MESSAGE => ['message' => $req_text, + 'flags' => Grpc\WRITE_NO_COMPRESS, ], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + + $event = $this->server->requestCall(); + $this->assertSame('dummy_method', $event->method); + $server_call = $event->call; + + $event = $server_call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text, + ], + ]); + + $event = $call->startBatch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $status = $event->status; + $this->assertSame([], $status->metadata); + $this->assertSame(Grpc\STATUS_OK, $status->code); + $this->assertSame($status_text, $status->details); + + unset($call); + unset($server_call); + } + + public function testClientServerFullRequestResponse() + { + $deadline = Grpc\Timeval::infFuture(); + $req_text = 'client_server_full_request_response'; + $reply_text = 'reply:client_server_full_request_response'; + $status_text = 'status:client_server_full_response_text'; + + $call = new Grpc\Call($this->channel, + 'dummy_method', + $deadline); + + $event = $call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + Grpc\OP_SEND_MESSAGE => ['message' => $req_text], + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + $this->assertTrue($event->send_message); + + $event = $this->server->requestCall(); + $this->assertSame('dummy_method', $event->method); + $server_call = $event->call; + + $event = $server_call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text, + ], + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_CLOSE_ON_SERVER => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertTrue($event->send_message); + $this->assertFalse($event->cancelled); + $this->assertSame($req_text, $event->message); + + $event = $call->startBatch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $this->assertSame([], $event->metadata); + $this->assertSame($reply_text, $event->message); + $status = $event->status; + $this->assertSame([], $status->metadata); + $this->assertSame(Grpc\STATUS_OK, $status->code); + $this->assertSame($status_text, $status->details); + + unset($call); + unset($server_call); + } + + public function testGetTarget() + { + $this->assertTrue(is_string($this->channel->getTarget())); + } + + public function testGetConnectivityState() + { + $this->assertTrue($this->channel->getConnectivityState() == Grpc\CHANNEL_IDLE); + } + + public function testWatchConnectivityStateFailed() + { + $idle_state = $this->channel->getConnectivityState(); + $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); + + $now = Grpc\Timeval::now(); + $delta = new Grpc\Timeval(500000); // should timeout + $deadline = $now->add($delta); + + $this->assertFalse($this->channel->watchConnectivityState( $idle_state, $deadline)); - } + } - public function testWatchConnectivityStateSuccess() { - $idle_state = $this->channel->getConnectivityState(true); - $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); + public function testWatchConnectivityStateSuccess() + { + $idle_state = $this->channel->getConnectivityState(true); + $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); - $now = Grpc\Timeval::now(); - $delta = new Grpc\Timeval(3000000); // should finish well before - $deadline = $now->add($delta); + $now = Grpc\Timeval::now(); + $delta = new Grpc\Timeval(3000000); // should finish well before + $deadline = $now->add($delta); - $this->assertTrue($this->channel->watchConnectivityState( + $this->assertTrue($this->channel->watchConnectivityState( $idle_state, $deadline)); - $new_state = $this->channel->getConnectivityState(); - $this->assertTrue($idle_state != $new_state); - } + $new_state = $this->channel->getConnectivityState(); + $this->assertTrue($idle_state != $new_state); + } - public function testWatchConnectivityStateDoNothing() { - $idle_state = $this->channel->getConnectivityState(); - $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); + public function testWatchConnectivityStateDoNothing() + { + $idle_state = $this->channel->getConnectivityState(); + $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); - $now = Grpc\Timeval::now(); - $delta = new Grpc\Timeval(100000); - $deadline = $now->add($delta); + $now = Grpc\Timeval::now(); + $delta = new Grpc\Timeval(100000); + $deadline = $now->add($delta); - $this->assertFalse($this->channel->watchConnectivityState( + $this->assertFalse($this->channel->watchConnectivityState( $idle_state, $deadline)); - $new_state = $this->channel->getConnectivityState(); - $this->assertTrue($new_state == Grpc\CHANNEL_IDLE); - } + $new_state = $this->channel->getConnectivityState(); + $this->assertTrue($new_state == Grpc\CHANNEL_IDLE); + } } diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php index d7fca14a0d5..e66bde376c7 100755 --- a/src/php/tests/unit_tests/SecureEndToEndTest.php +++ b/src/php/tests/unit_tests/SecureEndToEndTest.php @@ -31,186 +31,193 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ - public function setUp() { - $credentials = Grpc\Credentials::createSsl( - file_get_contents(dirname(__FILE__) . '/../data/ca.pem')); - $server_credentials = Grpc\ServerCredentials::createSsl( - null, - file_get_contents(dirname(__FILE__) . '/../data/server1.key'), - file_get_contents(dirname(__FILE__) . '/../data/server1.pem')); - $this->server = new Grpc\Server(); - $this->port = $this->server->addSecureHttp2Port('0.0.0.0:0', +class SecureEndToEndTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $credentials = Grpc\Credentials::createSsl( + file_get_contents(dirname(__FILE__).'/../data/ca.pem')); + $server_credentials = Grpc\ServerCredentials::createSsl( + null, + file_get_contents(dirname(__FILE__).'/../data/server1.key'), + file_get_contents(dirname(__FILE__).'/../data/server1.pem')); + $this->server = new Grpc\Server(); + $this->port = $this->server->addSecureHttp2Port('0.0.0.0:0', $server_credentials); - $this->server->start(); - $this->host_override = 'foo.test.google.fr'; - $this->channel = new Grpc\Channel( - 'localhost:' . $this->port, - [ + $this->server->start(); + $this->host_override = 'foo.test.google.fr'; + $this->channel = new Grpc\Channel( + 'localhost:'.$this->port, + [ 'grpc.ssl_target_name_override' => $this->host_override, 'grpc.default_authority' => $this->host_override, - 'credentials' => $credentials - ]); - } - - public function tearDown() { - unset($this->channel); - unset($this->server); - } - - public function testSimpleRequestBody() { - $deadline = Grpc\Timeval::infFuture(); - $status_text = 'xyz'; - $call = new Grpc\Call($this->channel, - 'dummy_method', - $deadline, - $this->host_override); - - $event = $call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_CLOSE_FROM_CLIENT => true - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_close); - - $event = $this->server->requestCall(); - $this->assertSame('dummy_method', $event->method); - $server_call = $event->call; - - $event = $server_call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_STATUS_FROM_SERVER => [ - 'metadata' => [], - 'code' => Grpc\STATUS_OK, - 'details' => $status_text - ], - Grpc\OP_RECV_CLOSE_ON_SERVER => true - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_status); - $this->assertFalse($event->cancelled); - - $event = $call->startBatch([ - Grpc\OP_RECV_INITIAL_METADATA => true, - Grpc\OP_RECV_STATUS_ON_CLIENT => true - ]); - - $this->assertSame([], $event->metadata); - $status = $event->status; - $this->assertSame([], $status->metadata); - $this->assertSame(Grpc\STATUS_OK, $status->code); - $this->assertSame($status_text, $status->details); - - unset($call); - unset($server_call); - } - - public function testMessageWriteFlags() { - $deadline = Grpc\Timeval::infFuture(); - $req_text = 'message_write_flags_test'; - $status_text = 'xyz'; - $call = new Grpc\Call($this->channel, - 'dummy_method', - $deadline, - $this->host_override); - - $event = $call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_MESSAGE => ['message' => $req_text, - 'flags' => Grpc\WRITE_NO_COMPRESS], - Grpc\OP_SEND_CLOSE_FROM_CLIENT => true - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_close); - - $event = $this->server->requestCall(); - $this->assertSame('dummy_method', $event->method); - $server_call = $event->call; - - $event = $server_call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_STATUS_FROM_SERVER => [ - 'metadata' => [], - 'code' => Grpc\STATUS_OK, - 'details' => $status_text - ], - ]); - - $event = $call->startBatch([ - Grpc\OP_RECV_INITIAL_METADATA => true, - Grpc\OP_RECV_STATUS_ON_CLIENT => true - ]); - - $this->assertSame([], $event->metadata); - $status = $event->status; - $this->assertSame([], $status->metadata); - $this->assertSame(Grpc\STATUS_OK, $status->code); - $this->assertSame($status_text, $status->details); - - unset($call); - unset($server_call); - } - - public function testClientServerFullRequestResponse() { - $deadline = Grpc\Timeval::infFuture(); - $req_text = 'client_server_full_request_response'; - $reply_text = 'reply:client_server_full_request_response'; - $status_text = 'status:client_server_full_response_text'; - - $call = new Grpc\Call($this->channel, - 'dummy_method', - $deadline, - $this->host_override); - - $event = $call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, - Grpc\OP_SEND_MESSAGE => ['message' => $req_text] - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_close); - $this->assertTrue($event->send_message); - - $event = $this->server->requestCall(); - $this->assertSame('dummy_method', $event->method); - $server_call = $event->call; - - $event = $server_call->startBatch([ - Grpc\OP_SEND_INITIAL_METADATA => [], - Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], - Grpc\OP_SEND_STATUS_FROM_SERVER => [ - 'metadata' => [], - 'code' => Grpc\STATUS_OK, - 'details' => $status_text - ], - Grpc\OP_RECV_MESSAGE => true, - Grpc\OP_RECV_CLOSE_ON_SERVER => true, - ]); - - $this->assertTrue($event->send_metadata); - $this->assertTrue($event->send_status); - $this->assertTrue($event->send_message); - $this->assertFalse($event->cancelled); - $this->assertSame($req_text, $event->message); - - $event = $call->startBatch([ - Grpc\OP_RECV_INITIAL_METADATA => true, - Grpc\OP_RECV_MESSAGE => true, - Grpc\OP_RECV_STATUS_ON_CLIENT => true, - ]); - - $this->assertSame([], $event->metadata); - $this->assertSame($reply_text, $event->message); - $status = $event->status; - $this->assertSame([], $status->metadata); - $this->assertSame(Grpc\STATUS_OK, $status->code); - $this->assertSame($status_text, $status->details); - - unset($call); - unset($server_call); - } + 'credentials' => $credentials, + ] + ); + } + + public function tearDown() + { + unset($this->channel); + unset($this->server); + } + + public function testSimpleRequestBody() + { + $deadline = Grpc\Timeval::infFuture(); + $status_text = 'xyz'; + $call = new Grpc\Call($this->channel, + 'dummy_method', + $deadline, + $this->host_override); + + $event = $call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + + $event = $this->server->requestCall(); + $this->assertSame('dummy_method', $event->method); + $server_call = $event->call; + + $event = $server_call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text, + ], + Grpc\OP_RECV_CLOSE_ON_SERVER => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertFalse($event->cancelled); + + $event = $call->startBatch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $this->assertSame([], $event->metadata); + $status = $event->status; + $this->assertSame([], $status->metadata); + $this->assertSame(Grpc\STATUS_OK, $status->code); + $this->assertSame($status_text, $status->details); + + unset($call); + unset($server_call); + } + + public function testMessageWriteFlags() + { + $deadline = Grpc\Timeval::infFuture(); + $req_text = 'message_write_flags_test'; + $status_text = 'xyz'; + $call = new Grpc\Call($this->channel, + 'dummy_method', + $deadline, + $this->host_override); + + $event = $call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_MESSAGE => ['message' => $req_text, + 'flags' => Grpc\WRITE_NO_COMPRESS, ], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + + $event = $this->server->requestCall(); + $this->assertSame('dummy_method', $event->method); + $server_call = $event->call; + + $event = $server_call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text, + ], + ]); + + $event = $call->startBatch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $this->assertSame([], $event->metadata); + $status = $event->status; + $this->assertSame([], $status->metadata); + $this->assertSame(Grpc\STATUS_OK, $status->code); + $this->assertSame($status_text, $status->details); + + unset($call); + unset($server_call); + } + + public function testClientServerFullRequestResponse() + { + $deadline = Grpc\Timeval::infFuture(); + $req_text = 'client_server_full_request_response'; + $reply_text = 'reply:client_server_full_request_response'; + $status_text = 'status:client_server_full_response_text'; + + $call = new Grpc\Call($this->channel, + 'dummy_method', + $deadline, + $this->host_override); + + $event = $call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + Grpc\OP_SEND_MESSAGE => ['message' => $req_text], + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + $this->assertTrue($event->send_message); + + $event = $this->server->requestCall(); + $this->assertSame('dummy_method', $event->method); + $server_call = $event->call; + + $event = $server_call->startBatch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text, + ], + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_CLOSE_ON_SERVER => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertTrue($event->send_message); + $this->assertFalse($event->cancelled); + $this->assertSame($req_text, $event->message); + + $event = $call->startBatch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $this->assertSame([], $event->metadata); + $this->assertSame($reply_text, $event->message); + $status = $event->status; + $this->assertSame([], $status->metadata); + $this->assertSame(Grpc\STATUS_OK, $status->code); + $this->assertSame($status_text, $status->details); + + unset($call); + unset($server_call); + } } diff --git a/src/php/tests/unit_tests/TimevalTest.php b/src/php/tests/unit_tests/TimevalTest.php index 7b4925cad60..1d2a8d303e7 100755 --- a/src/php/tests/unit_tests/TimevalTest.php +++ b/src/php/tests/unit_tests/TimevalTest.php @@ -31,56 +31,64 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -class TimevalTest extends PHPUnit_Framework_TestCase{ - public function testCompareSame() { - $zero = Grpc\Timeval::zero(); - $this->assertSame(0, Grpc\Timeval::compare($zero, $zero)); - } +class TimevalTest extends PHPUnit_Framework_TestCase +{ + public function testCompareSame() + { + $zero = Grpc\Timeval::zero(); + $this->assertSame(0, Grpc\Timeval::compare($zero, $zero)); + } - public function testPastIsLessThanZero() { - $zero = Grpc\Timeval::zero(); - $past = Grpc\Timeval::infPast(); - $this->assertLessThan(0, Grpc\Timeval::compare($past, $zero)); - $this->assertGreaterThan(0, Grpc\Timeval::compare($zero, $past)); - } + public function testPastIsLessThanZero() + { + $zero = Grpc\Timeval::zero(); + $past = Grpc\Timeval::infPast(); + $this->assertLessThan(0, Grpc\Timeval::compare($past, $zero)); + $this->assertGreaterThan(0, Grpc\Timeval::compare($zero, $past)); + } - public function testFutureIsGreaterThanZero() { - $zero = Grpc\Timeval::zero(); - $future = Grpc\Timeval::infFuture(); - $this->assertLessThan(0, Grpc\Timeval::compare($zero, $future)); - $this->assertGreaterThan(0, Grpc\Timeval::compare($future, $zero)); - } + public function testFutureIsGreaterThanZero() + { + $zero = Grpc\Timeval::zero(); + $future = Grpc\Timeval::infFuture(); + $this->assertLessThan(0, Grpc\Timeval::compare($zero, $future)); + $this->assertGreaterThan(0, Grpc\Timeval::compare($future, $zero)); + } - /** - * @depends testFutureIsGreaterThanZero - */ - public function testNowIsBetweenZeroAndFuture() { - $zero = Grpc\Timeval::zero(); - $future = Grpc\Timeval::infFuture(); - $now = Grpc\Timeval::now(); - $this->assertLessThan(0, Grpc\Timeval::compare($zero, $now)); - $this->assertLessThan(0, Grpc\Timeval::compare($now, $future)); - } + /** + * @depends testFutureIsGreaterThanZero + */ + public function testNowIsBetweenZeroAndFuture() + { + $zero = Grpc\Timeval::zero(); + $future = Grpc\Timeval::infFuture(); + $now = Grpc\Timeval::now(); + $this->assertLessThan(0, Grpc\Timeval::compare($zero, $now)); + $this->assertLessThan(0, Grpc\Timeval::compare($now, $future)); + } - public function testNowAndAdd() { - $now = Grpc\Timeval::now(); - $delta = new Grpc\Timeval(1000); - $deadline = $now->add($delta); - $this->assertGreaterThan(0, Grpc\Timeval::compare($deadline, $now)); - } + public function testNowAndAdd() + { + $now = Grpc\Timeval::now(); + $delta = new Grpc\Timeval(1000); + $deadline = $now->add($delta); + $this->assertGreaterThan(0, Grpc\Timeval::compare($deadline, $now)); + } - public function testNowAndSubtract() { - $now = Grpc\Timeval::now(); - $delta = new Grpc\Timeval(1000); - $deadline = $now->subtract($delta); - $this->assertLessThan(0, Grpc\Timeval::compare($deadline, $now)); - } + public function testNowAndSubtract() + { + $now = Grpc\Timeval::now(); + $delta = new Grpc\Timeval(1000); + $deadline = $now->subtract($delta); + $this->assertLessThan(0, Grpc\Timeval::compare($deadline, $now)); + } - public function testAddAndSubtract() { - $now = Grpc\Timeval::now(); - $delta = new Grpc\Timeval(1000); - $deadline = $now->add($delta); - $back_to_now = $deadline->subtract($delta); - $this->assertSame(0, Grpc\Timeval::compare($back_to_now, $now)); - } + public function testAddAndSubtract() + { + $now = Grpc\Timeval::now(); + $delta = new Grpc\Timeval(1000); + $deadline = $now->add($delta); + $back_to_now = $deadline->subtract($delta); + $this->assertSame(0, Grpc\Timeval::compare($back_to_now, $now)); + } } diff --git a/src/ruby/README.md b/src/ruby/README.md index e6ffadcaa93..76d9f7663a0 100644 --- a/src/ruby/README.md +++ b/src/ruby/README.md @@ -1,3 +1,4 @@ +[![Gem](https://img.shields.io/gem/v/grpc.svg)](https://rubygems.org/gems/grpc/) gRPC Ruby ========= diff --git a/templates/Makefile.template b/templates/Makefile.template index 115d8136b53..20d14c797f9 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -1851,6 +1851,11 @@ endif % endif % endif + % for src in tgt.src: + % if not proto_re.match(src) and any(proto_re.match(src2) for src2 in tgt.src): + $(OBJDIR)/$(CONFIG)/${os.path.splitext(src)[0]}.o: ${' '.join(proto_to_cc(src2) for src2 in tgt.src if proto_re.match(src2))} + % endif + % endfor ifneq ($(OPENSSL_DEP),) diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template index 3b96fe28857..3885cb337b5 100644 --- a/templates/gRPC.podspec.template +++ b/templates/gRPC.podspec.template @@ -88,8 +88,12 @@ ss.header_mappings_dir = '.' # This isn't officially supported in Cocoapods. We've asked for an alternative: # https://github.com/CocoaPods/CocoaPods/issues/4386 - ss.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC" ' + - '"$(PODS_ROOT)/Headers/Private/gRPC/include"' } + ss.xcconfig = { + 'USE_HEADERMAP' => 'NO', + 'ALWAYS_SEARCH_USER_PATHS' => 'NO', + 'USER_HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC"', + 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC/include"' + } ss.requires_arc = false ss.libraries = 'z' diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c index a9edf381575..3eb6f11bf74 100644 --- a/test/core/client_config/lb_policies_test.c +++ b/test/core/client_config/lb_policies_test.c @@ -211,29 +211,32 @@ static void teardown_servers(servers_fixture *f) { gpr_free(f); } +typedef struct request_data { + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + char *details; + size_t details_capacity; + grpc_status_code status; + grpc_call_details *call_details; +} request_data; + /** Returns connection sequence (server indices), which must be freed */ int *perform_request(servers_fixture *f, grpc_channel *client, - const test_spec *spec) { + request_data *rdata, const test_spec *spec) { grpc_call *c; int s_idx; int *s_valid; gpr_timespec deadline; grpc_op ops[6]; grpc_op *op; - grpc_status_code status; - char *details; - size_t details_capacity; int was_cancelled; - grpc_call_details *call_details; size_t i, iter_num; grpc_event ev; int read_tag; int *connection_sequence; - grpc_metadata_array initial_metadata_recv; - grpc_metadata_array trailing_metadata_recv; s_valid = gpr_malloc(sizeof(int) * f->num_servers); - call_details = gpr_malloc(sizeof(grpc_call_details) * f->num_servers); + rdata->call_details = gpr_malloc(sizeof(grpc_call_details) * f->num_servers); connection_sequence = gpr_malloc(sizeof(int) * spec->num_iters); /* Send a trivial request. */ @@ -241,8 +244,8 @@ int *perform_request(servers_fixture *f, grpc_channel *client, for (iter_num = 0; iter_num < spec->num_iters; iter_num++) { cq_verifier *cqv = cq_verifier_create(f->cq); - details = NULL; - details_capacity = 0; + rdata->details = NULL; + rdata->details_capacity = 0; was_cancelled = 2; for (i = 0; i < f->num_servers; i++) { @@ -255,11 +258,11 @@ int *perform_request(servers_fixture *f, grpc_channel *client, } connection_sequence[iter_num] = -1; - grpc_metadata_array_init(&initial_metadata_recv); - grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&rdata->initial_metadata_recv); + grpc_metadata_array_init(&rdata->trailing_metadata_recv); for (i = 0; i < f->num_servers; i++) { - grpc_call_details_init(&call_details[i]); + grpc_call_details_init(&rdata->call_details[i]); } memset(s_valid, 0, f->num_servers * sizeof(int)); @@ -278,15 +281,15 @@ int *perform_request(servers_fixture *f, grpc_channel *client, op->reserved = NULL; op++; op->op = GRPC_OP_RECV_INITIAL_METADATA; - op->data.recv_initial_metadata = &initial_metadata_recv; + op->data.recv_initial_metadata = &rdata->initial_metadata_recv; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; - op->data.recv_status_on_client.status = &status; - op->data.recv_status_on_client.status_details = &details; - op->data.recv_status_on_client.status_details_capacity = &details_capacity; + op->data.recv_status_on_client.trailing_metadata = &rdata->trailing_metadata_recv; + op->data.recv_status_on_client.status = &rdata->status; + op->data.recv_status_on_client.status_details = &rdata->details; + op->data.recv_status_on_client.status_details_capacity = &rdata->details_capacity; op->flags = 0; op->reserved = NULL; op++; @@ -299,7 +302,7 @@ int *perform_request(servers_fixture *f, grpc_channel *client, if (f->servers[i] != NULL) { GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->servers[i], &f->server_calls[i], - &call_details[i], + &rdata->call_details[i], &f->request_metadata_recv[i], f->cq, f->cq, tag(1000 + (int)i))); } @@ -348,11 +351,12 @@ int *perform_request(servers_fixture *f, grpc_channel *client, cq_expect_completion(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); - GPR_ASSERT(0 == strcmp(details, "xyz")); - GPR_ASSERT(0 == strcmp(call_details[s_idx].method, "/foo")); - GPR_ASSERT(0 == strcmp(call_details[s_idx].host, "foo.test.google.fr")); + GPR_ASSERT(rdata->status == GRPC_STATUS_UNIMPLEMENTED); + GPR_ASSERT(0 == strcmp(rdata->details, "xyz")); + GPR_ASSERT(0 == strcmp(rdata->call_details[s_idx].method, "/foo")); + GPR_ASSERT(0 == strcmp(rdata->call_details[s_idx].host, "foo.test.google.fr")); GPR_ASSERT(was_cancelled == 1); + } else { } for (i = 0; i < f->num_servers; i++) { @@ -361,20 +365,20 @@ int *perform_request(servers_fixture *f, grpc_channel *client, } grpc_metadata_array_destroy(&f->request_metadata_recv[i]); } - grpc_metadata_array_destroy(&initial_metadata_recv); - grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&rdata->initial_metadata_recv); + grpc_metadata_array_destroy(&rdata->trailing_metadata_recv); cq_verifier_destroy(cqv); grpc_call_destroy(c); for (i = 0; i < f->num_servers; i++) { - grpc_call_details_destroy(&call_details[i]); + grpc_call_details_destroy(&rdata->call_details[i]); } - gpr_free(details); + gpr_free(rdata->details); } - gpr_free(call_details); + gpr_free(rdata->call_details); gpr_free(s_valid); return connection_sequence; @@ -436,6 +440,7 @@ void run_spec(const test_spec *spec) { char *client_hostport; char *servers_hostports_str; int *actual_connection_sequence; + request_data rdata; servers_fixture *f = setup_servers("127.0.0.1", spec->num_servers); /* Create client. */ @@ -448,7 +453,7 @@ void run_spec(const test_spec *spec) { gpr_log(GPR_INFO, "Testing '%s' with servers=%s client=%s", spec->description, servers_hostports_str, client_hostport); - actual_connection_sequence = perform_request(f, client, spec); + actual_connection_sequence = perform_request(f, client, &rdata, spec); spec->verifier(f, client, actual_connection_sequence, spec->num_iters); diff --git a/test/core/network_benchmarks/low_level_ping_pong.c b/test/core/network_benchmarks/low_level_ping_pong.c index 0ce4bd4b250..7a2d894481b 100644 --- a/test/core/network_benchmarks/low_level_ping_pong.c +++ b/test/core/network_benchmarks/low_level_ping_pong.c @@ -82,7 +82,7 @@ typedef struct thread_args { /* Basic call to read() */ static int read_bytes(int fd, char *buf, size_t read_size, int spin) { size_t bytes_read = 0; - int err; + ssize_t err; do { err = read(fd, buf + bytes_read, read_size - bytes_read); if (err < 0) { @@ -96,7 +96,7 @@ static int read_bytes(int fd, char *buf, size_t read_size, int spin) { return -1; } } else { - bytes_read += err; + bytes_read += (size_t)err; } } while (bytes_read < read_size); return 0; @@ -115,6 +115,7 @@ static int poll_read_bytes(int fd, char *buf, size_t read_size, int spin) { struct pollfd pfd; size_t bytes_read = 0; int err; + ssize_t err2; pfd.fd = fd; pfd.events = POLLIN; @@ -132,13 +133,13 @@ static int poll_read_bytes(int fd, char *buf, size_t read_size, int spin) { GPR_ASSERT(err == 1); GPR_ASSERT(pfd.revents == POLLIN); do { - err = read(fd, buf + bytes_read, read_size - bytes_read); - } while (err < 0 && errno == EINTR); - if (err < 0 && errno != EAGAIN) { + err2 = read(fd, buf + bytes_read, read_size - bytes_read); + } while (err2 < 0 && errno == EINTR); + if (err2 < 0 && errno != EAGAIN) { gpr_log(GPR_ERROR, "Read failed: %s", strerror(errno)); return -1; } - bytes_read += err; + bytes_read += (size_t) err2; } while (bytes_read < read_size); return 0; } @@ -157,6 +158,7 @@ static int epoll_read_bytes(struct thread_args *args, char *buf, int spin) { struct epoll_event ev; size_t bytes_read = 0; int err; + ssize_t err2; size_t read_size = args->msg_size; do { @@ -172,10 +174,11 @@ static int epoll_read_bytes(struct thread_args *args, char *buf, int spin) { GPR_ASSERT(ev.data.fd == args->fds.read_fd); do { do { - err = read(args->fds.read_fd, buf + bytes_read, read_size - bytes_read); - } while (err < 0 && errno == EINTR); + err2 = read(args->fds.read_fd, buf + bytes_read, + read_size - bytes_read); + } while (err2 < 0 && errno == EINTR); if (errno == EAGAIN) break; - bytes_read += err; + bytes_read += (size_t) err2; /* TODO(klempner): This should really be doing an extra call after we are done to ensure we see an EAGAIN */ } while (bytes_read < read_size); @@ -199,7 +202,7 @@ static int epoll_read_bytes_spin(struct thread_args *args, char *buf) { */ static int blocking_write_bytes(struct thread_args *args, char *buf) { size_t bytes_written = 0; - int err; + ssize_t err; size_t write_size = args->msg_size; do { err = write(args->fds.write_fd, buf + bytes_written, @@ -212,7 +215,7 @@ static int blocking_write_bytes(struct thread_args *args, char *buf) { return -1; } } else { - bytes_written += err; + bytes_written += (size_t)err; } } while (bytes_written < write_size); return 0; @@ -297,7 +300,7 @@ static void print_histogram(gpr_histogram *histogram) { static double now(void) { gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME); - return 1e9 * tv.tv_sec + tv.tv_nsec; + return 1e9 * (double)tv.tv_sec + (double)tv.tv_nsec; } static void client_thread(thread_args *args) { @@ -373,7 +376,7 @@ error: return -1; } -static int connect_client(struct sockaddr *addr, int len) { +static int connect_client(struct sockaddr *addr, socklen_t len) { int fd = socket(addr->sa_family, SOCK_STREAM, 0); int err; if (fd < 0) { @@ -586,27 +589,27 @@ static int run_benchmark(char *socket_type, thread_args *client_args, return 0; } -static int run_all_benchmarks(int msg_size) { +static int run_all_benchmarks(size_t msg_size) { int error = 0; size_t i; for (i = 0; i < GPR_ARRAY_SIZE(test_strategies); ++i) { - test_strategy *test_strategy = &test_strategies[i]; + test_strategy *strategy = &test_strategies[i]; size_t j; for (j = 0; j < GPR_ARRAY_SIZE(socket_types); ++j) { thread_args *client_args = malloc(sizeof(thread_args)); thread_args *server_args = malloc(sizeof(thread_args)); char *socket_type = socket_types[j]; - client_args->read_bytes = test_strategy->read_strategy; + client_args->read_bytes = strategy->read_strategy; client_args->write_bytes = blocking_write_bytes; - client_args->setup = test_strategy->setup; + client_args->setup = strategy->setup; client_args->msg_size = msg_size; - client_args->strategy_name = test_strategy->name; - server_args->read_bytes = test_strategy->read_strategy; + client_args->strategy_name = strategy->name; + server_args->read_bytes = strategy->read_strategy; server_args->write_bytes = blocking_write_bytes; - server_args->setup = test_strategy->setup; + server_args->setup = strategy->setup; server_args->msg_size = msg_size; - server_args->strategy_name = test_strategy->name; + server_args->strategy_name = strategy->name; error = run_benchmark(socket_type, client_args, server_args); if (error < 0) { return error; @@ -623,7 +626,7 @@ int main(int argc, char **argv) { char *read_strategy = NULL; char *socket_type = NULL; size_t i; - const test_strategy *test_strategy = NULL; + const test_strategy *strategy = NULL; int error = 0; gpr_cmdline *cmdline = @@ -643,7 +646,7 @@ int main(int argc, char **argv) { if (read_strategy == NULL) { gpr_log(GPR_INFO, "No strategy specified, running all benchmarks"); - return run_all_benchmarks(msg_size); + return run_all_benchmarks((size_t)msg_size); } if (socket_type == NULL) { @@ -657,23 +660,23 @@ int main(int argc, char **argv) { for (i = 0; i < GPR_ARRAY_SIZE(test_strategies); ++i) { if (strcmp(test_strategies[i].name, read_strategy) == 0) { - test_strategy = &test_strategies[i]; + strategy = &test_strategies[i]; } } - if (test_strategy == NULL) { + if (strategy == NULL) { fprintf(stderr, "Invalid read strategy %s\n", read_strategy); return -1; } - client_args->read_bytes = test_strategy->read_strategy; + client_args->read_bytes = strategy->read_strategy; client_args->write_bytes = blocking_write_bytes; - client_args->setup = test_strategy->setup; - client_args->msg_size = msg_size; + client_args->setup = strategy->setup; + client_args->msg_size = (size_t)msg_size; client_args->strategy_name = read_strategy; - server_args->read_bytes = test_strategy->read_strategy; + server_args->read_bytes = strategy->read_strategy; server_args->write_bytes = blocking_write_bytes; - server_args->setup = test_strategy->setup; - server_args->msg_size = msg_size; + server_args->setup = strategy->setup; + server_args->msg_size = (size_t)msg_size; server_args->strategy_name = read_strategy; error = run_benchmark(socket_type, client_args, server_args); diff --git a/test/core/support/cpu_test.c b/test/core/support/cpu_test.c index 6559c1b57e2..fa83878a152 100644 --- a/test/core/support/cpu_test.c +++ b/test/core/support/cpu_test.c @@ -81,9 +81,9 @@ static void worker_thread(void *arg) { gpr_uint32 cpu; int r = 12345678; int i, j; - for (i = 0; i < 1000; i++) { + for (i = 0; i < 1000 / GRPC_TEST_SLOWDOWN_FACTOR; i++) { /* run for a bit - just calculate something random. */ - for (j = 0; j < 1000000; j++) { + for (j = 0; j < 1000000 / GRPC_TEST_SLOWDOWN_FACTOR; j++) { r = (r * 17) & ((r - i) | (r * i)); } cpu = gpr_cpu_current_cpu(); diff --git a/test/core/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c index 560e0ac7b23..7f9cd6b62b0 100644 --- a/test/core/surface/byte_buffer_reader_test.c +++ b/test/core/surface/byte_buffer_reader_test.c @@ -184,6 +184,39 @@ static void test_byte_buffer_from_reader(void) { grpc_byte_buffer_destroy(buffer_from_reader); } +static void test_readall(void) { + char* lotsa_as[512]; + char* lotsa_bs[1024]; + gpr_slice slices[2]; + grpc_byte_buffer *buffer; + grpc_byte_buffer_reader reader; + gpr_slice slice_out; + + LOG_TEST("test_readall"); + + memset(lotsa_as, 'a', 512); + memset(lotsa_bs, 'b', 1024); + /* use slices large enough to overflow inlining */ + slices[0] = gpr_slice_malloc(512); + memcpy(GPR_SLICE_START_PTR(slices[0]), lotsa_as, 512); + slices[1] = gpr_slice_malloc(1024); + memcpy(GPR_SLICE_START_PTR(slices[1]), lotsa_bs, 1024); + + buffer = grpc_raw_byte_buffer_create(slices, 2); + gpr_slice_unref(slices[0]); + gpr_slice_unref(slices[1]); + + grpc_byte_buffer_reader_init(&reader, buffer); + slice_out = grpc_byte_buffer_reader_readall(&reader); + + GPR_ASSERT(GPR_SLICE_LENGTH(slice_out) == 512 + 1024); + GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(slice_out), lotsa_as, 512) == 0); + GPR_ASSERT(memcmp(&(GPR_SLICE_START_PTR(slice_out)[512]), lotsa_bs, 1024) == + 0); + gpr_slice_unref(slice_out); + grpc_byte_buffer_destroy(buffer); +} + int main(int argc, char **argv) { grpc_test_init(argc, argv); test_read_one_slice(); @@ -192,6 +225,6 @@ int main(int argc, char **argv) { test_read_gzip_compressed_slice(); test_read_deflate_compressed_slice(); test_byte_buffer_from_reader(); - + test_readall(); return 0; } diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc index 9c35fede8f6..80057d893e1 100644 --- a/test/cpp/end2end/mock_test.cc +++ b/test/cpp/end2end/mock_test.cc @@ -62,7 +62,7 @@ template class MockClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface { public: - void WaitForInitialMetadata() {} + void WaitForInitialMetadata() GRPC_OVERRIDE {} bool Read(R* msg) GRPC_OVERRIDE { return true; } bool Write(const W& msg) GRPC_OVERRIDE { return true; } bool WritesDone() GRPC_OVERRIDE { return true; } @@ -73,7 +73,7 @@ class MockClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface { public: MockClientReaderWriter() : writes_done_(false) {} - void WaitForInitialMetadata() {} + void WaitForInitialMetadata() GRPC_OVERRIDE {} bool Read(EchoResponse* msg) GRPC_OVERRIDE { if (writes_done_) return false; msg->set_message(last_message_); diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc index 49f3fbcc14c..5d1419728e4 100644 --- a/test/cpp/interop/stress_test.cc +++ b/test/cpp/interop/stress_test.cc @@ -186,14 +186,7 @@ int main(int argc, char** argv) { // Parse test cases and weights if (FLAGS_test_cases.length() == 0) { gpr_log(GPR_INFO, "Not running tests. The 'test_cases' string is empty"); - - // TODO(sreek): stress_tests is currently being run by run_tests.py in - // jenkins. There does not seem to be a straightforward way to skip this. - // So, for now, return 0 (i.e success) to keep jenkins build happy. Moreover - // we don't want to run stress_tests (for now) in jenkins anyway. - // Once we figure out a good way to skip this tests in run_tests.py, I will - // change this to 'return 1' - return 0; + return 1; } vector> tests; diff --git a/test/cpp/qps/async_streaming_ping_pong_test.cc b/test/cpp/qps/async_streaming_ping_pong_test.cc index 411df4d32af..9fef93a70fd 100644 --- a/test/cpp/qps/async_streaming_ping_pong_test.cc +++ b/test/cpp/qps/async_streaming_ping_pong_test.cc @@ -35,8 +35,6 @@ #include -#include - #include "test/cpp/qps/driver.h" #include "test/cpp/qps/report.h" #include "test/cpp/util/benchmark_config.h" @@ -52,17 +50,15 @@ static void RunAsyncStreamingPingPong() { ClientConfig client_config; client_config.set_client_type(ASYNC_CLIENT); - client_config.set_enable_ssl(false); client_config.set_outstanding_rpcs_per_channel(1); client_config.set_client_channels(1); - client_config.set_payload_size(1); client_config.set_async_client_threads(1); client_config.set_rpc_type(STREAMING); + client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; server_config.set_server_type(ASYNC_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(1); + server_config.set_async_server_threads(1); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -77,7 +73,6 @@ static void RunAsyncStreamingPingPong() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::RunAsyncStreamingPingPong(); return 0; } diff --git a/test/cpp/qps/async_unary_ping_pong_test.cc b/test/cpp/qps/async_unary_ping_pong_test.cc index eda31b57442..b4ab0e5d595 100644 --- a/test/cpp/qps/async_unary_ping_pong_test.cc +++ b/test/cpp/qps/async_unary_ping_pong_test.cc @@ -35,8 +35,6 @@ #include -#include - #include "test/cpp/qps/driver.h" #include "test/cpp/qps/report.h" #include "test/cpp/util/benchmark_config.h" @@ -52,17 +50,15 @@ static void RunAsyncUnaryPingPong() { ClientConfig client_config; client_config.set_client_type(ASYNC_CLIENT); - client_config.set_enable_ssl(false); client_config.set_outstanding_rpcs_per_channel(1); client_config.set_client_channels(1); - client_config.set_payload_size(1); client_config.set_async_client_threads(1); client_config.set_rpc_type(UNARY); + client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; server_config.set_server_type(ASYNC_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(1); + server_config.set_async_server_threads(1); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -75,7 +71,6 @@ static void RunAsyncUnaryPingPong() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::RunAsyncUnaryPingPong(); return 0; diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index cd8b34f65b3..f4400692fea 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -40,8 +40,9 @@ #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/interarrival.h" #include "test/cpp/qps/timer.h" -#include "test/proto/qpstest.grpc.pb.h" #include "test/cpp/util/create_test_channel.h" +#include "test/proto/benchmarks/payloads.grpc.pb.h" +#include "test/proto/benchmarks/services.grpc.pb.h" namespace grpc { @@ -75,27 +76,54 @@ class Client { channels_[i].init(config.server_targets(i % config.server_targets_size()), config); } - request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE); - request_.set_response_size(config.payload_size()); + if (config.payload_config().has_bytebuf_params()) { + GPR_ASSERT(false); // not yet implemented + } else if (config.payload_config().has_simple_params()) { + request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE); + request_.set_response_size( + config.payload_config().simple_params().resp_size()); + request_.mutable_payload()->set_type( + grpc::testing::PayloadType::COMPRESSABLE); + int size = config.payload_config().simple_params().req_size(); + std::unique_ptr body(new char[size]); + request_.mutable_payload()->set_body(body.get(), size); + } else if (config.payload_config().has_complex_params()) { + GPR_ASSERT(false); // not yet implemented + } else { + // default should be simple proto without payloads + request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE); + request_.set_response_size(0); + request_.mutable_payload()->set_type( + grpc::testing::PayloadType::COMPRESSABLE); + } } virtual ~Client() {} - ClientStats Mark() { + ClientStats Mark(bool reset) { Histogram latencies; + Timer::Result timer_result; + // avoid std::vector for old compilers that expect a copy constructor - Histogram* to_merge = new Histogram[threads_.size()]; - for (size_t i = 0; i < threads_.size(); i++) { - threads_[i]->BeginSwap(&to_merge[i]); - } - std::unique_ptr timer(new Timer); - timer_.swap(timer); - for (size_t i = 0; i < threads_.size(); i++) { - threads_[i]->EndSwap(); - latencies.Merge(&to_merge[i]); + if (reset) { + Histogram* to_merge = new Histogram[threads_.size()]; + for (size_t i = 0; i < threads_.size(); i++) { + threads_[i]->BeginSwap(&to_merge[i]); + } + std::unique_ptr timer(new Timer); + timer_.swap(timer); + for (size_t i = 0; i < threads_.size(); i++) { + threads_[i]->EndSwap(); + latencies.Merge(to_merge[i]); + } + delete[] to_merge; + timer_result = timer->Mark(); + } else { + // merge snapshots of each thread histogram + for (size_t i = 0; i < threads_.size(); i++) { + threads_[i]->MergeStatsInto(&latencies); + } + timer_result = timer_->Mark(); } - delete[] to_merge; - - auto timer_result = timer->Mark(); ClientStats stats; latencies.FillProto(stats.mutable_latencies()); @@ -122,15 +150,18 @@ class Client { // We have to use a 2-phase init like this with a default // constructor followed by an initializer function to make // old compilers happy with using this in std::vector - channel_ = CreateTestChannel(target, config.enable_ssl()); - stub_ = TestService::NewStub(channel_); + channel_ = CreateTestChannel( + target, config.security_params().server_host_override(), + config.has_security_params(), + !config.security_params().use_test_ca()); + stub_ = BenchmarkService::NewStub(channel_); } Channel* get_channel() { return channel_.get(); } - TestService::Stub* get_stub() { return stub_.get(); } + BenchmarkService::Stub* get_stub() { return stub_.get(); } private: std::shared_ptr channel_; - std::unique_ptr stub_; + std::unique_ptr stub_; }; std::vector channels_; @@ -146,37 +177,41 @@ class Client { void SetupLoadTest(const ClientConfig& config, size_t num_threads) { // Set up the load distribution based on the number of threads - if (config.load_type() == CLOSED_LOOP) { + const auto& load = config.load_params(); + + std::unique_ptr random_dist; + switch (load.load_case()) { + case LoadParams::kClosedLoop: + // Closed-loop doesn't use random dist at all + break; + case LoadParams::kPoisson: + random_dist.reset( + new ExpDist(load.poisson().offered_load() / num_threads)); + break; + case LoadParams::kUniform: + random_dist.reset( + new UniformDist(load.uniform().interarrival_lo() * num_threads, + load.uniform().interarrival_hi() * num_threads)); + break; + case LoadParams::kDeterm: + random_dist.reset( + new DetDist(num_threads / load.determ().offered_load())); + break; + case LoadParams::kPareto: + random_dist.reset( + new ParetoDist(load.pareto().interarrival_base() * num_threads, + load.pareto().alpha())); + break; + default: + GPR_ASSERT(false); + } + + // Set closed_loop_ based on whether or not random_dist is set + if (!random_dist) { closed_loop_ = true; } else { closed_loop_ = false; - - std::unique_ptr random_dist; - const auto& load = config.load_params(); - switch (config.load_type()) { - case POISSON: - random_dist.reset( - new ExpDist(load.poisson().offered_load() / num_threads)); - break; - case UNIFORM: - random_dist.reset( - new UniformDist(load.uniform().interarrival_lo() * num_threads, - load.uniform().interarrival_hi() * num_threads)); - break; - case DETERMINISTIC: - random_dist.reset( - new DetDist(num_threads / load.determ().offered_load())); - break; - case PARETO: - random_dist.reset( - new ParetoDist(load.pareto().interarrival_base() * num_threads, - load.pareto().alpha())); - break; - default: - GPR_ASSERT(false); - break; - } - + // set up interarrival timer according to random dist interarrival_timer_.init(*random_dist, num_threads); for (size_t i = 0; i < num_threads; i++) { next_time_.push_back( @@ -204,7 +239,7 @@ class Client { public: Thread(Client* client, size_t idx) : done_(false), - new_(nullptr), + new_stats_(nullptr), client_(client), idx_(idx), impl_(&Thread::ThreadFunc, this) {} @@ -219,16 +254,21 @@ class Client { void BeginSwap(Histogram* n) { std::lock_guard g(mu_); - new_ = n; + new_stats_ = n; } void EndSwap() { std::unique_lock g(mu_); - while (new_ != nullptr) { + while (new_stats_ != nullptr) { cv_.wait(g); }; } + void MergeStatsInto(Histogram* hist) { + std::unique_lock g(mu_); + hist->Merge(histogram_); + } + private: Thread(const Thread&); Thread& operator=(const Thread&); @@ -246,21 +286,21 @@ class Client { if (done_) { return; } - // check if we're marking, swap out the histogram if so - if (new_) { - new_->Swap(&histogram_); - new_ = nullptr; + // check if we're resetting stats, swap out the histogram if so + if (new_stats_) { + new_stats_->Swap(&histogram_); + new_stats_ = nullptr; cv_.notify_one(); } } } - TestService::Stub* stub_; + BenchmarkService::Stub* stub_; ClientConfig config_; std::mutex mu_; std::condition_variable cv_; bool done_; - Histogram* new_; + Histogram* new_stats_; Histogram histogram_; Client* client_; size_t idx_; diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index 9ed42b7db63..9594179822d 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -48,10 +48,10 @@ #include #include -#include "test/proto/qpstest.grpc.pb.h" #include "test/cpp/qps/timer.h" #include "test/cpp/qps/client.h" #include "test/cpp/util/create_test_channel.h" +#include "test/proto/benchmarks/services.grpc.pb.h" namespace grpc { namespace testing { @@ -88,10 +88,10 @@ template class ClientRpcContextUnaryImpl : public ClientRpcContext { public: ClientRpcContextUnaryImpl( - int channel_id, TestService::Stub* stub, const RequestType& req, + int channel_id, BenchmarkService::Stub* stub, const RequestType& req, std::function< std::unique_ptr>( - TestService::Stub*, grpc::ClientContext*, const RequestType&, + BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&, CompletionQueue*)> start_req, std::function on_done) : ClientRpcContext(channel_id), @@ -131,13 +131,13 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext { return true; // we're done, this'll be ignored } grpc::ClientContext context_; - TestService::Stub* stub_; + BenchmarkService::Stub* stub_; RequestType req_; ResponseType response_; bool (ClientRpcContextUnaryImpl::*next_state_)(bool); std::function callback_; std::function>( - TestService::Stub*, grpc::ClientContext*, const RequestType&, + BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&, CompletionQueue*)> start_req_; grpc::Status status_; double start_; @@ -151,7 +151,7 @@ class AsyncClient : public Client { public: explicit AsyncClient( const ClientConfig& config, - std::function setup_ctx) : Client(config), channel_lock_(new std::mutex[config.client_channels()]), @@ -354,11 +354,12 @@ class AsyncUnaryClient GRPC_FINAL : public AsyncClient { private: static void CheckDone(grpc::Status s, SimpleResponse* response) {} static std::unique_ptr> - StartReq(TestService::Stub* stub, grpc::ClientContext* ctx, + StartReq(BenchmarkService::Stub* stub, grpc::ClientContext* ctx, const SimpleRequest& request, CompletionQueue* cq) { return stub->AsyncUnaryCall(ctx, request, cq); }; - static ClientRpcContext* SetupCtx(int channel_id, TestService::Stub* stub, + static ClientRpcContext* SetupCtx(int channel_id, + BenchmarkService::Stub* stub, const SimpleRequest& req) { return new ClientRpcContextUnaryImpl( channel_id, stub, req, AsyncUnaryClient::StartReq, @@ -370,10 +371,11 @@ template class ClientRpcContextStreamingImpl : public ClientRpcContext { public: ClientRpcContextStreamingImpl( - int channel_id, TestService::Stub* stub, const RequestType& req, - std::function>(TestService::Stub*, grpc::ClientContext*, - CompletionQueue*, void*)> start_req, + int channel_id, BenchmarkService::Stub* stub, const RequestType& req, + std::function>( + BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, + void*)> start_req, std::function on_done) : ClientRpcContext(channel_id), context_(), @@ -420,15 +422,15 @@ class ClientRpcContextStreamingImpl : public ClientRpcContext { return StartWrite(ok); } grpc::ClientContext context_; - TestService::Stub* stub_; + BenchmarkService::Stub* stub_; RequestType req_; ResponseType response_; bool (ClientRpcContextStreamingImpl::*next_state_)(bool, Histogram*); std::function callback_; std::function< std::unique_ptr>( - TestService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)> - start_req_; + BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, + void*)> start_req_; grpc::Status status_; double start_; std::unique_ptr> @@ -439,8 +441,8 @@ class AsyncStreamingClient GRPC_FINAL : public AsyncClient { public: explicit AsyncStreamingClient(const ClientConfig& config) : AsyncClient(config, SetupCtx) { - // async streaming currently only supported closed loop - GPR_ASSERT(config.load_type() == CLOSED_LOOP); + // async streaming currently only supports closed loop + GPR_ASSERT(closed_loop_); StartThreads(config.async_client_threads()); } @@ -451,12 +453,13 @@ class AsyncStreamingClient GRPC_FINAL : public AsyncClient { static void CheckDone(grpc::Status s, SimpleResponse* response) {} static std::unique_ptr< grpc::ClientAsyncReaderWriter> - StartReq(TestService::Stub* stub, grpc::ClientContext* ctx, + StartReq(BenchmarkService::Stub* stub, grpc::ClientContext* ctx, CompletionQueue* cq, void* tag) { auto stream = stub->AsyncStreamingCall(ctx, cq, tag); return stream; }; - static ClientRpcContext* SetupCtx(int channel_id, TestService::Stub* stub, + static ClientRpcContext* SetupCtx(int channel_id, + BenchmarkService::Stub* stub, const SimpleRequest& req) { return new ClientRpcContextStreamingImpl( channel_id, stub, req, AsyncStreamingClient::StartReq, diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index ed4134c7436..10d680860a9 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -54,10 +54,10 @@ #include "test/cpp/util/create_test_channel.h" #include "test/cpp/qps/client.h" -#include "test/proto/qpstest.grpc.pb.h" #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/interarrival.h" #include "test/cpp/qps/timer.h" +#include "test/proto/benchmarks/services.grpc.pb.h" #include "src/core/profiling/timers.h" diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index dd5c4f4f73f..2c6247deea1 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -48,6 +48,7 @@ #include "test/cpp/qps/driver.h" #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/qps_worker.h" +#include "test/proto/benchmarks/services.grpc.pb.h" using std::list; using std::thread; @@ -91,12 +92,12 @@ static ClientContext* AllocContext(list* contexts, T deadline) { } struct ServerData { - unique_ptr stub; + unique_ptr stub; unique_ptr> stream; }; struct ClientData { - unique_ptr stub; + unique_ptr stub; unique_ptr> stream; }; } // namespace runsc @@ -131,8 +132,7 @@ std::unique_ptr RunScenario( } int driver_port = grpc_pick_unused_port_or_die(); - int benchmark_port = grpc_pick_unused_port_or_die(); - local_workers.emplace_back(new QpsWorker(driver_port, benchmark_port)); + local_workers.emplace_back(new QpsWorker(driver_port)); char addr[256]; sprintf(addr, "localhost:%d", driver_port); if (spawn_local_worker_count < 0) { @@ -161,11 +161,10 @@ std::unique_ptr RunScenario( // where class contained in std::vector must have a copy constructor auto* servers = new ServerData[num_servers]; for (size_t i = 0; i < num_servers; i++) { - servers[i].stub = - Worker::NewStub(CreateChannel(workers[i], InsecureCredentials())); + servers[i].stub = WorkerService::NewStub( + CreateChannel(workers[i], InsecureCredentials())); ServerArgs args; result_server_config = server_config; - result_server_config.set_host(workers[i]); *args.mutable_setup() = server_config; servers[i].stream = servers[i].stub->RunServer(runsc::AllocContext(&contexts, deadline)); @@ -189,14 +188,13 @@ std::unique_ptr RunScenario( // where class contained in std::vector must have a copy constructor auto* clients = new ClientData[num_clients]; for (size_t i = 0; i < num_clients; i++) { - clients[i].stub = Worker::NewStub( + clients[i].stub = WorkerService::NewStub( CreateChannel(workers[i + num_servers], InsecureCredentials())); ClientArgs args; result_client_config = client_config; - result_client_config.set_host(workers[i + num_servers]); *args.mutable_setup() = client_config; clients[i].stream = - clients[i].stub->RunTest(runsc::AllocContext(&contexts, deadline)); + clients[i].stub->RunClient(runsc::AllocContext(&contexts, deadline)); GPR_ASSERT(clients[i].stream->Write(args)); ClientStatus init_status; GPR_ASSERT(clients[i].stream->Read(&init_status)); @@ -211,9 +209,9 @@ std::unique_ptr RunScenario( // Start a run gpr_log(GPR_INFO, "Starting"); ServerArgs server_mark; - server_mark.mutable_mark(); + server_mark.mutable_mark()->set_reset(true); ClientArgs client_mark; - client_mark.mutable_mark(); + client_mark.mutable_mark()->set_reset(true); for (auto server = &servers[0]; server != &servers[num_servers]; server++) { GPR_ASSERT(server->stream->Write(server_mark)); } @@ -251,14 +249,15 @@ std::unique_ptr RunScenario( GPR_ASSERT(server->stream->Read(&server_status)); const auto& stats = server_status.stats(); result->server_resources.emplace_back( - stats.time_elapsed(), stats.time_user(), stats.time_system()); + stats.time_elapsed(), stats.time_user(), stats.time_system(), + server_status.cores()); } for (auto client = &clients[0]; client != &clients[num_clients]; client++) { GPR_ASSERT(client->stream->Read(&client_status)); const auto& stats = client_status.stats(); result->latencies.MergeProto(stats.latencies()); result->client_resources.emplace_back( - stats.time_elapsed(), stats.time_user(), stats.time_system()); + stats.time_elapsed(), stats.time_user(), stats.time_system(), -1); } for (auto client = &clients[0]; client != &clients[num_clients]; client++) { diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h index 6116aa656a9..50bf17ceab2 100644 --- a/test/cpp/qps/driver.h +++ b/test/cpp/qps/driver.h @@ -37,22 +37,24 @@ #include #include "test/cpp/qps/histogram.h" -#include "test/proto/qpstest.grpc.pb.h" +#include "test/proto/benchmarks/control.grpc.pb.h" namespace grpc { namespace testing { class ResourceUsage { public: - ResourceUsage(double w, double u, double s) - : wall_time_(w), user_time_(u), system_time_(s) {} + ResourceUsage(double w, double u, double s, int c) + : wall_time_(w), user_time_(u), system_time_(s), cores_(c) {} double wall_time() const { return wall_time_; } double user_time() const { return user_time_; } double system_time() const { return system_time_; } + int cores() const { return cores_; } private: double wall_time_; double user_time_; double system_time_; + int cores_; }; struct ScenarioResult { diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h index 1151cca87c5..35527d2a2cb 100644 --- a/test/cpp/qps/histogram.h +++ b/test/cpp/qps/histogram.h @@ -35,7 +35,7 @@ #define TEST_QPS_HISTOGRAM_H #include -#include "test/proto/qpstest.grpc.pb.h" +#include "test/proto/benchmarks/stats.grpc.pb.h" namespace grpc { namespace testing { @@ -48,7 +48,7 @@ class Histogram { } Histogram(Histogram&& other) : impl_(other.impl_) { other.impl_ = nullptr; } - void Merge(Histogram* h) { gpr_histogram_merge(impl_, h->impl_); } + void Merge(const Histogram& h) { gpr_histogram_merge(impl_, h.impl_); } void Add(double value) { gpr_histogram_add(impl_, value); } double Percentile(double pctile) const { return gpr_histogram_percentile(impl_, pctile); diff --git a/test/cpp/qps/perf_db.proto b/test/cpp/qps/perf_db.proto index 7ae5cfe86e2..8a691ddded4 100644 --- a/test/cpp/qps/perf_db.proto +++ b/test/cpp/qps/perf_db.proto @@ -29,7 +29,7 @@ syntax = "proto3"; -import "test/proto/qpstest.proto"; +import "test/proto/benchmarks/control.proto"; package grpc.testing; diff --git a/test/cpp/qps/qps-sweep.sh b/test/cpp/qps/qps-sweep.sh index cb932019335..36ea974812a 100755 --- a/test/cpp/qps/qps-sweep.sh +++ b/test/cpp/qps/qps-sweep.sh @@ -37,17 +37,21 @@ fi bins=`find . .. ../.. ../../.. -name bins | head -1` -for channels in 1 2 4 8 +for secure in true false do - for client in SYNCHRONOUS_CLIENT ASYNC_CLIENT + for channels in 1 2 4 8 do - for server in SYNCHRONOUS_SERVER ASYNC_SERVER + for client in SYNC_CLIENT ASYNC_CLIENT do - for rpc in UNARY STREAMING + for server in SYNC_SERVER ASYNC_SERVER do - echo "Test $rpc $client $server , $channels channels" - "$bins"/opt/qps_driver --rpc_type=$rpc \ - --client_type=$client --server_type=$server + for rpc in UNARY STREAMING + do + echo "Test $rpc $client $server, $channels channels, secure=$secure" + "$bins"/opt/qps_driver --rpc_type=$rpc \ + --client_type=$client --server_type=$server \ + --secure_test=$secure + done done done done diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc index b1463be8f62..4c93a042cf5 100644 --- a/test/cpp/qps/qps_driver.cc +++ b/test/cpp/qps/qps_driver.cc @@ -33,7 +33,6 @@ #include #include -#include #include #include @@ -50,31 +49,39 @@ DEFINE_int32(benchmark_seconds, 30, "Benchmark time (in seconds)"); DEFINE_int32(local_workers, 0, "Number of local workers to start"); // Common config -DEFINE_bool(enable_ssl, false, "Use SSL"); DEFINE_string(rpc_type, "UNARY", "Type of RPC: UNARY or STREAMING"); // Server config -DEFINE_int32(server_threads, 1, "Number of server threads"); -DEFINE_string(server_type, "SYNCHRONOUS_SERVER", "Server type"); +DEFINE_int32(async_server_threads, 1, "Number of threads for async servers"); +DEFINE_string(server_type, "SYNC_SERVER", "Server type"); // Client config DEFINE_int32(outstanding_rpcs_per_channel, 1, "Number of outstanding rpcs per channel"); DEFINE_int32(client_channels, 1, "Number of client channels"); -DEFINE_int32(payload_size, 1, "Payload size"); -DEFINE_string(client_type, "SYNCHRONOUS_CLIENT", "Client type"); + +DEFINE_int32(simple_req_size, -1, "Simple proto request payload size"); +DEFINE_int32(simple_resp_size, -1, "Simple proto response payload size"); + +DEFINE_string(client_type, "SYNC_CLIENT", "Client type"); DEFINE_int32(async_client_threads, 1, "Async client threads"); -DEFINE_string(load_type, "CLOSED_LOOP", "Load type"); -DEFINE_double(load_param_1, 0.0, "Load parameter 1"); -DEFINE_double(load_param_2, 0.0, "Load parameter 2"); + +DEFINE_double(poisson_load, -1.0, "Poisson offered load (qps)"); +DEFINE_double(uniform_lo, -1.0, "Uniform low interarrival time (us)"); +DEFINE_double(uniform_hi, -1.0, "Uniform high interarrival time (us)"); +DEFINE_double(determ_load, -1.0, "Deterministic offered load (qps)"); +DEFINE_double(pareto_base, -1.0, "Pareto base interarrival time (us)"); +DEFINE_double(pareto_alpha, -1.0, "Pareto alpha value"); + +DEFINE_bool(secure_test, false, "Run a secure test"); using grpc::testing::ClientConfig; using grpc::testing::ServerConfig; using grpc::testing::ClientType; using grpc::testing::ServerType; -using grpc::testing::LoadType; using grpc::testing::RpcType; using grpc::testing::ResourceUsage; +using grpc::testing::SecurityParams; namespace grpc { namespace testing { @@ -85,72 +92,63 @@ static void QpsDriver() { ClientType client_type; ServerType server_type; - LoadType load_type; GPR_ASSERT(ClientType_Parse(FLAGS_client_type, &client_type)); GPR_ASSERT(ServerType_Parse(FLAGS_server_type, &server_type)); - GPR_ASSERT(LoadType_Parse(FLAGS_load_type, &load_type)); ClientConfig client_config; client_config.set_client_type(client_type); - client_config.set_load_type(load_type); - client_config.set_enable_ssl(FLAGS_enable_ssl); client_config.set_outstanding_rpcs_per_channel( FLAGS_outstanding_rpcs_per_channel); client_config.set_client_channels(FLAGS_client_channels); - client_config.set_payload_size(FLAGS_payload_size); + + // Decide which type to use based on the response type + if (FLAGS_simple_resp_size >= 0) { + auto params = + client_config.mutable_payload_config()->mutable_simple_params(); + params->set_resp_size(FLAGS_simple_resp_size); + if (FLAGS_simple_req_size >= 0) { + params->set_req_size(FLAGS_simple_req_size); + } + } else { + // set a reasonable default: proto but no payload + client_config.mutable_payload_config()->mutable_simple_params(); + } + client_config.set_async_client_threads(FLAGS_async_client_threads); client_config.set_rpc_type(rpc_type); // set up the load parameters - switch (load_type) { - case grpc::testing::CLOSED_LOOP: - break; - case grpc::testing::POISSON: { - auto poisson = client_config.mutable_load_params()->mutable_poisson(); - GPR_ASSERT(FLAGS_load_param_1 != 0.0); - poisson->set_offered_load(FLAGS_load_param_1); - break; - } - case grpc::testing::UNIFORM: { - auto uniform = client_config.mutable_load_params()->mutable_uniform(); - GPR_ASSERT(FLAGS_load_param_1 != 0.0); - GPR_ASSERT(FLAGS_load_param_2 != 0.0); - uniform->set_interarrival_lo(FLAGS_load_param_1 / 1e6); - uniform->set_interarrival_hi(FLAGS_load_param_2 / 1e6); - break; - } - case grpc::testing::DETERMINISTIC: { - auto determ = client_config.mutable_load_params()->mutable_determ(); - GPR_ASSERT(FLAGS_load_param_1 != 0.0); - determ->set_offered_load(FLAGS_load_param_1); - break; - } - case grpc::testing::PARETO: { - auto pareto = client_config.mutable_load_params()->mutable_pareto(); - GPR_ASSERT(FLAGS_load_param_1 != 0.0); - GPR_ASSERT(FLAGS_load_param_2 != 0.0); - pareto->set_interarrival_base(FLAGS_load_param_1 / 1e6); - pareto->set_alpha(FLAGS_load_param_2); - break; - } - default: - GPR_ASSERT(false); - break; + if (FLAGS_poisson_load > 0.0) { + auto poisson = client_config.mutable_load_params()->mutable_poisson(); + poisson->set_offered_load(FLAGS_poisson_load); + } else if (FLAGS_uniform_lo > 0.0) { + auto uniform = client_config.mutable_load_params()->mutable_uniform(); + uniform->set_interarrival_lo(FLAGS_uniform_lo / 1e6); + uniform->set_interarrival_hi(FLAGS_uniform_hi / 1e6); + } else if (FLAGS_determ_load > 0.0) { + auto determ = client_config.mutable_load_params()->mutable_determ(); + determ->set_offered_load(FLAGS_determ_load); + } else if (FLAGS_pareto_base > 0.0) { + auto pareto = client_config.mutable_load_params()->mutable_pareto(); + pareto->set_interarrival_base(FLAGS_pareto_base / 1e6); + pareto->set_alpha(FLAGS_pareto_alpha); + } else { + client_config.mutable_load_params()->mutable_closed_loop(); + // No further load parameters to set up for closed loop } ServerConfig server_config; server_config.set_server_type(server_type); - server_config.set_threads(FLAGS_server_threads); - server_config.set_enable_ssl(FLAGS_enable_ssl); - - // If we're running a sync-server streaming test, make sure - // that we have at least as many threads as the active streams - // or else threads will be blocked from forward progress and the - // client will deadlock on a timer. - GPR_ASSERT(!(server_type == grpc::testing::SYNCHRONOUS_SERVER && - rpc_type == grpc::testing::STREAMING && - FLAGS_server_threads < - FLAGS_client_channels * FLAGS_outstanding_rpcs_per_channel)); + server_config.set_async_server_threads(FLAGS_async_server_threads); + + if (FLAGS_secure_test) { + // Set up security params + SecurityParams security; + security.set_use_test_ca(true); + security.set_server_host_override("foo.test.google.fr"); + client_config.mutable_security_params()->CopyFrom(security); + server_config.mutable_security_params()->CopyFrom(security); + } const auto result = RunScenario( client_config, FLAGS_num_clients, server_config, FLAGS_num_servers, @@ -168,7 +166,6 @@ static void QpsDriver() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::QpsDriver(); return 0; diff --git a/test/cpp/qps/qps_interarrival_test.cc b/test/cpp/qps/qps_interarrival_test.cc index a7979e61878..ccda28f09ae 100644 --- a/test/cpp/qps/qps_interarrival_test.cc +++ b/test/cpp/qps/qps_interarrival_test.cc @@ -42,7 +42,7 @@ using grpc::testing::RandomDist; using grpc::testing::InterarrivalTimer; -void RunTest(RandomDist &&r, int threads, std::string title) { +static void RunTest(RandomDist &&r, int threads, std::string title) { InterarrivalTimer timer; timer.init(r, threads); gpr_histogram *h(gpr_histogram_create(0.01, 60e9)); diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc index 5a6a9249a93..dc88c893bb9 100644 --- a/test/cpp/qps/qps_openloop_test.cc +++ b/test/cpp/qps/qps_openloop_test.cc @@ -31,8 +31,6 @@ * */ -#include - #include #include @@ -52,20 +50,16 @@ static void RunQPS() { ClientConfig client_config; client_config.set_client_type(ASYNC_CLIENT); - client_config.set_enable_ssl(false); client_config.set_outstanding_rpcs_per_channel(1000); client_config.set_client_channels(8); - client_config.set_payload_size(1); client_config.set_async_client_threads(8); client_config.set_rpc_type(UNARY); - client_config.set_load_type(POISSON); client_config.mutable_load_params()->mutable_poisson()->set_offered_load( 1000.0); ServerConfig server_config; server_config.set_server_type(ASYNC_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(4); + server_config.set_async_server_threads(4); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -80,7 +74,6 @@ static void RunQPS() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::RunQPS(); return 0; diff --git a/test/cpp/qps/qps_test.cc b/test/cpp/qps/qps_test.cc index d0c4a79cd92..89b35cfb052 100644 --- a/test/cpp/qps/qps_test.cc +++ b/test/cpp/qps/qps_test.cc @@ -31,8 +31,6 @@ * */ -#include - #include #include @@ -52,17 +50,15 @@ static void RunQPS() { ClientConfig client_config; client_config.set_client_type(ASYNC_CLIENT); - client_config.set_enable_ssl(false); client_config.set_outstanding_rpcs_per_channel(1000); client_config.set_client_channels(8); - client_config.set_payload_size(1); client_config.set_async_client_threads(8); client_config.set_rpc_type(UNARY); + client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; server_config.set_server_type(ASYNC_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(8); + server_config.set_async_server_threads(8); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -77,7 +73,6 @@ static void RunQPS() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::RunQPS(); return 0; diff --git a/test/cpp/qps/qps_test_with_poll.cc b/test/cpp/qps/qps_test_with_poll.cc index 31d2c1bf7b4..97da4096ed3 100644 --- a/test/cpp/qps/qps_test_with_poll.cc +++ b/test/cpp/qps/qps_test_with_poll.cc @@ -31,8 +31,6 @@ * */ -#include - #include #include @@ -56,17 +54,15 @@ static void RunQPS() { ClientConfig client_config; client_config.set_client_type(ASYNC_CLIENT); - client_config.set_enable_ssl(false); client_config.set_outstanding_rpcs_per_channel(1000); client_config.set_client_channels(8); - client_config.set_payload_size(1); client_config.set_async_client_threads(8); client_config.set_rpc_type(UNARY); + client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; server_config.set_server_type(ASYNC_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(4); + server_config.set_async_server_threads(4); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -83,7 +79,6 @@ int main(int argc, char** argv) { grpc_platform_become_multipoller = grpc_poll_become_multipoller; - signal(SIGPIPE, SIG_IGN); grpc::testing::RunQPS(); return 0; diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc index 4ce77f366de..dc59eab7ef6 100644 --- a/test/cpp/qps/qps_worker.cc +++ b/test/cpp/qps/qps_worker.cc @@ -52,17 +52,17 @@ #include #include "test/core/util/grpc_profiler.h" -#include "test/proto/qpstest.pb.h" #include "test/cpp/qps/client.h" #include "test/cpp/qps/server.h" #include "test/cpp/util/create_test_channel.h" +#include "test/proto/benchmarks/services.pb.h" namespace grpc { namespace testing { -std::unique_ptr CreateClient(const ClientConfig& config) { +static std::unique_ptr CreateClient(const ClientConfig& config) { switch (config.client_type()) { - case ClientType::SYNCHRONOUS_CLIENT: + case ClientType::SYNC_CLIENT: return (config.rpc_type() == RpcType::UNARY) ? CreateSynchronousUnaryClient(config) : CreateSynchronousStreamingClient(config); @@ -76,26 +76,29 @@ std::unique_ptr CreateClient(const ClientConfig& config) { abort(); } -std::unique_ptr CreateServer(const ServerConfig& config, - int server_port) { +static void LimitCores(int cores) {} + +static std::unique_ptr CreateServer(const ServerConfig& config) { + if (config.core_limit() > 0) { + LimitCores(config.core_limit()); + } switch (config.server_type()) { - case ServerType::SYNCHRONOUS_SERVER: - return CreateSynchronousServer(config, server_port); + case ServerType::SYNC_SERVER: + return CreateSynchronousServer(config); case ServerType::ASYNC_SERVER: - return CreateAsyncServer(config, server_port); + return CreateAsyncServer(config); default: abort(); } abort(); } -class WorkerImpl GRPC_FINAL : public Worker::Service { +class WorkerServiceImpl GRPC_FINAL : public WorkerService::Service { public: - explicit WorkerImpl(int server_port) - : server_port_(server_port), acquired_(false) {} + explicit WorkerServiceImpl() : acquired_(false) {} - Status RunTest(ServerContext* ctx, - ServerReaderWriter* stream) + Status RunClient(ServerContext* ctx, + ServerReaderWriter* stream) GRPC_OVERRIDE { InstanceGuard g(this); if (!g.Acquired()) { @@ -103,7 +106,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { } grpc_profiler_start("qps_client.prof"); - Status ret = RunTestBody(ctx, stream); + Status ret = RunClientBody(ctx, stream); grpc_profiler_stop(); return ret; } @@ -126,7 +129,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { // Protect against multiple clients using this worker at once. class InstanceGuard { public: - InstanceGuard(WorkerImpl* impl) + InstanceGuard(WorkerServiceImpl* impl) : impl_(impl), acquired_(impl->TryAcquireInstance()) {} ~InstanceGuard() { if (acquired_) { @@ -137,7 +140,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { bool Acquired() const { return acquired_; } private: - WorkerImpl* const impl_; + WorkerServiceImpl* const impl_; const bool acquired_; }; @@ -154,8 +157,8 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { acquired_ = false; } - Status RunTestBody(ServerContext* ctx, - ServerReaderWriter* stream) { + Status RunClientBody(ServerContext* ctx, + ServerReaderWriter* stream) { ClientArgs args; if (!stream->Read(&args)) { return Status(StatusCode::INVALID_ARGUMENT, ""); @@ -175,7 +178,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { if (!args.has_mark()) { return Status(StatusCode::INVALID_ARGUMENT, ""); } - *status.mutable_stats() = client->Mark(); + *status.mutable_stats() = client->Mark(args.mark().reset()); stream->Write(status); } @@ -191,12 +194,13 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { if (!args.has_setup()) { return Status(StatusCode::INVALID_ARGUMENT, ""); } - auto server = CreateServer(args.setup(), server_port_); + auto server = CreateServer(args.setup()); if (!server) { return Status(StatusCode::INVALID_ARGUMENT, ""); } ServerStatus status; - status.set_port(server_port_); + status.set_port(server->port()); + status.set_cores(server->cores()); if (!stream->Write(status)) { return Status(StatusCode::UNKNOWN, ""); } @@ -204,21 +208,19 @@ class WorkerImpl GRPC_FINAL : public Worker::Service { if (!args.has_mark()) { return Status(StatusCode::INVALID_ARGUMENT, ""); } - *status.mutable_stats() = server->Mark(); + *status.mutable_stats() = server->Mark(args.mark().reset()); stream->Write(status); } return Status::OK; } - const int server_port_; - std::mutex mu_; bool acquired_; }; -QpsWorker::QpsWorker(int driver_port, int server_port) { - impl_.reset(new WorkerImpl(server_port)); +QpsWorker::QpsWorker(int driver_port) { + impl_.reset(new WorkerServiceImpl()); char* server_address = NULL; gpr_join_host_port(&server_address, "::", driver_port); diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h index 861588907ec..0db88ad3d13 100644 --- a/test/cpp/qps/qps_worker.h +++ b/test/cpp/qps/qps_worker.h @@ -42,15 +42,15 @@ class Server; namespace testing { -class WorkerImpl; +class WorkerServiceImpl; class QpsWorker { public: - QpsWorker(int driver_port, int server_port); + explicit QpsWorker(int driver_port); ~QpsWorker(); private: - std::unique_ptr impl_; + std::unique_ptr impl_; std::unique_ptr server_; }; diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc index e03e8e1fb08..b230eb441e8 100644 --- a/test/cpp/qps/report.cc +++ b/test/cpp/qps/report.cc @@ -43,6 +43,7 @@ namespace testing { static double WallTime(ResourceUsage u) { return u.wall_time(); } static double UserTime(ResourceUsage u) { return u.user_time(); } static double SystemTime(ResourceUsage u) { return u.system_time(); } +static int Cores(ResourceUsage u) { return u.cores(); } void CompositeReporter::add(std::unique_ptr reporter) { reporters_.emplace_back(std::move(reporter)); @@ -83,7 +84,7 @@ void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) { result.latencies.Count() / average(result.client_resources, WallTime); gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps, - qps / result.server_config.threads()); + qps / sum(result.server_resources, Cores)); } void GprLogReporter::ReportLatency(const ScenarioResult& result) { @@ -123,10 +124,10 @@ void PerfDbReporter::ReportQPSPerCore(const ScenarioResult& result) { auto qps = result.latencies.Count() / average(result.client_resources, WallTime); - auto qpsPerCore = qps / result.server_config.threads(); + auto qps_per_core = qps / sum(result.server_resources, Cores); perf_db_client_.setQps(qps); - perf_db_client_.setQpsPerCore(qpsPerCore); + perf_db_client_.setQpsPerCore(qps_per_core); perf_db_client_.setConfigs(result.client_config, result.server_config); } diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h index 00d12369d54..78779231d38 100644 --- a/test/cpp/qps/report.h +++ b/test/cpp/qps/report.h @@ -41,7 +41,6 @@ #include #include "test/cpp/qps/driver.h" -#include "test/proto/qpstest.grpc.pb.h" #include "test/cpp/qps/perf_db_client.h" namespace grpc { diff --git a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc new file mode 100644 index 00000000000..df06f7e471f --- /dev/null +++ b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc @@ -0,0 +1,84 @@ +/* + * + * 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 + +#include + +#include "test/cpp/qps/driver.h" +#include "test/cpp/qps/report.h" +#include "test/cpp/util/benchmark_config.h" + +namespace grpc { +namespace testing { + +static const int WARMUP = 5; +static const int BENCHMARK = 10; + +static void RunSynchronousUnaryPingPong() { + gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(SYNC_CLIENT); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_rpc_type(UNARY); + client_config.mutable_load_params()->mutable_closed_loop(); + + ServerConfig server_config; + server_config.set_server_type(SYNC_SERVER); + + // Set up security params + SecurityParams security; + security.set_use_test_ca(true); + security.set_server_host_override("foo.test.google.fr"); + client_config.mutable_security_params()->CopyFrom(security); + server_config.mutable_security_params()->CopyFrom(security); + + const auto result = + RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); + + GetReporter()->ReportQPS(*result); + GetReporter()->ReportLatency(*result); +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc::testing::InitBenchmark(&argc, &argv, true); + + grpc::testing::RunSynchronousUnaryPingPong(); + + return 0; +} diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h index e48e873dc33..6e81edc8ffe 100644 --- a/test/cpp/qps/server.h +++ b/test/cpp/qps/server.h @@ -34,22 +34,38 @@ #ifndef TEST_QPS_SERVER_H #define TEST_QPS_SERVER_H +#include +#include + +#include "test/core/end2end/data/ssl_test_data.h" +#include "test/core/util/port.h" #include "test/cpp/qps/timer.h" -#include "test/proto/qpstest.grpc.pb.h" +#include "test/proto/messages.grpc.pb.h" +#include "test/proto/benchmarks/control.grpc.pb.h" namespace grpc { namespace testing { class Server { public: - Server() : timer_(new Timer) {} + explicit Server(const ServerConfig& config) : timer_(new Timer) { + if (config.port()) { + port_ = config.port(); + } else { + port_ = grpc_pick_unused_port_or_die(); + } + } virtual ~Server() {} - ServerStats Mark() { - std::unique_ptr timer(new Timer); - timer.swap(timer_); - - auto timer_result = timer->Mark(); + ServerStats Mark(bool reset) { + Timer::Result timer_result; + if (reset) { + std::unique_ptr timer(new Timer); + timer.swap(timer_); + timer_result = timer->Mark(); + } else { + timer_result = timer_->Mark(); + } ServerStats stats; stats.set_time_elapsed(timer_result.wall); @@ -70,13 +86,29 @@ class Server { return true; } + int port() const { return port_; } + int cores() const { return gpr_cpu_num_cores(); } + static std::shared_ptr CreateServerCredentials( + const ServerConfig& config) { + if (config.has_security_params()) { + SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, + test_server1_cert}; + SslServerCredentialsOptions ssl_opts; + ssl_opts.pem_root_certs = ""; + ssl_opts.pem_key_cert_pairs.push_back(pkcp); + return SslServerCredentials(ssl_opts); + } else { + return InsecureServerCredentials(); + } + } + private: + int port_; std::unique_ptr timer_; }; -std::unique_ptr CreateSynchronousServer(const ServerConfig& config, - int port); -std::unique_ptr CreateAsyncServer(const ServerConfig& config, int port); +std::unique_ptr CreateSynchronousServer(const ServerConfig& config); +std::unique_ptr CreateAsyncServer(const ServerConfig& config); } // namespace testing } // namespace grpc diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 98fa9c53e25..2d922fa6150 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -49,38 +49,40 @@ #include #include -#include "test/proto/qpstest.grpc.pb.h" #include "test/cpp/qps/server.h" +#include "test/proto/benchmarks/services.grpc.pb.h" namespace grpc { namespace testing { class AsyncQpsServerTest : public Server { public: - AsyncQpsServerTest(const ServerConfig &config, int port) { + explicit AsyncQpsServerTest(const ServerConfig &config) : Server(config) { char *server_address = NULL; - gpr_join_host_port(&server_address, "::", port); + + gpr_join_host_port(&server_address, "::", port()); ServerBuilder builder; - builder.AddListeningPort(server_address, InsecureServerCredentials()); + builder.AddListeningPort(server_address, + Server::CreateServerCredentials(config)); gpr_free(server_address); builder.RegisterAsyncService(&async_service_); - for (int i = 0; i < config.threads(); i++) { + for (int i = 0; i < config.async_server_threads(); i++) { srv_cqs_.emplace_back(builder.AddCompletionQueue()); } server_ = builder.BuildAndStart(); using namespace std::placeholders; - for (int i = 0; i < 10000 / config.threads(); i++) { - for (int j = 0; j < config.threads(); j++) { + for (int i = 0; i < 10000 / config.async_server_threads(); i++) { + for (int j = 0; j < config.async_server_threads(); j++) { auto request_unary = std::bind( - &TestService::AsyncService::RequestUnaryCall, &async_service_, _1, - _2, _3, srv_cqs_[j].get(), srv_cqs_[j].get(), _4); + &BenchmarkService::AsyncService::RequestUnaryCall, &async_service_, + _1, _2, _3, srv_cqs_[j].get(), srv_cqs_[j].get(), _4); auto request_streaming = std::bind( - &TestService::AsyncService::RequestStreamingCall, &async_service_, - _1, _2, srv_cqs_[j].get(), srv_cqs_[j].get(), _3); + &BenchmarkService::AsyncService::RequestStreamingCall, + &async_service_, _1, _2, srv_cqs_[j].get(), srv_cqs_[j].get(), _3); contexts_.push_front( new ServerRpcContextUnaryImpl( request_unary, ProcessRPC)); @@ -89,10 +91,10 @@ class AsyncQpsServerTest : public Server { request_streaming, ProcessRPC)); } } - for (int i = 0; i < config.threads(); i++) { + for (int i = 0; i < config.async_server_threads(); i++) { shutdown_state_.emplace_back(new PerThreadShutdownState()); } - for (int i = 0; i < config.threads(); i++) { + for (int i = 0; i < config.async_server_threads(); i++) { threads_.emplace_back(&AsyncQpsServerTest::ThreadFunc, this, i); } } @@ -309,7 +311,7 @@ class AsyncQpsServerTest : public Server { std::vector threads_; std::unique_ptr server_; std::vector> srv_cqs_; - TestService::AsyncService async_service_; + BenchmarkService::AsyncService async_service_; std::forward_list contexts_; class PerThreadShutdownState { @@ -333,9 +335,8 @@ class AsyncQpsServerTest : public Server { std::vector> shutdown_state_; }; -std::unique_ptr CreateAsyncServer(const ServerConfig &config, - int port) { - return std::unique_ptr(new AsyncQpsServerTest(config, port)); +std::unique_ptr CreateAsyncServer(const ServerConfig &config) { + return std::unique_ptr(new AsyncQpsServerTest(config)); } } // namespace testing diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index b760ef63ec5..a09b174b7e0 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -43,14 +43,14 @@ #include #include -#include "test/proto/qpstest.grpc.pb.h" #include "test/cpp/qps/server.h" #include "test/cpp/qps/timer.h" +#include "test/proto/benchmarks/services.grpc.pb.h" namespace grpc { namespace testing { -class TestServiceImpl GRPC_FINAL : public TestService::Service { +class BenchmarkServiceImpl GRPC_FINAL : public BenchmarkService::Service { public: Status UnaryCall(ServerContext* context, const SimpleRequest* request, SimpleResponse* response) GRPC_OVERRIDE { @@ -84,30 +84,29 @@ class TestServiceImpl GRPC_FINAL : public TestService::Service { class SynchronousServer GRPC_FINAL : public grpc::testing::Server { public: - SynchronousServer(const ServerConfig& config, int port) - : impl_(MakeImpl(port)) {} - - private: - std::unique_ptr MakeImpl(int port) { + explicit SynchronousServer(const ServerConfig& config) : Server(config) { ServerBuilder builder; char* server_address = NULL; - gpr_join_host_port(&server_address, "::", port); - builder.AddListeningPort(server_address, InsecureServerCredentials()); + + gpr_join_host_port(&server_address, "::", port()); + builder.AddListeningPort(server_address, + Server::CreateServerCredentials(config)); gpr_free(server_address); builder.RegisterService(&service_); - return builder.BuildAndStart(); + impl_ = builder.BuildAndStart(); } - TestServiceImpl service_; + private: + BenchmarkServiceImpl service_; std::unique_ptr impl_; }; std::unique_ptr CreateSynchronousServer( - const ServerConfig& config, int port) { - return std::unique_ptr(new SynchronousServer(config, port)); + const ServerConfig& config) { + return std::unique_ptr(new SynchronousServer(config)); } } // namespace testing diff --git a/test/cpp/qps/single_run_localhost.sh b/test/cpp/qps/single_run_localhost.sh index 9d76f08f800..f5356f18343 100755 --- a/test/cpp/qps/single_run_localhost.sh +++ b/test/cpp/qps/single_run_localhost.sh @@ -42,9 +42,9 @@ NUMCPUS=`python2.7 -c 'import multiprocessing; print multiprocessing.cpu_count() make CONFIG=$config qps_worker qps_driver -j$NUMCPUS -bins/$config/qps_worker -driver_port 10000 -server_port 10001 & +bins/$config/qps_worker -driver_port 10000 & PID1=$! -bins/$config/qps_worker -driver_port 10010 -server_port 10011 & +bins/$config/qps_worker -driver_port 10010 & PID2=$! export QPS_WORKERS="localhost:10000,localhost:10010" diff --git a/test/cpp/qps/sync_streaming_ping_pong_test.cc b/test/cpp/qps/sync_streaming_ping_pong_test.cc index 52e43939a81..186afc03f7c 100644 --- a/test/cpp/qps/sync_streaming_ping_pong_test.cc +++ b/test/cpp/qps/sync_streaming_ping_pong_test.cc @@ -31,8 +31,6 @@ * */ -#include - #include #include @@ -51,17 +49,14 @@ static void RunSynchronousStreamingPingPong() { gpr_log(GPR_INFO, "Running Synchronous Streaming Ping Pong"); ClientConfig client_config; - client_config.set_client_type(SYNCHRONOUS_CLIENT); - client_config.set_enable_ssl(false); + client_config.set_client_type(SYNC_CLIENT); client_config.set_outstanding_rpcs_per_channel(1); client_config.set_client_channels(1); - client_config.set_payload_size(1); client_config.set_rpc_type(STREAMING); + client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; - server_config.set_server_type(SYNCHRONOUS_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(1); + server_config.set_server_type(SYNC_SERVER); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -75,7 +70,6 @@ static void RunSynchronousStreamingPingPong() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::RunSynchronousStreamingPingPong(); return 0; diff --git a/test/cpp/qps/sync_unary_ping_pong_test.cc b/test/cpp/qps/sync_unary_ping_pong_test.cc index fbd21357aa5..25851833a6d 100644 --- a/test/cpp/qps/sync_unary_ping_pong_test.cc +++ b/test/cpp/qps/sync_unary_ping_pong_test.cc @@ -31,8 +31,6 @@ * */ -#include - #include #include @@ -51,17 +49,14 @@ static void RunSynchronousUnaryPingPong() { gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong"); ClientConfig client_config; - client_config.set_client_type(SYNCHRONOUS_CLIENT); - client_config.set_enable_ssl(false); + client_config.set_client_type(SYNC_CLIENT); client_config.set_outstanding_rpcs_per_channel(1); client_config.set_client_channels(1); - client_config.set_payload_size(1); client_config.set_rpc_type(UNARY); + client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; - server_config.set_server_type(SYNCHRONOUS_SERVER); - server_config.set_enable_ssl(false); - server_config.set_threads(1); + server_config.set_server_type(SYNC_SERVER); const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); @@ -76,7 +71,6 @@ static void RunSynchronousUnaryPingPong() { int main(int argc, char** argv) { grpc::testing::InitBenchmark(&argc, &argv, true); - signal(SIGPIPE, SIG_IGN); grpc::testing::RunSynchronousUnaryPingPong(); return 0; diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc index 8edb838da37..3ec7f49f832 100644 --- a/test/cpp/qps/timer.cc +++ b/test/cpp/qps/timer.cc @@ -61,7 +61,7 @@ Timer::Result Timer::Sample() { return r; } -Timer::Result Timer::Mark() { +Timer::Result Timer::Mark() const { Result s = Sample(); Result r; r.wall = s.wall - start_.wall; diff --git a/test/cpp/qps/timer.h b/test/cpp/qps/timer.h index 30dbd7e7d50..d1aee1a9d19 100644 --- a/test/cpp/qps/timer.h +++ b/test/cpp/qps/timer.h @@ -44,7 +44,7 @@ class Timer { double system; }; - Result Mark(); + Result Mark() const; static double Now(); diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc index 935e4853a62..430ffb7cdc2 100644 --- a/test/cpp/qps/worker.cc +++ b/test/cpp/qps/worker.cc @@ -43,8 +43,7 @@ #include "test/cpp/qps/qps_worker.h" #include "test/cpp/util/test_config.h" -DEFINE_int32(driver_port, 0, "Driver server port."); -DEFINE_int32(server_port, 0, "Spawned server port."); +DEFINE_int32(driver_port, 0, "Port for communication with driver"); static bool got_sigint = false; @@ -54,7 +53,7 @@ namespace grpc { namespace testing { static void RunServer() { - QpsWorker worker(FLAGS_driver_port, FLAGS_server_port); + QpsWorker worker(FLAGS_driver_port); while (!got_sigint) { gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), diff --git a/test/proto/qpstest.proto b/test/proto/benchmarks/control.proto similarity index 51% rename from test/proto/qpstest.proto rename to test/proto/benchmarks/control.proto index ef1f9451e9a..966ab78baae 100644 --- a/test/proto/qpstest.proto +++ b/test/proto/benchmarks/control.proto @@ -1,4 +1,3 @@ - // Copyright 2015, Google Inc. // All rights reserved. // @@ -28,62 +27,20 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// An integration test service that covers all the method signature permutations -// of unary/streaming requests/responses. syntax = "proto3"; -package grpc.testing; - -enum PayloadType { - // Compressable text format. - COMPRESSABLE = 0; - - // Uncompressable binary format. - UNCOMPRESSABLE = 1; - - // Randomly chosen from all other formats defined in this enum. - RANDOM = 2; -} - -message StatsRequest { - // run number - int32 test_num = 1; -} - -message ServerStats { - // wall clock time - double time_elapsed = 1; - - // user time used by the server process and threads - double time_user = 2; - - // server time used by the server process and all threads - double time_system = 3; -} - -message Payload { - // The type of data in body. - PayloadType type = 1; - // Primary contents of payload. - bytes body = 2; -} +import "test/proto/benchmarks/payloads.proto"; +import "test/proto/benchmarks/stats.proto"; -message HistogramData { - repeated uint32 bucket = 1; - double min_seen = 2; - double max_seen = 3; - double sum = 4; - double sum_of_squares = 5; - double count = 6; -} +package grpc.testing; enum ClientType { - SYNCHRONOUS_CLIENT = 0; + SYNC_CLIENT = 0; ASYNC_CLIENT = 1; } enum ServerType { - SYNCHRONOUS_SERVER = 0; + SYNC_SERVER = 0; ASYNC_SERVER = 1; } @@ -92,14 +49,6 @@ enum RpcType { STREAMING = 1; } -enum LoadType { - CLOSED_LOOP = 0; - POISSON = 1; - UNIFORM = 2; - DETERMINISTIC = 3; - PARETO = 4; -} - message PoissonParams { double offered_load = 1; } @@ -118,32 +67,45 @@ message ParetoParams { double alpha = 2; } +message ClosedLoopParams { +} + message LoadParams { oneof load { - PoissonParams poisson = 1; - UniformParams uniform = 2; - DeterministicParams determ = 3; - ParetoParams pareto = 4; + ClosedLoopParams closed_loop = 1; + PoissonParams poisson = 2; + UniformParams uniform = 3; + DeterministicParams determ = 4; + ParetoParams pareto = 5; }; } +// presence of SecurityParams implies use of TLS +message SecurityParams { + bool use_test_ca = 1; + string server_host_override = 2; +} + message ClientConfig { repeated string server_targets = 1; ClientType client_type = 2; - bool enable_ssl = 3; + SecurityParams security_params = 3; int32 outstanding_rpcs_per_channel = 4; int32 client_channels = 5; - int32 payload_size = 6; // only for async client: int32 async_client_threads = 7; RpcType rpc_type = 8; - string host = 9; - LoadType load_type = 10; - LoadParams load_params = 11; + LoadParams load_params = 10; + PayloadConfig payload_config = 11; +} + +message ClientStatus { + ClientStats stats = 1; } // Request current stats message Mark { + bool reset = 1; } message ClientArgs { @@ -153,22 +115,15 @@ message ClientArgs { } } -message ClientStats { - HistogramData latencies = 1; - double time_elapsed = 2; - double time_user = 3; - double time_system = 4; -} - -message ClientStatus { - ClientStats stats = 1; -} - message ServerConfig { ServerType server_type = 1; - int32 threads = 2; - bool enable_ssl = 3; - string host = 4; + SecurityParams security_params = 2; + int32 port = 4; + // only for async server + int32 async_server_threads = 7; + // restrict core usage + int32 core_limit = 8; + PayloadConfig payload_config = 9; } message ServerArgs { @@ -181,38 +136,5 @@ message ServerArgs { message ServerStatus { ServerStats stats = 1; int32 port = 2; -} - -message SimpleRequest { - // Desired payload type in the response from the server. - // If response_type is RANDOM, server randomly chooses one from other formats. - PayloadType response_type = 1; - - // Desired payload size in the response from the server. - // If response_type is COMPRESSABLE, this denotes the size before compression. - int32 response_size = 2; - - // Optional input payload sent along with the request. - Payload payload = 3; -} - -message SimpleResponse { - Payload payload = 1; -} - -service TestService { - // One request followed by one response. - // The server returns the client payload as-is. - rpc UnaryCall(SimpleRequest) returns (SimpleResponse); - - // One request followed by one response. - // The server returns the client payload as-is. - rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse); -} - -service Worker { - // Start test with specified workload - rpc RunTest(stream ClientArgs) returns (stream ClientStatus); - // Start test with specified workload - rpc RunServer(stream ServerArgs) returns (stream ServerStatus); + int32 cores = 3; } diff --git a/test/proto/benchmarks/payloads.proto b/test/proto/benchmarks/payloads.proto new file mode 100644 index 00000000000..7e5b2c61ff7 --- /dev/null +++ b/test/proto/benchmarks/payloads.proto @@ -0,0 +1,55 @@ +// 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. + +syntax = "proto3"; + +package grpc.testing; + +message ByteBufferParams { + int32 req_size = 1; + int32 resp_size = 2; +} + +message SimpleProtoParams { + int32 req_size = 1; + int32 resp_size = 2; +} + +message ComplexProtoParams { + // TODO (vpai): Fill this in once the details of complex, representative + // protos are decided +} + +message PayloadConfig { + oneof payload { + ByteBufferParams bytebuf_params = 1; + SimpleProtoParams simple_params = 2; + ComplexProtoParams complex_params = 3; + } +} diff --git a/test/proto/benchmarks/services.proto b/test/proto/benchmarks/services.proto new file mode 100644 index 00000000000..4c2cbabdf87 --- /dev/null +++ b/test/proto/benchmarks/services.proto @@ -0,0 +1,55 @@ +// 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. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. +syntax = "proto3"; + +import "test/proto/messages.proto"; +import "test/proto/benchmarks/control.proto"; + +package grpc.testing; + +service BenchmarkService { + // One request followed by one response. + // The server returns the client payload as-is. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by one response. + // The server returns the client payload as-is. + rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse); +} + +service WorkerService { + // Start server with specified workload + rpc RunServer(stream ServerArgs) returns (stream ServerStatus); + + // Start client with specified workload + rpc RunClient(stream ClientArgs) returns (stream ClientStatus); +} diff --git a/test/proto/benchmarks/stats.proto b/test/proto/benchmarks/stats.proto new file mode 100644 index 00000000000..d52144f3214 --- /dev/null +++ b/test/proto/benchmarks/stats.proto @@ -0,0 +1,59 @@ +// 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. + +syntax = "proto3"; + +package grpc.testing; + +message ServerStats { + // wall clock time + double time_elapsed = 1; + + // user time used by the server process and threads + double time_user = 2; + + // server time used by the server process and all threads + double time_system = 3; +} + +message HistogramData { + repeated uint32 bucket = 1; + double min_seen = 2; + double max_seen = 3; + double sum = 4; + double sum_of_squares = 5; + double count = 6; +} + +message ClientStats { + HistogramData latencies = 1; + double time_elapsed = 2; + double time_user = 3; + double time_system = 4; +} diff --git a/tools/http2_interop/http2interop.go b/tools/http2_interop/http2interop.go index f1bca7fe13d..8585a044e53 100644 --- a/tools/http2_interop/http2interop.go +++ b/tools/http2_interop/http2interop.go @@ -2,15 +2,38 @@ package http2interop import ( "crypto/tls" + "crypto/x509" "fmt" "io" - "log" + "net" + "testing" + "time" ) const ( Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" ) +var ( + defaultTimeout = 1 * time.Second +) + +type HTTP2InteropCtx struct { + // Inputs + ServerHost string + ServerPort int + UseTLS bool + UseTestCa bool + ServerHostnameOverride string + + T *testing.T + + // Derived + serverSpec string + authority string + rootCAs *x509.CertPool +} + func parseFrame(r io.Reader) (Frame, error) { fh := FrameHeader{} if err := fh.Parse(r); err != nil { @@ -49,22 +72,8 @@ func streamFrame(w io.Writer, f Frame) error { return nil } -func getHttp2Conn(addr string) (*tls.Conn, error) { - config := &tls.Config{ - InsecureSkipVerify: true, - NextProtos: []string{"h2"}, - } - - conn, err := tls.Dial("tcp", addr, config) - if err != nil { - return nil, err - } - - return conn, nil -} - -func testClientShortSettings(addr string, length int) error { - c, err := getHttp2Conn(addr) +func testClientShortSettings(ctx *HTTP2InteropCtx, length int) error { + c, err := connect(ctx) if err != nil { return err } @@ -82,22 +91,22 @@ func testClientShortSettings(addr string, length int) error { Data: make([]byte, length), } if err := streamFrame(c, sf); err != nil { + ctx.T.Log("Unable to stream frame", sf) return err } for { - frame, err := parseFrame(c) - if err != nil { + if _, err := parseFrame(c); err != nil { + ctx.T.Log("Unable to parse frame") return err } - log.Println(frame) } return nil } -func testClientPrefaceWithStreamId(addr string) error { - c, err := getHttp2Conn(addr) +func testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error { + c, err := connect(ctx) if err != nil { return err } @@ -119,18 +128,16 @@ func testClientPrefaceWithStreamId(addr string) error { } for { - frame, err := parseFrame(c) - if err != nil { + if _, err := parseFrame(c); err != nil { return err } - log.Println(frame) } return nil } -func testUnknownFrameType(addr string) error { - c, err := getHttp2Conn(addr) +func testUnknownFrameType(ctx *HTTP2InteropCtx) error { + c, err := connect(ctx) if err != nil { return err } @@ -143,6 +150,7 @@ func testUnknownFrameType(addr string) error { // Send some settings, which are part of the client preface sf := &SettingsFrame{} if err := streamFrame(c, sf); err != nil { + ctx.T.Log("Unable to stream frame", sf) return err } @@ -154,6 +162,7 @@ func testUnknownFrameType(addr string) error { }, } if err := streamFrame(c, fh); err != nil { + ctx.T.Log("Unable to stream frame", fh) return err } } @@ -162,12 +171,14 @@ func testUnknownFrameType(addr string) error { Data: []byte("01234567"), } if err := streamFrame(c, pf); err != nil { + ctx.T.Log("Unable to stream frame", sf) return err } for { frame, err := parseFrame(c) if err != nil { + ctx.T.Log("Unable to parse frame") return err } if npf, ok := frame.(*PingFrame); !ok { @@ -183,8 +194,8 @@ func testUnknownFrameType(addr string) error { return nil } -func testShortPreface(addr string, prefacePrefix string) error { - c, err := getHttp2Conn(addr) +func testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error { + c, err := connect(ctx) if err != nil { return err } @@ -201,17 +212,15 @@ func testShortPreface(addr string, prefacePrefix string) error { return err } -func testTLSMaxVersion(addr string, version uint16) error { - config := &tls.Config{ - InsecureSkipVerify: true, - NextProtos: []string{"h2"}, - MaxVersion: version, - } - conn, err := tls.Dial("tcp", addr, config) +func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error { + config := buildTlsConfig(ctx) + config.MaxVersion = version + conn, err := connectWithTls(ctx, config) if err != nil { return err } defer conn.Close() + conn.SetDeadline(time.Now().Add(defaultTimeout)) buf := make([]byte, 256) if n, err := conn.Read(buf); err != nil { @@ -223,16 +232,15 @@ func testTLSMaxVersion(addr string, version uint16) error { return nil } -func testTLSApplicationProtocol(addr string) error { - config := &tls.Config{ - InsecureSkipVerify: true, - NextProtos: []string{"h2c"}, - } - conn, err := tls.Dial("tcp", addr, config) +func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error { + config := buildTlsConfig(ctx) + config.NextProtos = []string{"h2c"} + conn, err := connectWithTls(ctx, config) if err != nil { return err } defer conn.Close() + conn.SetDeadline(time.Now().Add(defaultTimeout)) buf := make([]byte, 256) if n, err := conn.Read(buf); err != nil { @@ -243,3 +251,48 @@ func testTLSApplicationProtocol(addr string) error { } return nil } + +func connect(ctx *HTTP2InteropCtx) (net.Conn, error) { + var conn net.Conn + var err error + if !ctx.UseTLS { + conn, err = connectWithoutTls(ctx) + } else { + config := buildTlsConfig(ctx) + conn, err = connectWithTls(ctx, config) + } + if err != nil { + return nil, err + } + conn.SetDeadline(time.Now().Add(defaultTimeout)) + + return conn, nil +} + +func buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config { + return &tls.Config{ + RootCAs: ctx.rootCAs, + NextProtos: []string{"h2"}, + ServerName: ctx.authority, + MinVersion: tls.VersionTLS12, + // TODO(carl-mastrangelo): remove this once all test certificates have been updated. + InsecureSkipVerify: true, + } +} + +func connectWithoutTls(ctx *HTTP2InteropCtx) (net.Conn, error) { + conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout) + if err != nil { + return nil, err + } + return conn, nil +} + +func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*tls.Conn, error) { + conn, err := connectWithoutTls(ctx) + if err != nil { + return nil, err + } + + return tls.Client(conn, config), nil +} diff --git a/tools/http2_interop/http2interop_test.go b/tools/http2_interop/http2interop_test.go index 3b687c035e8..dc2960048f1 100644 --- a/tools/http2_interop/http2interop_test.go +++ b/tools/http2_interop/http2interop_test.go @@ -2,46 +2,117 @@ package http2interop import ( "crypto/tls" + "crypto/x509" + "strings" "flag" + "fmt" "io" + "io/ioutil" "os" + "strconv" "testing" ) var ( - serverSpec = flag.String("spec", ":50051", "The server spec to test") + serverHost = flag.String("server_host", "", "The host to test") + serverPort = flag.Int("server_port", 443, "The port to test") + useTls = flag.Bool("use_tls", true, "Should TLS tests be run") + // TODO: implement + testCase = flag.String("test_case", "", "What test cases to run") + + // The rest of these are unused, but present to fulfill the client interface + serverHostOverride = flag.String("server_host_override", "", "Unused") + useTestCa = flag.Bool("use_test_ca", false, "Unused") + defaultServiceAccount = flag.String("default_service_account", "", "Unused") + oauthScope = flag.String("oauth_scope", "", "Unused") + serviceAccountKeyFile = flag.String("service_account_key_file", "", "Unused") ) +func InteropCtx(t *testing.T) *HTTP2InteropCtx { + ctx := &HTTP2InteropCtx{ + ServerHost: *serverHost, + ServerPort: *serverPort, + ServerHostnameOverride: *serverHostOverride, + UseTLS: *useTls, + UseTestCa: *useTestCa, + T: t, + } + + ctx.serverSpec = ctx.ServerHost + if ctx.ServerPort != -1 { + ctx.serverSpec += ":" + strconv.Itoa(ctx.ServerPort) + } + if ctx.ServerHostnameOverride == "" { + ctx.authority = ctx.ServerHost + } else { + ctx.authority = ctx.ServerHostnameOverride + } + + if ctx.UseTestCa { + // It would be odd if useTestCa was true, but not useTls. meh + certData, err := ioutil.ReadFile("src/core/tsi/test_creds/ca.pem") + if err != nil { + t.Fatal(err) + } + + ctx.rootCAs = x509.NewCertPool() + if !ctx.rootCAs.AppendCertsFromPEM(certData) { + t.Fatal(fmt.Errorf("Unable to parse pem data")) + } + } + + return ctx +} + +func (ctx *HTTP2InteropCtx) Close() error { + // currently a noop + return nil +} + func TestShortPreface(t *testing.T) { + ctx := InteropCtx(t) for i := 0; i < len(Preface)-1; i++ { - if err := testShortPreface(*serverSpec, Preface[:i]+"X"); err != io.EOF { + if err := testShortPreface(ctx, Preface[:i]+"X"); err != io.EOF { t.Error("Expected an EOF but was", err) } } } func TestUnknownFrameType(t *testing.T) { - if err := testUnknownFrameType(*serverSpec); err != nil { + ctx := InteropCtx(t) + if err := testUnknownFrameType(ctx); err != nil { t.Fatal(err) } } func TestTLSApplicationProtocol(t *testing.T) { - if err := testTLSApplicationProtocol(*serverSpec); err != io.EOF { - t.Fatal("Expected an EOF but was", err) - } + ctx := InteropCtx(t) + err := testTLSApplicationProtocol(ctx); + matchError(t, err, "EOF") } func TestTLSMaxVersion(t *testing.T) { - if err := testTLSMaxVersion(*serverSpec, tls.VersionTLS11); err != io.EOF { - t.Fatal("Expected an EOF but was", err) - } + ctx := InteropCtx(t) + err := testTLSMaxVersion(ctx, tls.VersionTLS11); + matchError(t, err, "EOF", "server selected unsupported protocol") } func TestClientPrefaceWithStreamId(t *testing.T) { - if err := testClientPrefaceWithStreamId(*serverSpec); err != io.EOF { - t.Fatal("Expected an EOF but was", err) - } + ctx := InteropCtx(t) + err := testClientPrefaceWithStreamId(ctx) + matchError(t, err, "EOF") +} + +func matchError(t *testing.T, err error, matches ... string) { + if err == nil { + t.Fatal("Expected an error") + } + for _, s := range matches { + if strings.Contains(err.Error(), s) { + return + } + } + t.Fatalf("Error %v not in %+v", err, matches) } func TestMain(m *testing.M) { diff --git a/tools/jenkins/build_docker_and_run_tests.sh b/tools/jenkins/build_docker_and_run_tests.sh index 5bb2b6b1886..b44c3805330 100755 --- a/tools/jenkins/build_docker_and_run_tests.sh +++ b/tools/jenkins/build_docker_and_run_tests.sh @@ -63,6 +63,7 @@ docker run \ -e "arch=$arch" \ -e CCACHE_DIR=/tmp/ccache \ -e XDG_CACHE_HOME=/tmp/xdg-cache-home \ + -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \ -i $TTY_FLAG \ -v "$git_root:/var/local/jenkins/grpc" \ -v /tmp/ccache:/tmp/ccache \ diff --git a/tools/jenkins/build_interop_image.sh b/tools/jenkins/build_interop_image.sh index 5dfa2425134..d0c5470ed6b 100755 --- a/tools/jenkins/build_interop_image.sh +++ b/tools/jenkins/build_interop_image.sh @@ -84,6 +84,7 @@ CONTAINER_NAME="build_${BASE_NAME}_$(uuidgen)" # Prepare image for interop tests, commit it on success. (docker run \ -e CCACHE_DIR=/tmp/ccache \ + -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \ -i $TTY_FLAG \ $MOUNT_ARGS \ $BUILD_INTEROP_DOCKER_EXTRA_ARGS \ diff --git a/tools/jenkins/grpc_interop_http2/Dockerfile b/tools/jenkins/grpc_interop_http2/Dockerfile new file mode 100644 index 00000000000..bb60f09f247 --- /dev/null +++ b/tools/jenkins/grpc_interop_http2/Dockerfile @@ -0,0 +1,36 @@ +# 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. + +FROM golang:1.4 + +# Using login shell removes Go from path, so we add it. +RUN ln -s /usr/src/go/bin/go /usr/local/bin + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/grpc_interop_http2/build_interop.sh b/tools/jenkins/grpc_interop_http2/build_interop.sh new file mode 100755 index 00000000000..46ddaf929a8 --- /dev/null +++ b/tools/jenkins/grpc_interop_http2/build_interop.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# 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. +# +# Builds http2 interop client in a base image. +set -e + +mkdir -p /var/local/git +git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc + +# copy service account keys if available +cp -r /var/local/jenkins/service_account $HOME || true + +# compile the tests +(cd /var/local/git/grpc/tools/http2_interop && go test -c) + diff --git a/tools/jenkins/run_interop.sh b/tools/jenkins/run_interop.sh index 5dd477ed77a..a424aea7fc4 100755 --- a/tools/jenkins/run_interop.sh +++ b/tools/jenkins/run_interop.sh @@ -34,4 +34,4 @@ set -ex # Enter the gRPC repo root cd $(dirname $0)/../.. -tools/run_tests/run_interop_tests.py -l all -s all --cloud_to_prod --cloud_to_prod_auth --use_docker -t -j 12 $@ || true +tools/run_tests/run_interop_tests.py -l all -s all --cloud_to_prod --cloud_to_prod_auth --use_docker --http2_interop -t -j 12 $@ || true diff --git a/tools/run_tests/build_csharp.sh b/tools/run_tests/build_csharp.sh index 6737d88b273..2c333517922 100755 --- a/tools/run_tests/build_csharp.sh +++ b/tools/run_tests/build_csharp.sh @@ -30,7 +30,7 @@ set -ex -if [ "$CONFIG" = "dbg" ] +if [ "$CONFIG" = "dbg" ] || [ "$CONFIG" = "gcov" ] then MSBUILD_CONFIG="Debug" else diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py index 1d67fe3033e..7d64222ba0b 100755 --- a/tools/run_tests/dockerjob.py +++ b/tools/run_tests/dockerjob.py @@ -101,7 +101,7 @@ class DockerJob: def __init__(self, spec): self._spec = spec - self._job = jobset.Job(spec, bin_hash=None, newline_on_success=True, travis=True, add_env={}, xml_report=None) + self._job = jobset.Job(spec, bin_hash=None, newline_on_success=True, travis=True, add_env={}) self._container_name = spec.container_name def mapped_port(self, port): diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py index 8343441a189..88d95027e28 100755 --- a/tools/run_tests/jobset.py +++ b/tools/run_tests/jobset.py @@ -34,15 +34,14 @@ import multiprocessing import os import platform import signal -import string import subprocess import sys import tempfile import time -import xml.etree.cElementTree as ET _DEFAULT_MAX_JOBS = 16 * multiprocessing.cpu_count() +_MAX_RESULT_SIZE = 8192 # setup a signal handler so that signal.pause registers 'something' @@ -130,14 +129,6 @@ def which(filename): raise Exception('%s not found' % filename) -def _filter_stdout(stdout): - """Filters out nonprintable and XML-illegal characters from stdout.""" - # keep whitespaces but remove formfeed and vertical tab characters - # that make XML report unparseable. - return filter(lambda x: x in string.printable and x != '\f' and x != '\v', - stdout.decode(errors='ignore')) - - class JobSpec(object): """Specifies what to run for a job.""" @@ -182,6 +173,7 @@ class JobResult(object): self.state = 'UNKNOWN' self.returncode = -1 self.elapsed_time = 0 + self.num_failures = 0 self.retries = 0 self.message = '' @@ -189,14 +181,12 @@ class JobResult(object): class Job(object): """Manages one job.""" - def __init__(self, spec, bin_hash, newline_on_success, travis, add_env, xml_report): + def __init__(self, spec, bin_hash, newline_on_success, travis, add_env): self._spec = spec self._bin_hash = bin_hash self._newline_on_success = newline_on_success self._travis = travis self._add_env = add_env.copy() - self._xml_test = ET.SubElement(xml_report, 'testcase', - name=self._spec.shortname) if xml_report is not None else None self._retries = 0 self._timeout_retries = 0 self._suppress_failure_message = False @@ -213,36 +203,40 @@ class Job(object): env.update(self._spec.environ) env.update(self._add_env) self._start = time.time() - self._process = subprocess.Popen(args=self._spec.cmdline, - stderr=subprocess.STDOUT, - stdout=self._tempfile, - cwd=self._spec.cwd, - shell=self._spec.shell, - env=env) + try_start = lambda: subprocess.Popen(args=self._spec.cmdline, + stderr=subprocess.STDOUT, + stdout=self._tempfile, + cwd=self._spec.cwd, + shell=self._spec.shell, + env=env) + delay = 0.3 + for i in range(0, 4): + try: + self._process = try_start() + break + except OSError: + message('WARNING', 'Failed to start %s, retrying in %f seconds' % (self._spec.shortname, delay)) + time.sleep(delay) + delay *= 2 + else: + self._process = try_start() self._state = _RUNNING def state(self, update_cache): """Poll current state of the job. Prints messages at completion.""" + self._tempfile.seek(0) + stdout = self._tempfile.read() + self.result.message = stdout[-_MAX_RESULT_SIZE:] if self._state == _RUNNING and self._process.poll() is not None: elapsed = time.time() - self._start - self._tempfile.seek(0) - stdout = self._tempfile.read() - filtered_stdout = _filter_stdout(stdout) - # TODO: looks like jenkins master is slow because parsing the junit results XMLs is not - # implemented efficiently. This is an experiment to workaround the issue by making sure - # results.xml file is small enough. - filtered_stdout = filtered_stdout[-128:] - self.result.message = filtered_stdout self.result.elapsed_time = elapsed - if self._xml_test is not None: - self._xml_test.set('time', str(elapsed)) - ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout if self._process.returncode != 0: if self._retries < self._spec.flake_retries: message('FLAKE', '%s [ret=%d, pid=%d]' % ( self._spec.shortname, self._process.returncode, self._process.pid), stdout, do_newline=True) self._retries += 1 + self.result.num_failures += 1 self.result.retries = self._timeout_retries + self._retries self.start() else: @@ -252,9 +246,8 @@ class Job(object): self._spec.shortname, self._process.returncode, self._process.pid), stdout, do_newline=True) self.result.state = 'FAILED' + self.result.num_failures += 1 self.result.returncode = self._process.returncode - if self._xml_test is not None: - ET.SubElement(self._xml_test, 'failure', message='Failure') else: self._state = _SUCCESS message('PASSED', '%s [time=%.1fsec; retries=%d;%d]' % ( @@ -264,13 +257,10 @@ class Job(object): if self._bin_hash: update_cache.finished(self._spec.identity(), self._bin_hash) elif self._state == _RUNNING and time.time() - self._start > self._spec.timeout_seconds: - self._tempfile.seek(0) - stdout = self._tempfile.read() - filtered_stdout = _filter_stdout(stdout) - self.result.message = filtered_stdout if self._timeout_retries < self._spec.timeout_retries: message('TIMEOUT_FLAKE', self._spec.shortname, stdout, do_newline=True) self._timeout_retries += 1 + self.result.num_failures += 1 self.result.retries = self._timeout_retries + self._retries if self._spec.kill_handler: self._spec.kill_handler(self) @@ -280,9 +270,7 @@ class Job(object): message('TIMEOUT', self._spec.shortname, stdout, do_newline=True) self.kill() self.result.state = 'TIMEOUT' - if self._xml_test is not None: - ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout - ET.SubElement(self._xml_test, 'error', message='Timeout') + self.result.num_failures += 1 return self._state def kill(self): @@ -294,13 +282,13 @@ class Job(object): def suppress_failure_message(self): self._suppress_failure_message = True - + class Jobset(object): """Manages one run of jobs.""" def __init__(self, check_cancelled, maxjobs, newline_on_success, travis, - stop_on_failure, add_env, cache, xml_report): + stop_on_failure, add_env, cache): self._running = set() self._check_cancelled = check_cancelled self._cancelled = False @@ -312,7 +300,6 @@ class Jobset(object): self._cache = cache self._stop_on_failure = stop_on_failure self._hashes = {} - self._xml_report = xml_report self._add_env = add_env self.resultset = {} @@ -344,10 +331,9 @@ class Jobset(object): bin_hash, self._newline_on_success, self._travis, - self._add_env, - self._xml_report) + self._add_env) self._running.add(job) - self.resultset[job.GetSpec().shortname] = None + self.resultset[job.GetSpec().shortname] = [] return True def reap(self): @@ -367,7 +353,7 @@ class Jobset(object): break for job in dead: self._completed += 1 - self.resultset[job.GetSpec().shortname] = job.result + self.resultset[job.GetSpec().shortname].append(job.result) self._running.remove(job) if dead: return if (not self._travis): @@ -419,13 +405,11 @@ def run(cmdlines, infinite_runs=False, stop_on_failure=False, cache=None, - xml_report=None, add_env={}): js = Jobset(check_cancelled, maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS, newline_on_success, travis, stop_on_failure, add_env, - cache if cache is not None else NoCache(), - xml_report) + cache if cache is not None else NoCache()) for cmdline in cmdlines: if not js.start(cmdline): break diff --git a/tools/run_tests/port_server.py b/tools/run_tests/port_server.py index 3b85486ebfe..14e82b601ea 100755 --- a/tools/run_tests/port_server.py +++ b/tools/run_tests/port_server.py @@ -42,7 +42,7 @@ import time # increment this number whenever making a change to ensure that # the changes are picked up by running CI servers # note that all changes must be backwards compatible -_MY_VERSION = 5 +_MY_VERSION = 7 if len(sys.argv) == 2 and sys.argv[1] == 'dump_version': diff --git a/tools/run_tests/post_tests_c.sh b/tools/run_tests/post_tests_c.sh index f2f3ce9432d..4409526dab2 100755 --- a/tools/run_tests/post_tests_c.sh +++ b/tools/run_tests/post_tests_c.sh @@ -34,8 +34,12 @@ if [ "$CONFIG" != "gcov" ] ; then exit ; fi root=$(readlink -f $(dirname $0)/../..) out=$root/reports/c_cxx_coverage -tmp=$(mktemp) +tmp1=$(mktemp) +tmp2=$(mktemp) cd $root -lcov --capture --directory . --output-file $tmp -genhtml $tmp --output-directory $out -rm $tmp +lcov --capture --directory . --output-file $tmp1 +lcov --extract $tmp1 "$root/src/*" "$root/include/*" --output-file $tmp2 +genhtml $tmp2 --output-directory $out +rm $tmp2 +rm $tmp1 + diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/report_utils.py new file mode 100644 index 00000000000..bb9eca42548 --- /dev/null +++ b/tools/run_tests/report_utils.py @@ -0,0 +1,215 @@ +# 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. + +"""Generate XML and HTML test reports.""" + +import os +import string +import xml.etree.cElementTree as ET + + +def _filter_msg(msg, output_format): + """Filters out nonprintable and illegal characters from the message.""" + if output_format in ['XML', 'HTML']: + # keep whitespaces but remove formfeed and vertical tab characters + # that make XML report unparseable. + filtered_msg = filter( + lambda x: x in string.printable and x != '\f' and x != '\v', + msg.decode(errors='ignore')) + if output_format == 'HTML': + filtered_msg = filtered_msg.replace('"', '"') + return filtered_msg + else: + return msg + + +def render_xml_report(resultset, xml_report): + """Generate JUnit-like XML report.""" + root = ET.Element('testsuites') + testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', + name='tests') + for shortname, results in resultset.iteritems(): + for result in results: + xml_test = ET.SubElement(testsuite, 'testcase', name=shortname) + if result.elapsed_time: + xml_test.set('time', str(result.elapsed_time)) + ET.SubElement(xml_test, 'system-out').text = _filter_msg(result.message, + 'XML') + if result.state == 'FAILED': + ET.SubElement(xml_test, 'failure', message='Failure') + elif result.state == 'TIMEOUT': + ET.SubElement(xml_test, 'error', message='Timeout') + tree = ET.ElementTree(root) + tree.write(xml_report, encoding='UTF-8') + + +# TODO(adelez): Use mako template. +def fill_one_test_result(shortname, resultset, html_str): + if shortname in resultset: + # Because interop tests does not have runs_per_test flag, each test is run + # once. So there should only be one element for each result. + result = resultset[shortname][0] + if result.state == 'PASSED': + html_str = '%sPASS\n' % html_str + else: + tooltip = '' + if result.returncode > 0 or result.message: + if result.returncode > 0: + tooltip = 'returncode: %d ' % result.returncode + if result.message: + escaped_msg = _filter_msg(result.message, 'HTML') + tooltip = '%smessage: %s' % (tooltip, escaped_msg) + if result.state == 'FAILED': + html_str = '%s' % html_str + if tooltip: + html_str = ('%sFAIL\n' % + (html_str, tooltip)) + else: + html_str = '%sFAIL\n' % html_str + elif result.state == 'TIMEOUT': + html_str = '%s' % html_str + if tooltip: + html_str = ('%sTIMEOUT\n' + % (html_str, tooltip)) + else: + html_str = '%sTIMEOUT\n' % html_str + else: + html_str = '%sNot implemented\n' % html_str + + return html_str + + +def render_html_report(client_langs, server_langs, test_cases, auth_test_cases, + http2_cases, resultset, num_failures, cloud_to_prod, + http2_interop): + """Generate html report.""" + sorted_test_cases = sorted(test_cases) + sorted_auth_test_cases = sorted(auth_test_cases) + sorted_http2_cases = sorted(http2_cases) + sorted_client_langs = sorted(client_langs) + sorted_server_langs = sorted(server_langs) + html_str = ('\n' + '\n' + 'Interop Test Result\n' + '\n') + if num_failures > 1: + html_str = ( + '%s

%d tests failed!

\n' % + (html_str, num_failures)) + elif num_failures: + html_str = ( + '%s

%d test failed!

\n' % + (html_str, num_failures)) + else: + html_str = ( + '%s

All tests passed!

\n' % + html_str) + if cloud_to_prod: + # Each column header is the client language. + html_str = ('%s

Cloud to Prod

\n' + '\n' + '\n' + '\n') % html_str + for client_lang in sorted_client_langs: + html_str = '%s\n' % html_str + for test_case in sorted_test_cases + sorted_auth_test_cases: + html_str = '%s\n' % (html_str, test_case) + for client_lang in sorted_client_langs: + if not test_case in sorted_auth_test_cases: + shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case) + else: + shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case) + html_str = fill_one_test_result(shortname, resultset, html_str) + html_str = '%s\n' % html_str + html_str = '%s
Client languages ►%s\n' % (html_str, client_lang) + html_str = '%s
%s
\n' % html_str + if http2_interop: + # Each column header is the server language. + html_str = ('%s

HTTP/2 Interop

\n' + '\n' + '\n' + '\n') % html_str + for server_lang in sorted_server_langs: + html_str = '%s\n' % html_str + for test_case in sorted_http2_cases: + html_str = '%s\n' % (html_str, test_case) + # Fill up the cells with test result. + for server_lang in sorted_server_langs: + shortname = 'cloud_to_cloud:%s:%s_server:%s' % ( + "http2", server_lang, test_case) + html_str = fill_one_test_result(shortname, resultset, html_str) + if cloud_to_prod: + shortname = 'cloud_to_prod:%s:%s' % ("http2", test_case) + html_str = fill_one_test_result(shortname, resultset, html_str) + html_str = '%s\n' % html_str + html_str = '%s
Servers ►
' + 'Test Cases ▼
%s\n' % (html_str, server_lang) + if cloud_to_prod: + html_str = '%s%s\n' % (html_str, "prod") + html_str = '%s
%s
\n' % html_str + if server_langs: + for test_case in sorted_test_cases: + # Each column header is the client language. + html_str = ('%s

%s

\n' + '\n' + '\n' + '\n') % (html_str, test_case) + for client_lang in sorted_client_langs: + html_str = '%s\n' % html_str + # Each row head is the server language. + for server_lang in sorted_server_langs: + html_str = '%s\n' % (html_str, server_lang) + # Fill up the cells with test result. + for client_lang in sorted_client_langs: + shortname = 'cloud_to_cloud:%s:%s_server:%s' % ( + client_lang, server_lang, test_case) + html_str = fill_one_test_result(shortname, resultset, html_str) + html_str = '%s\n' % html_str + html_str = '%s
Client languages ►
' + 'Server languages ▼
%s\n' % (html_str, client_lang) + html_str = '%s
%s
\n' % html_str + + html_str = ('%s\n' + '\n' + '\n' + '') % html_str + + # Write to reports/index.html as set up in Jenkins plugin. + html_report_dir = 'reports' + if not os.path.exists(html_report_dir): + os.mkdir(html_report_dir) + html_file_path = os.path.join(html_report_dir, 'index.html') + with open(html_file_path, 'w') as f: + f.write(html_str) diff --git a/tools/run_tests/run_csharp.bat b/tools/run_tests/run_csharp.bat index 310cfe0d2fe..0e33e5295a4 100644 --- a/tools/run_tests/run_csharp.bat +++ b/tools/run_tests/run_csharp.bat @@ -2,13 +2,23 @@ setlocal -@rem enter this directory +@rem enter src/csharp directory cd /d %~dp0\..\..\src\csharp -@rem set UUID variable to a random GUID, we will use it to put TestResults.xml to a dedicated directory, so that parallel test runs don't collide -for /F %%i in ('powershell -Command "[guid]::NewGuid().ToString()"') do (set UUID=%%i) +if not "%CONFIG%" == "gcov" ( + @rem Run tests for assembly passed as 1st arg. -packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe /domain:None -labels "%1/bin/Debug/%1.dll" -work test-results/%UUID% || goto :error + @rem set UUID variable to a random GUID, we will use it to put TestResults.xml to a dedicated directory, so that parallel test runs don't collide + for /F %%i in ('powershell -Command "[guid]::NewGuid().ToString()"') do (set UUID=%%i) + + packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe /domain:None -labels "%1/bin/Debug/%1.dll" -work test-results/%UUID% || goto :error +) else ( + @rem Run all tests with code coverage + + packages\OpenCover.4.6.166\tools\OpenCover.Console.exe -target:"packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe" -targetdir:"." -targetargs:"/domain:None -labels Grpc.Core.Tests/bin/Debug/Grpc.Core.Tests.dll Grpc.IntegrationTesting/bin/Debug/Grpc.IntegrationTesting.dll Grpc.Examples.Tests/bin/Debug/Grpc.Examples.Tests.dll Grpc.HealthCheck.Tests/bin/Debug/Grpc.HealthCheck.Tests.dll" -filter:"+[Grpc.Core]*" -register:user -output:coverage_results.xml || goto :error + + packages\ReportGenerator.2.3.2.0\tools\ReportGenerator.exe -reports:"coverage_results.xml" -targetdir:"..\..\reports\csharp_coverage" -reporttypes:"Html;TextSummary" || goto :error +) endlocal diff --git a/tools/run_tests/run_csharp.sh b/tools/run_tests/run_csharp.sh index c0fedca1935..37e86feaad3 100755 --- a/tools/run_tests/run_csharp.sh +++ b/tools/run_tests/run_csharp.sh @@ -34,7 +34,7 @@ CONFIG=${CONFIG:-opt} NUNIT_CONSOLE="mono packages/NUnit.Runners.2.6.4/tools/nunit-console.exe" -if [ "$CONFIG" = "dbg" ] +if [ "$CONFIG" = "dbg" ] || [ "$CONFIG" = "gcov" ] then MSBUILD_CONFIG="Debug" else @@ -45,10 +45,24 @@ fi cd $(dirname $0)/../.. root=`pwd` -cd src/csharp - export LD_LIBRARY_PATH=$root/libs/$CONFIG -$NUNIT_CONSOLE -labels "$1/bin/$MSBUILD_CONFIG/$1.dll" +if [ "$CONFIG" = "gcov" ] +then + (cd src/csharp; $NUNIT_CONSOLE -labels \ + "Grpc.Core.Tests/bin/$MSBUILD_CONFIG/Grpc.Core.Tests.dll" \ + "Grpc.Examples.Tests/bin/$MSBUILD_CONFIG/Grpc.Examples.Tests.dll" \ + "Grpc.HealthCheck.Tests/bin/$MSBUILD_CONFIG/Grpc.HealthCheck.Tests.dll" \ + "Grpc.IntegrationTesting/bin/$MSBUILD_CONFIG/Grpc.IntegrationTesting.dll") + + gcov objs/gcov/src/csharp/ext/*.o + lcov --base-directory . --directory . -c -o coverage.info + lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info + genhtml -o reports/csharp_ext_coverage --num-spaces 2 \ + -t 'gRPC C# native extension test coverage' coverage.info \ + --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix +else + (cd src/csharp; $NUNIT_CONSOLE -labels "$1/bin/$MSBUILD_CONFIG/$1.dll") +fi diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index e1d60b2de39..2634164a215 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -33,10 +33,10 @@ import argparse import dockerjob import itertools -import xml.etree.cElementTree as ET import jobset import multiprocessing import os +import report_utils import subprocess import sys import tempfile @@ -159,6 +159,31 @@ class GoLanguage: return 'go' +class Http2Client: + """Represents the HTTP/2 Interop Test + + This pretends to be a language in order to be built and run, but really it + isn't. + """ + def __init__(self): + self.client_cwd = None + self.safename = str(self) + + def client_args(self): + return ['tools/http2_interop/http2_interop.test'] + + def cloud_to_prod_env(self): + return {} + + def global_env(self): + return {} + + def unimplemented_test_cases(self): + return _TEST_CASES + + def __str__(self): + return 'http2' + class NodeLanguage: def __init__(self): @@ -281,6 +306,7 @@ _TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong', _AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds', 'oauth2_auth_token', 'per_rpc_creds'] +_HTTP2_TEST_CASES = ["tls"] def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None): """Wraps given cmdline array to create 'docker run' cmdline from it.""" @@ -439,6 +465,7 @@ def server_jobspec(language, docker_image): environ=environ, docker_args=['-p', str(_DEFAULT_SERVER_PORT), '--name', container_name]) + server_job = jobset.JobSpec( cmdline=docker_cmdline, environ=environ, @@ -471,123 +498,6 @@ def build_interop_image_jobspec(language, tag=None): return build_job -# TODO(adelez): Use mako template. -def fill_one_test_result(shortname, resultset, html_str): - if shortname in resultset: - result = resultset[shortname] - if result.state == 'PASSED': - html_str = '%sPASS\n' % html_str - else: - tooltip = '' - if result.returncode > 0 or result.message: - if result.returncode > 0: - tooltip = 'returncode: %d ' % result.returncode - if result.message: - tooltip = '%smessage: %s' % (tooltip, result.message) - if result.state == 'FAILED': - html_str = '%s' % html_str - if tooltip: - html_str = ('%sFAIL\n' % - (html_str, tooltip)) - else: - html_str = '%sFAIL\n' % html_str - elif result.state == 'TIMEOUT': - html_str = '%s' % html_str - if tooltip: - html_str = ('%sTIMEOUT\n' - % (html_str, tooltip)) - else: - html_str = '%sTIMEOUT\n' % html_str - else: - html_str = '%sNot implemented\n' % html_str - - return html_str - - -def render_html_report(client_langs, server_langs, resultset, - num_failures): - """Generate html report.""" - sorted_test_cases = sorted(_TEST_CASES) - sorted_auth_test_cases = sorted(_AUTH_TEST_CASES) - sorted_client_langs = sorted(client_langs) - sorted_server_langs = sorted(server_langs) - html_str = ('\n' - '\n' - 'Interop Test Result\n' - '\n') - if num_failures > 1: - html_str = ( - '%s

%d tests failed!

\n' % - (html_str, num_failures)) - elif num_failures: - html_str = ( - '%s

%d test failed!

\n' % - (html_str, num_failures)) - else: - html_str = ( - '%s

All tests passed!

\n' % - html_str) - if args.cloud_to_prod_auth or args.cloud_to_prod: - # Each column header is the client language. - html_str = ('%s

Cloud to Prod

\n' - '\n' - '\n' - '\n') % html_str - for client_lang in sorted_client_langs: - html_str = '%s\n' % html_str - for test_case in sorted_test_cases + sorted_auth_test_cases: - html_str = '%s\n' % (html_str, test_case) - for client_lang in sorted_client_langs: - if not test_case in sorted_auth_test_cases: - shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case) - else: - shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case) - html_str = fill_one_test_result(shortname, resultset, html_str) - html_str = '%s\n' % html_str - html_str = '%s
Client languages ►%s\n' % (html_str, client_lang) - html_str = '%s
%s
\n' % html_str - if servers: - for test_case in sorted_test_cases: - # Each column header is the client language. - html_str = ('%s

%s

\n' - '\n' - '\n' - '\n') % (html_str, test_case) - for client_lang in sorted_client_langs: - html_str = '%s\n' % html_str - # Each row head is the server language. - for server_lang in sorted_server_langs: - html_str = '%s\n' % (html_str, server_lang) - # Fill up the cells with test result. - for client_lang in sorted_client_langs: - shortname = 'cloud_to_cloud:%s:%s_server:%s' % ( - client_lang, server_lang, test_case) - html_str = fill_one_test_result(shortname, resultset, html_str) - html_str = '%s\n' % html_str - html_str = '%s
Client languages ►
' - 'Server languages ▼
%s\n' % (html_str, client_lang) - html_str = '%s
%s
\n' % html_str - - html_str = ('%s\n' - '\n' - '\n' - '') % html_str - - # Write to reports/index.html as set up in Jenkins plugin. - html_report_dir = 'reports' - if not os.path.exists(html_report_dir): - os.mkdir(html_report_dir) - html_file_path = os.path.join(html_report_dir, 'index.html') - with open(html_file_path, 'w') as f: - f.write(html_str) - - argp = argparse.ArgumentParser(description='Run interop tests.') argp.add_argument('-l', '--language', choices=['all'] + sorted(_LANGUAGES), @@ -633,6 +543,12 @@ argp.add_argument('--allow_flakes', action='store_const', const=True, help='Allow flaky tests to show as passing (re-runs failed tests up to five times)') +argp.add_argument('--http2_interop', + default=False, + action='store_const', + const=True, + help='Enable HTTP/2 interop tests') + args = argp.parse_args() servers = set(s for s in itertools.chain.from_iterable(_SERVERS @@ -656,12 +572,16 @@ languages = set(_LANGUAGES[l] for l in itertools.chain.from_iterable( _LANGUAGES.iterkeys() if x == 'all' else [x] for x in args.language)) + +http2Interop = Http2Client() if args.http2_interop else None docker_images={} if args.use_docker: # languages for which to build docker images languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] + [s for s in servers])) + if args.http2_interop: + languages_to_build.add(http2Interop) build_jobs = [] for l in languages_to_build: @@ -703,6 +623,15 @@ try: test_job = cloud_to_prod_jobspec(language, test_case, docker_image=docker_images.get(str(language))) jobs.append(test_job) + + # TODO(carl-mastrangelo): Currently prod TLS terminators aren't spec compliant. Reenable + # this once a better solution is in place. + if args.http2_interop and False: + for test_case in _HTTP2_TEST_CASES: + test_job = cloud_to_prod_jobspec(http2Interop, test_case, + docker_image=docker_images.get(str(http2Interop))) + jobs.append(test_job) + if args.cloud_to_prod_auth: for language in languages: @@ -730,6 +659,19 @@ try: server_port, docker_image=docker_images.get(str(language))) jobs.append(test_job) + + if args.http2_interop: + for test_case in _HTTP2_TEST_CASES: + if server_name == "go": + # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434 + continue + test_job = cloud_to_cloud_jobspec(http2Interop, + test_case, + server_name, + server_host, + server_port, + docker_image=docker_images.get(str(http2Interop))) + jobs.append(test_job) if not jobs: print 'No jobs to run.' @@ -737,22 +679,19 @@ try: dockerjob.remove_image(image, skip_nonexistent=True) sys.exit(1) - root = ET.Element('testsuites') - testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') - num_failures, resultset = jobset.run(jobs, newline_on_success=True, - maxjobs=args.jobs, xml_report=testsuite) + maxjobs=args.jobs) if num_failures: jobset.message('FAILED', 'Some tests failed', do_newline=True) else: jobset.message('SUCCESS', 'All tests passed', do_newline=True) - tree = ET.ElementTree(root) - tree.write('report.xml', encoding='UTF-8') + report_utils.render_xml_report(resultset, 'report.xml') - # Generate HTML report. - render_html_report(set([str(l) for l in languages]), servers, - resultset, num_failures) + report_utils.render_html_report( + set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES, + _HTTP2_TEST_CASES, resultset, num_failures, + args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop) finally: # Check if servers are still running. diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 3859958a952..b8017e6fe94 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -46,10 +46,10 @@ import sys import tempfile import traceback import time -import xml.etree.cElementTree as ET import urllib2 import jobset +import report_utils import watch_dirs ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..')) @@ -342,10 +342,18 @@ class CSharpLanguage(object): cmd = 'tools\\run_tests\\run_csharp.bat' else: cmd = 'tools/run_tests/run_csharp.sh' - return [config.job_spec([cmd, assembly], - None, shortname=assembly, - environ=_FORCE_ENVIRON_FOR_WRAPPERS) - for assembly in assemblies] + + if config.build_config == 'gcov': + # On Windows, we only collect C# code coverage. + # On Linux, we only collect coverage for native extension. + # For code coverage all tests need to run as one suite. + return [config.job_spec([cmd], None, + environ=_FORCE_ENVIRON_FOR_WRAPPERS)] + else: + return [config.job_spec([cmd, assembly], + None, shortname=assembly, + environ=_FORCE_ENVIRON_FOR_WRAPPERS) + for assembly in assemblies] def pre_build_steps(self): if self.platform == 'windows': @@ -411,8 +419,8 @@ class ObjCLanguage(object): class Sanity(object): def test_specs(self, config, travis): - return [config.job_spec('tools/run_tests/run_sanity.sh', None), - config.job_spec('tools/run_tests/check_sources_and_headers.py', None)] + return [config.job_spec(['tools/run_tests/run_sanity.sh'], None), + config.job_spec(['tools/run_tests/check_sources_and_headers.py'], None)] def pre_build_steps(self): return [] @@ -450,6 +458,9 @@ class Build(object): def build_steps(self): return [] + def post_tests_steps(self): + return [] + def makefile_name(self): return 'Makefile' @@ -637,13 +648,16 @@ if platform.system() == 'Windows': for target in targets] else: def make_jobspec(cfg, targets, makefile='Makefile'): - return [jobset.JobSpec([os.getenv('MAKE', 'make'), - '-f', makefile, - '-j', '%d' % (multiprocessing.cpu_count() + 1), - 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % - args.slowdown, - 'CONFIG=%s' % cfg] + targets, - timeout_seconds=30*60)] + if targets: + return [jobset.JobSpec([os.getenv('MAKE', 'make'), + '-f', makefile, + '-j', '%d' % (multiprocessing.cpu_count() + 1), + 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % + args.slowdown, + 'CONFIG=%s' % cfg] + targets, + timeout_seconds=30*60)] + else: + return [] make_targets = {} for l in languages: makefile = l.makefile_name() @@ -730,7 +744,8 @@ def _start_port_server(port_server_port): running = False if running: current_version = int(subprocess.check_output( - [sys.executable, 'tools/run_tests/port_server.py', 'dump_version'])) + [sys.executable, os.path.abspath('tools/run_tests/port_server.py'), + 'dump_version'])) print 'my port server is version %d' % current_version running = (version >= current_version) if not running: @@ -741,13 +756,18 @@ def _start_port_server(port_server_port): fd, logfile = tempfile.mkstemp() os.close(fd) print 'starting port_server, with log file %s' % logfile - args = [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port, '-l', logfile] + args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'), + '-p', '%d' % port_server_port, '-l', logfile] env = dict(os.environ) env['BUILD_ID'] = 'pleaseDontKillMeJenkins' if platform.system() == 'Windows': + # Working directory of port server needs to be outside of Jenkins + # workspace to prevent file lock issues. + tempdir = tempfile.mkdtemp() port_server = subprocess.Popen( args, env=env, + cwd=tempdir, creationflags = 0x00000008, # detached process close_fds=True) else: @@ -798,6 +818,23 @@ def _start_port_server(port_server_port): raise +def _calculate_num_runs_failures(list_of_results): + """Caculate number of runs and failures for a particular test. + + Args: + list_of_results: (List) of JobResult object. + Returns: + A tuple of total number of runs and failures. + """ + num_runs = len(list_of_results) # By default, there is 1 run per JobResult. + num_failures = 0 + for jobresult in list_of_results: + if jobresult.retries > 0: + num_runs += jobresult.retries + if jobresult.num_failures > 0: + num_failures += jobresult.num_failures + return num_runs, num_failures + def _build_and_run( check_cancelled, newline_on_success, travis, cache, xml_report=None): """Do one pass of building & running tests.""" @@ -813,6 +850,7 @@ def _build_and_run( for _ in range(0, args.antagonists)] port_server_port = 32767 _start_port_server(port_server_port) + resultset = None try: infinite_runs = runs_per_test == 0 one_run = set( @@ -836,24 +874,30 @@ def _build_and_run( else itertools.repeat(massaged_one_run, runs_per_test)) all_runs = itertools.chain.from_iterable(runs_sequence) - root = ET.Element('testsuites') if xml_report else None - testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None - - number_failures, _ = jobset.run( - all_runs, check_cancelled, newline_on_success=newline_on_success, + number_failures, resultset = jobset.run( + all_runs, check_cancelled, newline_on_success=newline_on_success, travis=travis, infinite_runs=infinite_runs, maxjobs=args.jobs, - stop_on_failure=args.stop_on_failure, + stop_on_failure=args.stop_on_failure, cache=cache if not xml_report else None, - xml_report=testsuite, add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}) + if resultset: + for k, v in resultset.iteritems(): + num_runs, num_failures = _calculate_num_runs_failures(v) + if num_failures == num_runs: # what about infinite_runs??? + jobset.message('FAILED', k, do_newline=True) + elif num_failures > 0: + jobset.message( + 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs), + do_newline=True) + else: + jobset.message('PASSED', k, do_newline=True) if number_failures: return 2 finally: for antagonist in antagonists: antagonist.kill() - if xml_report: - tree = ET.ElementTree(root) - tree.write(xml_report, encoding='UTF-8') + if xml_report and resultset: + report_utils.render_xml_report(resultset, xml_report) number_failures, _ = jobset.run( post_tests_steps, maxjobs=1, stop_on_failure=True, diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 0f4e4874b75..7f4b339a53d 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -1587,6 +1587,23 @@ "test/cpp/common/secure_auth_context_test.cc" ] }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc++", + "grpc++_test_util", + "grpc_test_util", + "qps" + ], + "headers": [], + "language": "c++", + "name": "secure_sync_unary_ping_pong_test", + "src": [ + "test/cpp/qps/secure_sync_unary_ping_pong_test.cc" + ] + }, { "deps": [ "gpr", @@ -14649,8 +14666,16 @@ "test/cpp/qps/stats.h", "test/cpp/qps/timer.h", "test/cpp/util/benchmark_config.h", - "test/proto/qpstest.grpc.pb.h", - "test/proto/qpstest.pb.h" + "test/proto/benchmarks/control.grpc.pb.h", + "test/proto/benchmarks/control.pb.h", + "test/proto/benchmarks/payloads.grpc.pb.h", + "test/proto/benchmarks/payloads.pb.h", + "test/proto/benchmarks/services.grpc.pb.h", + "test/proto/benchmarks/services.pb.h", + "test/proto/benchmarks/stats.grpc.pb.h", + "test/proto/benchmarks/stats.pb.h", + "test/proto/messages.grpc.pb.h", + "test/proto/messages.pb.h" ], "language": "c++", "name": "qps", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index b03e952c893..3abd41dfdc2 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -1497,22 +1497,6 @@ "windows" ] }, - { - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "exclude_configs": [], - "flaky": false, - "language": "c++", - "name": "qps_openloop_test", - "platforms": [ - "linux", - "mac", - "posix" - ] - }, { "ci_platforms": [ "linux", @@ -1558,7 +1542,7 @@ "exclude_configs": [], "flaky": false, "language": "c++", - "name": "server_crash_test", + "name": "secure_sync_unary_ping_pong_test", "platforms": [ "linux", "mac", @@ -1569,18 +1553,16 @@ "ci_platforms": [ "linux", "mac", - "posix", - "windows" + "posix" ], "exclude_configs": [], "flaky": false, "language": "c++", - "name": "shutdown_test", + "name": "server_crash_test", "platforms": [ "linux", "mac", - "posix", - "windows" + "posix" ] }, { @@ -1593,7 +1575,7 @@ "exclude_configs": [], "flaky": false, "language": "c++", - "name": "status_test", + "name": "shutdown_test", "platforms": [ "linux", "mac", @@ -1605,34 +1587,34 @@ "ci_platforms": [ "linux", "mac", - "posix" + "posix", + "windows" ], "exclude_configs": [], "flaky": false, "language": "c++", - "name": "streaming_throughput_test", + "name": "status_test", "platforms": [ "linux", "mac", - "posix" + "posix", + "windows" ] }, { "ci_platforms": [ "linux", "mac", - "posix", - "windows" + "posix" ], "exclude_configs": [], "flaky": false, "language": "c++", - "name": "stress_test", + "name": "streaming_throughput_test", "platforms": [ "linux", "mac", - "posix", - "windows" + "posix" ] }, { diff --git a/vsprojects/vcxproj/qps/qps.vcxproj b/vsprojects/vcxproj/qps/qps.vcxproj index b361b1b601b..9c5a4da0081 100644 --- a/vsprojects/vcxproj/qps/qps.vcxproj +++ b/vsprojects/vcxproj/qps/qps.vcxproj @@ -147,13 +147,45 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsprojects/vcxproj/qps/qps.vcxproj.filters b/vsprojects/vcxproj/qps/qps.vcxproj.filters index cffb5ff118b..afa71953164 100644 --- a/vsprojects/vcxproj/qps/qps.vcxproj.filters +++ b/vsprojects/vcxproj/qps/qps.vcxproj.filters @@ -1,9 +1,21 @@ - + test\proto + + test\proto\benchmarks + + + test\proto\benchmarks + + + test\proto\benchmarks + + + test\proto\benchmarks + test\cpp\qps @@ -90,6 +102,9 @@ {44e63a33-67f4-0575-e87a-711a7c9111e2} + + {4180a094-39b4-e46c-1576-940bfe87d284} +