diff --git a/Makefile b/Makefile
index 718ee95396183f625ede06d9df0a8b99185540dd..2bbb691ebf07a7a364de0abd0337e2d44de6c97d 100644
--- a/Makefile
+++ b/Makefile
@@ -189,9 +189,9 @@ CC_gcov = gcc
 CXX_gcov = g++
 LD_gcov = gcc
 LDXX_gcov = g++
-CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage
+CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
 LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
-DEFINES_gcov = _DEBUG DEBUG
+DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
 
 
 # General settings.
@@ -830,6 +830,8 @@ hpack_table_test: $(BINDIR)/$(CONFIG)/hpack_table_test
 httpcli_format_request_test: $(BINDIR)/$(CONFIG)/httpcli_format_request_test
 httpcli_parser_test: $(BINDIR)/$(CONFIG)/httpcli_parser_test
 httpcli_test: $(BINDIR)/$(CONFIG)/httpcli_test
+init_test: $(BINDIR)/$(CONFIG)/init_test
+invalid_call_argument_test: $(BINDIR)/$(CONFIG)/invalid_call_argument_test
 json_rewrite: $(BINDIR)/$(CONFIG)/json_rewrite
 json_rewrite_test: $(BINDIR)/$(CONFIG)/json_rewrite_test
 json_test: $(BINDIR)/$(CONFIG)/json_test
@@ -837,7 +839,6 @@ lame_client_test: $(BINDIR)/$(CONFIG)/lame_client_test
 lb_policies_test: $(BINDIR)/$(CONFIG)/lb_policies_test
 low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
 message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
-multi_init_test: $(BINDIR)/$(CONFIG)/multi_init_test
 multiple_server_queues_test: $(BINDIR)/$(CONFIG)/multiple_server_queues_test
 murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test
 no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
@@ -1749,7 +1750,9 @@ h2_uds+poll_simple_delayed_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds+poll_s
 h2_uds+poll_simple_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds+poll_simple_request_nosec_test
 h2_uds+poll_trailing_metadata_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds+poll_trailing_metadata_nosec_test
 connection_prefix_bad_client_test: $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test
+headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test
 initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
+unknown_frame_bad_client_test: $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
 
 run_dep_checks:
 	$(OPENSSL_ALPN_CHECK_CMD) || true
@@ -1874,7 +1877,7 @@ endif
 
 buildtests: buildtests_c buildtests_cxx buildtests_zookeeper
 
-buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_varint_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_avl_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)/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)/set_initial_connect_string_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_c: privatelibs_c $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_varint_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_avl_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)/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)/init_test $(BINDIR)/$(CONFIG)/invalid_call_argument_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)/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)/set_initial_connect_string_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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_cancel_with_status_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_hpack_size_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_negative_deadline_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)/headers_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test $(BINDIR)/$(CONFIG)/unknown_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)/metrics_client $(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
 
@@ -1980,6 +1983,10 @@ test_c: buildtests_c
 	$(Q) $(BINDIR)/$(CONFIG)/httpcli_parser_test || ( echo test httpcli_parser_test failed ; exit 1 )
 	$(E) "[RUN]     Testing httpcli_test"
 	$(Q) $(BINDIR)/$(CONFIG)/httpcli_test || ( echo test httpcli_test failed ; exit 1 )
+	$(E) "[RUN]     Testing init_test"
+	$(Q) $(BINDIR)/$(CONFIG)/init_test || ( echo test init_test failed ; exit 1 )
+	$(E) "[RUN]     Testing invalid_call_argument_test"
+	$(Q) $(BINDIR)/$(CONFIG)/invalid_call_argument_test || ( echo test invalid_call_argument_test failed ; exit 1 )
 	$(E) "[RUN]     Testing json_rewrite_test"
 	$(Q) $(BINDIR)/$(CONFIG)/json_rewrite_test || ( echo test json_rewrite_test failed ; exit 1 )
 	$(E) "[RUN]     Testing json_test"
@@ -1990,8 +1997,6 @@ test_c: buildtests_c
 	$(Q) $(BINDIR)/$(CONFIG)/lb_policies_test || ( echo test lb_policies_test failed ; exit 1 )
 	$(E) "[RUN]     Testing message_compress_test"
 	$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
-	$(E) "[RUN]     Testing multi_init_test"
-	$(Q) $(BINDIR)/$(CONFIG)/multi_init_test || ( echo test multi_init_test failed ; exit 1 )
 	$(E) "[RUN]     Testing multiple_server_queues_test"
 	$(Q) $(BINDIR)/$(CONFIG)/multiple_server_queues_test || ( echo test multiple_server_queues_test failed ; exit 1 )
 	$(E) "[RUN]     Testing murmur_hash_test"
@@ -3724,8 +3729,12 @@ test_c: buildtests_c
 	$(Q) $(BINDIR)/$(CONFIG)/h2_uds+poll_trailing_metadata_nosec_test || ( echo test h2_uds+poll_trailing_metadata_nosec_test failed ; exit 1 )
 	$(E) "[RUN]     Testing connection_prefix_bad_client_test"
 	$(Q) $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test || ( echo test connection_prefix_bad_client_test failed ; exit 1 )
+	$(E) "[RUN]     Testing headers_bad_client_test"
+	$(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 )
 	$(E) "[RUN]     Testing initial_settings_frame_bad_client_test"
 	$(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 )
+	$(E) "[RUN]     Testing unknown_frame_bad_client_test"
+	$(Q) $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test || ( echo test unknown_frame_bad_client_test failed ; exit 1 )
 
 
 flaky_test_c: buildtests_c
@@ -9755,6 +9764,64 @@ endif
 endif
 
 
+INIT_TEST_SRC = \
+    test/core/surface/init_test.c \
+
+INIT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INIT_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/init_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/init_test: $(INIT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(INIT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/init_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/surface/init_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_init_test: $(INIT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(INIT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+INVALID_CALL_ARGUMENT_TEST_SRC = \
+    test/core/end2end/invalid_call_argument_test.c \
+
+INVALID_CALL_ARGUMENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INVALID_CALL_ARGUMENT_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/invalid_call_argument_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/invalid_call_argument_test: $(INVALID_CALL_ARGUMENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(INVALID_CALL_ARGUMENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/invalid_call_argument_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/invalid_call_argument_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_invalid_call_argument_test: $(INVALID_CALL_ARGUMENT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(INVALID_CALL_ARGUMENT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 JSON_REWRITE_SRC = \
     test/core/json/json_rewrite.c \
 
@@ -9958,35 +10025,6 @@ endif
 endif
 
 
-MULTI_INIT_TEST_SRC = \
-    test/core/surface/multi_init_test.c \
-
-MULTI_INIT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MULTI_INIT_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/multi_init_test: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/multi_init_test: $(MULTI_INIT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(MULTI_INIT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/multi_init_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/surface/multi_init_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_multi_init_test: $(MULTI_INIT_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(MULTI_INIT_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 MULTIPLE_SERVER_QUEUES_TEST_SRC = \
     test/core/end2end/multiple_server_queues_test.c \
 
@@ -24247,6 +24285,23 @@ ifneq ($(NO_DEPS),true)
 endif
 
 
+HEADERS_BAD_CLIENT_TEST_SRC = \
+    test/core/bad_client/tests/headers.c \
+
+HEADERS_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HEADERS_BAD_CLIENT_TEST_SRC))))
+$(BINDIR)/$(CONFIG)/headers_bad_client_test: $(HEADERS_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(HEADERS_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/headers_bad_client_test
+
+$(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/headers.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_headers_bad_client_test: $(HEADERS_BAD_CLIENT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(HEADERS_BAD_CLIENT_TEST_OBJS:.o=.dep)
+endif
+
+
 INITIAL_SETTINGS_FRAME_BAD_CLIENT_TEST_SRC = \
     test/core/bad_client/tests/initial_settings_frame.c \
 
@@ -24264,6 +24319,23 @@ ifneq ($(NO_DEPS),true)
 endif
 
 
+UNKNOWN_FRAME_BAD_CLIENT_TEST_SRC = \
+    test/core/bad_client/tests/unknown_frame.c \
+
+UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(UNKNOWN_FRAME_BAD_CLIENT_TEST_SRC))))
+$(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test: $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
+
+$(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/unknown_frame.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_unknown_frame_bad_client_test: $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(UNKNOWN_FRAME_BAD_CLIENT_TEST_OBJS:.o=.dep)
+endif
+
+
 
 
 
diff --git a/build.yaml b/build.yaml
index a7f2bf04d8bb112d689e17588d9c073e1789ef9d..ca9ce93dd39e2b58a79c932b6bc7d422b2bb66e9 100644
--- a/build.yaml
+++ b/build.yaml
@@ -1335,6 +1335,26 @@ targets:
   - mac
   - linux
   - posix
+- name: init_test
+  build: test
+  language: c
+  src:
+  - test/core/surface/init_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+- name: invalid_call_argument_test
+  build: test
+  language: c
+  src:
+  - test/core/end2end/invalid_call_argument_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: json_rewrite
   build: test
   run: false
@@ -1408,16 +1428,6 @@ targets:
   - grpc
   - gpr_test_util
   - gpr
-- name: multi_init_test
-  build: test
-  language: c
-  src:
-  - test/core/surface/multi_init_test.c
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr_test_util
-  - gpr
 - name: multiple_server_queues_test
   build: test
   language: c
diff --git a/examples/objective-c/auth_sample/Podfile b/examples/objective-c/auth_sample/Podfile
index ea70511dc6caba4bf3452919b6f52defdc371f13..7affe08743cb8e80f451c5ad2858bf7558096f63 100644
--- a/examples/objective-c/auth_sample/Podfile
+++ b/examples/objective-c/auth_sample/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
 pod 'Protobuf', :path => "../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => "../../../src/objective-c"
 pod 'gRPC', :path => "../../.."
 
 target 'AuthSample' do
diff --git a/examples/objective-c/helloworld/Podfile b/examples/objective-c/helloworld/Podfile
index 16af075a9faca180135ad88063b681f5633a3366..eebf05470d110cb5a9b2cbadbd0d0a02665094ce 100644
--- a/examples/objective-c/helloworld/Podfile
+++ b/examples/objective-c/helloworld/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
 pod 'Protobuf', :path => "../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => "../../../src/objective-c"
 pod 'gRPC', :path => "../../.."
 
 target 'HelloWorld' do
diff --git a/examples/objective-c/route_guide/Podfile b/examples/objective-c/route_guide/Podfile
index efa46bba4fa9ed7c52d7c01b2742d4b5365042c4..b9f2fefd6d2a0702ab43c80b45a7fc2b3451f506 100644
--- a/examples/objective-c/route_guide/Podfile
+++ b/examples/objective-c/route_guide/Podfile
@@ -3,6 +3,7 @@ platform :ios, '8.0'
 
 target 'RouteGuideClient' do
   pod 'Protobuf', :path => "../../../third_party/protobuf"
+  pod 'BoringSSL', :podspec => "../../../src/objective-c"
   pod 'gRPC', :path => "../../.."
   # Depend on the generated RouteGuide library.
   pod 'RouteGuide', :path => '.'
diff --git a/gRPC.podspec b/gRPC.podspec
index 0262479f6129f109e9ddb6b7b12c0fc15372c0b7..f20776dc1d80952efe360194d710eb2ee821cfa9 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -589,7 +589,7 @@ Pod::Spec.new do |s|
 
     ss.requires_arc = false
     ss.libraries = 'z'
-    ss.dependency 'OpenSSL', '~> 1.0.204.1'
+    ss.dependency 'BoringSSL', '~> 1.0'
 
     # ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
   end
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index 63e692cdb567c0bfe5de2d125566cc734528b364..557410beea53852ac292a0e00784d34e922a6ab7 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -183,7 +183,7 @@
 #endif
 #define GPR_MSG_IOVLEN_TYPE int
 #if TARGET_OS_IPHONE
-#define GPR_FORBID_UNREACHABLE_CODE
+#define GPR_FORBID_UNREACHABLE_CODE 1
 #define GPR_PLATFORM_STRING "ios"
 #define GPR_CPU_IPHONE 1
 #define GPR_PTHREAD_TLS 1
@@ -252,6 +252,11 @@
 #define GPR_PLATFORM_STRING "unknown"
 #endif
 
+#ifdef GPR_GCOV
+#undef GPR_FORBID_UNREACHABLE_CODE
+#define GPR_FORBID_UNREACHABLE_CODE 1
+#endif
+
 /* For a common case, assume that the platform has a C99-like stdint.h */
 
 #include <stdint.h>
@@ -337,7 +342,7 @@ typedef uintptr_t gpr_uintptr;
 #endif
 #endif
 
-#ifdef GPR_FORBID_UNREACHABLE_CODE
+#if GPR_FORBID_UNREACHABLE_CODE
 #define GPR_UNREACHABLE_CODE(STATEMENT)
 #else
 #define GPR_UNREACHABLE_CODE(STATEMENT)             \
diff --git a/package.json b/package.json
index 9517c59acedefd1c89315aa56c810ce762bf3f3e..f39dfc4c7cc9e9b1700803fd2c9edec23c302aeb 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,8 @@
     "minimist": "^1.1.0",
     "mocha": "~1.21.0",
     "mocha-jenkins-reporter": "^0.1.9",
-    "mustache": "^2.0.0"
+    "mustache": "^2.0.0",
+    "poisson-process": "^0.2.1"
   },
   "engines": {
     "node": ">=0.10.13"
diff --git a/src/core/census/context.h b/src/core/census/context.h
index d9907d4da75146101070b3309d9d12c88339adde..e45409a6b833f99cc5ad83620ceb35843b41b902 100644
--- a/src/core/census/context.h
+++ b/src/core/census/context.h
@@ -39,11 +39,7 @@
 /* census_context is the in-memory representation of information needed to
  * maintain tracing, RPC statistics and resource usage information. */
 struct census_context {
-  gpr_uint64 op_id;    /* Operation identifier - unique per-context */
-  gpr_uint64 trace_id; /* Globally unique trace identifier */
-                       /* TODO(aveitch) Add census tags:
-                          const census_tag_set *tags;
-                        */
+  census_tag_set *tags;  /* Opaque data structure for census tags. */
 };
 
 #endif /* GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H */
diff --git a/src/core/iomgr/endpoint_pair_posix.c b/src/core/iomgr/endpoint_pair_posix.c
index deae9c6875723153a6cf13dc5e3bf63fc9ecdc83..56f6f146fd34ad164f4d238bd127fe71939b3d24 100644
--- a/src/core/iomgr/endpoint_pair_posix.c
+++ b/src/core/iomgr/endpoint_pair_posix.c
@@ -36,6 +36,7 @@
 #ifdef GPR_POSIX_SOCKET
 
 #include "src/core/iomgr/endpoint_pair.h"
+#include "src/core/iomgr/socket_utils_posix.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -56,6 +57,8 @@ static void create_sockets(int sv[2]) {
   GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
   flags = fcntl(sv[1], F_GETFL, 0);
   GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+  GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0]));
+  GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]));
 }
 
 grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
diff --git a/src/core/support/log.c b/src/core/support/log.c
index f52c2035b9c21066f5c6fce8ac73f8805f3fa28b..04156a5b1fc092094f29c82426feb9c57df1d565 100644
--- a/src/core/support/log.c
+++ b/src/core/support/log.c
@@ -32,6 +32,7 @@
  */
 
 #include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
 
 #include <stdio.h>
 #include <string.h>
@@ -48,7 +49,7 @@ const char *gpr_log_severity_string(gpr_log_severity severity) {
     case GPR_LOG_SEVERITY_ERROR:
       return "E";
   }
-  return "UNKNOWN";
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
 }
 
 void gpr_log_message(const char *file, int line, gpr_log_severity severity,
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
index 5b091f17b0f390b64f06202147dddd11c08a77fb..9f0ded4932b4d1f5123ee1ba4c989af3a2aa6fe8 100644
--- a/src/core/support/slice.c
+++ b/src/core/support/slice.c
@@ -341,10 +341,3 @@ int gpr_slice_str_cmp(gpr_slice a, const char *b) {
   if (d != 0) return d;
   return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
 }
-
-char *gpr_slice_to_cstring(gpr_slice slice) {
-  char *result = gpr_malloc(GPR_SLICE_LENGTH(slice) + 1);
-  memcpy(result, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
-  result[GPR_SLICE_LENGTH(slice)] = '\0';
-  return result;
-}
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 4affafa5850d9828a90655a2193c7b63e6070f39..84b9daaa2896ca795ad3123260a8683362c4c1bc 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -1270,6 +1270,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
         }
         if (call->receiving_message) {
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
         }
         call->receiving_message = 1;
         bctl->recv_message = 1;
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 24ab9c33bbe8c1373fb947f79702480c63140c6e..20907ac6d6c2a88e9cd031e482cb70e7af064023 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -91,19 +91,6 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
                          grpc_call *call, const grpc_op *ops, size_t nops,
                          void *tag);
 
-void grpc_server_log_request_call(char *file, int line,
-                                  gpr_log_severity severity,
-                                  grpc_server *server, grpc_call **call,
-                                  grpc_call_details *details,
-                                  grpc_metadata_array *initial_metadata,
-                                  grpc_completion_queue *cq_bound_to_call,
-                                  grpc_completion_queue *cq_for_notification,
-                                  void *tag);
-
-void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity,
-                              grpc_server *server, grpc_completion_queue *cq,
-                              void *tag);
-
 /* Set a context pointer.
    No thread safety guarantees are made wrt this value. */
 void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
index 16212f63866c1c0581b68e6eead60a9594100b15..f4cd8375c2615d451816397598f33ff23451f1ba 100644
--- a/src/core/surface/call_log_batch.c
+++ b/src/core/surface/call_log_batch.c
@@ -117,26 +117,3 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
   }
 }
 
-void grpc_server_log_request_call(char *file, int line,
-                                  gpr_log_severity severity,
-                                  grpc_server *server, grpc_call **call,
-                                  grpc_call_details *details,
-                                  grpc_metadata_array *initial_metadata,
-                                  grpc_completion_queue *cq_bound_to_call,
-                                  grpc_completion_queue *cq_for_notification,
-                                  void *tag) {
-  gpr_log(file, line, severity,
-          "grpc_server_request_call(server=%p, call=%p, details=%p, "
-          "initial_metadata=%p, cq_bound_to_call=%p, cq_for_notification=%p, "
-          "tag=%p)",
-          server, call, details, initial_metadata, cq_bound_to_call,
-          cq_for_notification, tag);
-}
-
-void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity,
-                              grpc_server *server, grpc_completion_queue *cq,
-                              void *tag) {
-  gpr_log(file, line, severity,
-          "grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", server,
-          cq, tag);
-}
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index e07fbb2cc756bf3a66365712734be90f09884874..38fa990758afe5f8047380efe10167795976ba19 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -118,7 +118,7 @@ void grpc_chttp2_encode_data(gpr_uint32 id, gpr_slice_buffer *inbuf,
 
   hdr = gpr_slice_malloc(9);
   p = GPR_SLICE_START_PTR(hdr);
-  GPR_ASSERT(write_bytes < 16777316);
+  GPR_ASSERT(write_bytes < (1<<24));
   *p++ = (gpr_uint8)(write_bytes >> 16);
   *p++ = (gpr_uint8)(write_bytes >> 8);
   *p++ = (gpr_uint8)(write_bytes);
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
index 472f9cebdb94a2acc6d69977da96a746ac30ba29..27d4d0043b56767fcd094c5e9753fffafd90bd25 100644
--- a/src/core/transport/chttp2/frame_data.h
+++ b/src/core/transport/chttp2/frame_data.h
@@ -94,9 +94,6 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
     grpc_chttp2_transport_parsing *transport_parsing,
     grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
-/* create a slice with an empty data frame and is_last set */
-gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id);
-
 void grpc_chttp2_encode_data(gpr_uint32 id, gpr_slice_buffer *inbuf,
                              gpr_uint32 write_bytes, int is_eof,
                              gpr_slice_buffer *outbuf);
diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c
index 28d5433d151dda563f0e9f13482066193d320f0e..7575031e58164de57225064640b96b37ea8d49f1 100644
--- a/src/core/transport/chttp2/hpack_encoder.c
+++ b/src/core/transport/chttp2/hpack_encoder.c
@@ -458,12 +458,6 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
   GRPC_MDELEM_UNREF(mdelem);
 }
 
-gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
-  gpr_slice slice = gpr_slice_malloc(9);
-  fill_header(GPR_SLICE_START_PTR(slice), GRPC_CHTTP2_FRAME_DATA, id, 0, 1);
-  return slice;
-}
-
 static gpr_uint32 elems_for_bytes(gpr_uint32 bytes) {
   return (bytes + 31) / 32;
 }
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
index d38ff687542410e191c30fbf86ce18e3c3dd83fe..30f0d469e38b01580d1be6eaa7b9b57a7ee5448a 100644
--- a/src/core/transport/chttp2/hpack_parser.c
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -728,6 +728,7 @@ static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
 /* parse an indexed field with index < 127 */
 static int parse_indexed_field(grpc_chttp2_hpack_parser *p,
                                const gpr_uint8 *cur, const gpr_uint8 *end) {
+  p->dynamic_table_update_allowed = 0;
   p->index = (*cur) & 0x7f;
   return finish_indexed_field(p, cur + 1, end);
 }
@@ -737,6 +738,7 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
                                  const gpr_uint8 *cur, const gpr_uint8 *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_indexed_field};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = 0x7f;
   p->parsing.value = &p->index;
@@ -748,6 +750,7 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
 static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  GPR_ASSERT(md != NULL); /* handled in string parsing */
   return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
                                                      take_string(p, &p->value)),
                 1) &&
@@ -768,6 +771,7 @@ static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
                                const gpr_uint8 *cur, const gpr_uint8 *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_incidx};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = (*cur) & 0x3f;
   return parse_string_prefix(p, cur + 1, end);
@@ -779,6 +783,7 @@ static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_incidx};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = 0x3f;
   p->parsing.value = &p->index;
@@ -791,6 +796,7 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_incidx_v};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   return parse_string_prefix(p, cur + 1, end);
 }
@@ -799,6 +805,7 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
 static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  GPR_ASSERT(md != NULL); /* handled in string parsing */
   return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
                                                      take_string(p, &p->value)),
                 0) &&
@@ -819,6 +826,7 @@ static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
                                const gpr_uint8 *cur, const gpr_uint8 *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_notidx};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = (*cur) & 0xf;
   return parse_string_prefix(p, cur + 1, end);
@@ -830,6 +838,7 @@ static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_notidx};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = 0xf;
   p->parsing.value = &p->index;
@@ -842,6 +851,7 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_notidx_v};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   return parse_string_prefix(p, cur + 1, end);
 }
@@ -850,6 +860,7 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
 static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  GPR_ASSERT(md != NULL); /* handled in string parsing */
   return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
                                                      take_string(p, &p->value)),
                 0) &&
@@ -870,6 +881,7 @@ static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
                                const gpr_uint8 *cur, const gpr_uint8 *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_nvridx};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = (*cur) & 0xf;
   return parse_string_prefix(p, cur + 1, end);
@@ -881,6 +893,7 @@ static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_nvridx};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = 0xf;
   p->parsing.value = &p->index;
@@ -893,6 +906,7 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
+  p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   return parse_string_prefix(p, cur + 1, end);
 }
@@ -908,6 +922,10 @@ static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
 /* parse a max table size change, max size < 15 */
 static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
                               const gpr_uint8 *end) {
+  if (p->dynamic_table_update_allowed == 0) {
+    return 0;
+  }
+  p->dynamic_table_update_allowed--;
   p->index = (*cur) & 0x1f;
   return finish_max_tbl_size(p, cur + 1, end);
 }
@@ -917,6 +935,10 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_max_tbl_size};
+  if (p->dynamic_table_update_allowed == 0) {
+    return 0;
+  }
+  p->dynamic_table_update_allowed--;
   p->next_state = and_then;
   p->index = 0x1f;
   p->parsing.value = &p->index;
@@ -1300,7 +1322,10 @@ static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
 
 static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) {
   grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  if (!elem) return ERROR_HEADER;
+  if (!elem) {
+    gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
+    return ERROR_HEADER;
+  }
   return grpc_is_binary_header(
              (const char *)GPR_SLICE_START_PTR(elem->key->slice),
              GPR_SLICE_LENGTH(elem->key->slice))
@@ -1338,15 +1363,7 @@ static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
 /* PUBLIC INTERFACE */
 
 static void on_header_not_set(void *user_data, grpc_mdelem *md) {
-  char *keyhex = gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
-  char *valuehex =
-      gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
-  gpr_log(GPR_ERROR, "on_header callback not set; key=%s value=%s", keyhex,
-          valuehex);
-  gpr_free(keyhex);
-  gpr_free(valuehex);
-  GRPC_MDELEM_UNREF(md);
-  abort();
+  GPR_UNREACHABLE_CODE(return );
 }
 
 void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
@@ -1359,6 +1376,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
   p->value.str = NULL;
   p->value.capacity = 0;
   p->value.length = 0;
+  p->dynamic_table_update_allowed = 2;
   grpc_chttp2_hptbl_init(&p->table);
 }
 
@@ -1400,20 +1418,25 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
       GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
       return GRPC_CHTTP2_CONNECTION_ERROR;
     }
-    if (parser->is_boundary) {
-      stream_parsing
-          ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
-      stream_parsing->header_frames_received++;
-      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                               stream_parsing);
-    }
-    if (parser->is_eof) {
-      stream_parsing->received_close = 1;
+    /* need to check for null stream: this can occur if we receive an invalid
+       stream id on a header */
+    if (stream_parsing != NULL) {
+      if (parser->is_boundary) {
+        stream_parsing
+            ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
+        stream_parsing->header_frames_received++;
+        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                                 stream_parsing);
+      }
+      if (parser->is_eof) {
+        stream_parsing->received_close = 1;
+      }
     }
     parser->on_header = on_header_not_set;
     parser->on_header_user_data = NULL;
     parser->is_boundary = 0xde;
     parser->is_eof = 0xde;
+    parser->dynamic_table_update_allowed = 2;
   }
   GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
   return GRPC_CHTTP2_PARSE_OK;
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
index fb894b5735a35557a7865d5e0fe9be197f392bdd..bd36357124aaf9b5040bab49c9ab00f5a161f5fd 100644
--- a/src/core/transport/chttp2/hpack_parser.h
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -85,6 +85,8 @@ struct grpc_chttp2_hpack_parser {
   gpr_uint8 binary;
   /* is the current string huffman encoded? */
   gpr_uint8 huff;
+  /* is a dynamic table update allowed? */
+  gpr_uint8 dynamic_table_update_allowed;
   /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal
      it should append a metadata boundary at the end of frame */
   gpr_uint8 is_boundary;
diff --git a/src/core/transport/chttp2/incoming_metadata.c b/src/core/transport/chttp2/incoming_metadata.c
index 956afc8e9d6416741f78e32463f0a6fc80048dc3..315bc2faa19c4b3a48097d1461e0f866a1244ff0 100644
--- a/src/core/transport/chttp2/incoming_metadata.c
+++ b/src/core/transport/chttp2/incoming_metadata.c
@@ -56,16 +56,6 @@ void grpc_chttp2_incoming_metadata_buffer_destroy(
   gpr_free(buffer->elems);
 }
 
-void grpc_chttp2_incoming_metadata_buffer_reset(
-    grpc_chttp2_incoming_metadata_buffer *buffer) {
-  size_t i;
-  GPR_ASSERT(!buffer->published);
-  for (i = 0; i < buffer->count; i++) {
-    GRPC_MDELEM_UNREF(buffer->elems[i].md);
-  }
-  buffer->count = 0;
-}
-
 void grpc_chttp2_incoming_metadata_buffer_add(
     grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) {
   GPR_ASSERT(!buffer->published);
@@ -83,14 +73,6 @@ void grpc_chttp2_incoming_metadata_buffer_set_deadline(
   buffer->deadline = deadline;
 }
 
-void grpc_chttp2_incoming_metadata_buffer_swap(
-    grpc_chttp2_incoming_metadata_buffer *a,
-    grpc_chttp2_incoming_metadata_buffer *b) {
-  GPR_ASSERT(!a->published);
-  GPR_ASSERT(!b->published);
-  GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, *a, *b);
-}
-
 void grpc_chttp2_incoming_metadata_buffer_publish(
     grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) {
   GPR_ASSERT(!buffer->published);
diff --git a/src/core/transport/chttp2/incoming_metadata.h b/src/core/transport/chttp2/incoming_metadata.h
index 0e1dabe8253e41d7e198cbefb54cb82138c83545..ea74cfc64b2a7cd57cb977dd477341b8fea886c8 100644
--- a/src/core/transport/chttp2/incoming_metadata.h
+++ b/src/core/transport/chttp2/incoming_metadata.h
@@ -49,8 +49,6 @@ void grpc_chttp2_incoming_metadata_buffer_init(
     grpc_chttp2_incoming_metadata_buffer *buffer);
 void grpc_chttp2_incoming_metadata_buffer_destroy(
     grpc_chttp2_incoming_metadata_buffer *buffer);
-void grpc_chttp2_incoming_metadata_buffer_reset(
-    grpc_chttp2_incoming_metadata_buffer *buffer);
 void grpc_chttp2_incoming_metadata_buffer_publish(
     grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch);
 
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index 3952f8a0e82fb41d5a0510fe1327850dd5eb924e..45d2599cdc7ae7ca8b5f96ba66131e86481ce186 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -512,9 +512,6 @@ void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
 void grpc_chttp2_list_add_writable_stream(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global *stream_global);
-void grpc_chttp2_list_add_first_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
 int grpc_chttp2_list_pop_writable_stream(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_transport_writing *transport_writing,
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
index a81ffcce79e7c1b0bd66de635aa5f95de93613b4..a4c85b4e574822eedb985b18e111a52f3656cc1d 100644
--- a/src/core/transport/chttp2/stream_lists.c
+++ b/src/core/transport/chttp2/stream_lists.c
@@ -108,23 +108,6 @@ static void stream_list_maybe_remove(grpc_chttp2_transport *t,
   }
 }
 
-static void stream_list_add_head(grpc_chttp2_transport *t,
-                                 grpc_chttp2_stream *s,
-                                 grpc_chttp2_stream_list_id id) {
-  grpc_chttp2_stream *old_head;
-  GPR_ASSERT(!s->included[id]);
-  old_head = t->lists[id].head;
-  s->links[id].next = old_head;
-  s->links[id].prev = NULL;
-  if (old_head) {
-    old_head->links[id].prev = s;
-  } else {
-    t->lists[id].tail = s;
-  }
-  t->lists[id].head = s;
-  s->included[id] = 1;
-}
-
 static void stream_list_add_tail(grpc_chttp2_transport *t,
                                  grpc_chttp2_stream *s,
                                  grpc_chttp2_stream_list_id id) {
@@ -161,15 +144,6 @@ void grpc_chttp2_list_add_writable_stream(
                   STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE);
 }
 
-void grpc_chttp2_list_add_first_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  GPR_ASSERT(stream_global->id != 0);
-  stream_list_add_head(TRANSPORT_FROM_GLOBAL(transport_global),
-                       STREAM_FROM_GLOBAL(stream_global),
-                       GRPC_CHTTP2_LIST_WRITABLE);
-}
-
 int grpc_chttp2_list_pop_writable_stream(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_transport_writing *transport_writing,
diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c
index c39e584496ce8ba1c09ab8cf895e99c16145856d..db219a50a6798a0e0de2f08a76e70381bc088884 100644
--- a/src/core/tsi/transport_security.c
+++ b/src/core/tsi/transport_security.c
@@ -145,7 +145,9 @@ void tsi_frame_protector_destroy(tsi_frame_protector *self) {
 tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
                                                     unsigned char *bytes,
                                                     size_t *bytes_size) {
-  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
   return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
 }
@@ -153,7 +155,9 @@ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
 tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
                                                   const unsigned char *bytes,
                                                   size_t *bytes_size) {
-  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
   return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
 }
diff --git a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
index 1c14c5bb5b44634c76cf40915bd1928becd04670..f77e9c6573d824857f501d41e49d995c40756216 100644
--- a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
+++ b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
@@ -57,9 +57,9 @@ namespace Grpc.Auth
         /// <returns>The interceptor.</returns>
         public static AsyncAuthInterceptor FromCredential(ITokenAccess credential)
         {
-            return new AsyncAuthInterceptor(async (authUri, metadata) =>
+            return new AsyncAuthInterceptor(async (context, metadata) =>
             {
-                var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false);
+                var accessToken = await credential.GetAccessTokenForRequestAsync(context.ServiceUrl, CancellationToken.None).ConfigureAwait(false);
                 metadata.Add(CreateBearerTokenHeader(accessToken));
             });
         }
@@ -72,7 +72,7 @@ namespace Grpc.Auth
         public static AsyncAuthInterceptor FromAccessToken(string accessToken)
         {
             Preconditions.CheckNotNull(accessToken);
-            return new AsyncAuthInterceptor(async (authUri, metadata) =>
+            return new AsyncAuthInterceptor(async (context, metadata) =>
             {
                 metadata.Add(CreateBearerTokenHeader(accessToken));
             });
diff --git a/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c9ab048120b6d0b5346cb54de515620c87d7b32
--- /dev/null
+++ b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
@@ -0,0 +1,84 @@
+#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.Collections.Generic;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+    /// <summary>
+    /// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
+    /// </summary>
+    /// <param name="context">The interceptor context.</param>
+    /// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
+    /// <returns></returns>
+    public delegate Task AsyncAuthInterceptor(AuthInterceptorContext context, Metadata metadata);
+
+    /// <summary>
+    /// Context for an RPC being intercepted by <see cref="AsyncAuthInterceptor"/>.
+    /// </summary>
+    public class AuthInterceptorContext
+    {
+        readonly string serviceUrl;
+        readonly string methodName;
+
+        /// <summary>
+        /// Initializes a new instance of <c>AuthInterceptorContext</c>.
+        /// </summary>
+        public AuthInterceptorContext(string serviceUrl, string methodName)
+        {
+            this.serviceUrl = Preconditions.CheckNotNull(serviceUrl);
+            this.methodName = Preconditions.CheckNotNull(methodName);
+        }
+
+        /// <summary>
+        /// The fully qualified service URL for the RPC being called.
+        /// </summary>
+        public string ServiceUrl
+        {
+            get { return serviceUrl; }
+        }
+
+        /// <summary>
+        /// The method name of the RPC being called.
+        /// </summary>
+        public string MethodName
+        {
+            get { return methodName; }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs
index 5ea179dfea152353b051902c03dde16cc2c477da..a71c8904fe76aeca8f8eae751f90a7b22b7eaafe 100644
--- a/src/csharp/Grpc.Core/CallCredentials.cs
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -40,14 +40,6 @@ using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
-    /// <summary>
-    /// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
-    /// </summary>
-    /// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
-    /// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
-    /// <returns></returns>
-    public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
-
     /// <summary>
     /// Client-side call credentials. Provide authorization with per-call granularity.
     /// </summary>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 56a06f4a9bbd1db529a7a5cdcf54330c5ba8f60a..5b3da7c6c9948b4853a56e21e79333c882325344 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -46,6 +46,7 @@
   <ItemGroup>
     <Compile Include="AsyncDuplexStreamingCall.cs" />
     <Compile Include="AsyncServerStreamingCall.cs" />
+    <Compile Include="AsyncAuthInterceptor.cs" />
     <Compile Include="CallCredentials.cs" />
     <Compile Include="IClientStreamWriter.cs" />
     <Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
@@ -148,8 +149,8 @@
     <Error Condition="!Exists('..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets'))" />
     <Error Condition="!Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets'))" />
   </Target>
-  <ItemGroup />
-  <ItemGroup />
   <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets')" />
   <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets')" />
-</Project>
\ No newline at end of file
+  <ItemGroup />
+  <ItemGroup />
+</Project>
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index 4c086048d265125aaa14c81d18ee6806d280f914..8bb646d303cd025c328b547f8d1b92574360162f 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -38,7 +38,7 @@ using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
 {
-    internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
+    internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
 
     internal class NativeMetadataCredentialsPlugin
     {
@@ -71,7 +71,7 @@ namespace Grpc.Core.Internal
             get { return credentials; }
         }
 
-        private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
+        private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
         {
             if (isDestroy)
             {
@@ -81,8 +81,9 @@ namespace Grpc.Core.Internal
 
             try
             {
-                string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr);
-                StartGetMetadata(serviceUrl, callbackPtr, userDataPtr);
+                var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr),
+                                                         Marshal.PtrToStringAnsi(methodNamePtr));
+                StartGetMetadata(context, callbackPtr, userDataPtr);
             }
             catch (Exception e)
             {
@@ -91,12 +92,12 @@ namespace Grpc.Core.Internal
             }
         }
 
-        private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr)
+        private async void StartGetMetadata(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)
         {
             try
             {
                 var metadata = new Metadata();
-                await interceptor(serviceUrl, metadata).ConfigureAwait(false);
+                await interceptor(context, metadata).ConfigureAwait(false);
 
                 using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
                 {
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 55462e02fd562f4d50a2b6fc61c27b361190aff6..53b2bb78c4c7f797f4af5dc6811a91abdfd424de 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -66,6 +66,5 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
-    <None Include="proto\math.proto" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 8fce5d39aabfd333ab2796a4995ef0cb8f7710c3..4e775a7a0c952f24da6beb31fef1b417ef4be219 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -65,7 +65,6 @@
   <ItemGroup>
     <None Include="Grpc.HealthCheck.nuspec" />
     <None Include="packages.config" />
-    <None Include="proto\health.proto" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
@@ -81,4 +80,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto
deleted file mode 100644
index 01aa3fcf5777ecd5ce19ab34927072c87116585a..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck/proto/health.proto
+++ /dev/null
@@ -1,52 +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.
-
-// TODO(jtattermusch): switch to proto3 once C# supports that.
-syntax = "proto3";
-
-package grpc.health.v1alpha;
-option csharp_namespace = "Grpc.Health.V1Alpha";
-
-message HealthCheckRequest {
-  string host = 1;
-  string service = 2;
-}
-
-message HealthCheckResponse {
-  enum ServingStatus {
-    UNKNOWN = 0;
-    SERVING = 1;
-    NOT_SERVING = 2;
-  }
-  ServingStatus status = 1;
-}
-
-service Health {
-  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
-}
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index 3d56678b990cc9ea7885171250b66d4301e5855e..35230f48c1785c2da03e3326d366f062ae043e92 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -67,7 +67,7 @@ namespace Grpc.IntegrationTesting
                 new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
             };
 
-            var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) =>
+            var asyncAuthInterceptor = new AsyncAuthInterceptor(async (context, metadata) =>
             {
                 await Task.Delay(100);  // make sure the operation is asynchronous.
                 metadata.Add("authorization", "SECRET_TOKEN");
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index b8705c49d320db1c046a590cce9383a4dc5cc00f..0ef9be33a6c989a946d174e8af3ef44dfd46c118 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -927,7 +927,8 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
 }
 
 typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
-  void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb,
+  void *state, const char *service_url, const char *method_name,
+  grpc_credentials_plugin_metadata_cb cb,
   void *user_data, gpr_int32 is_destroy);
 
 static void grpcsharp_get_metadata_handler(
@@ -935,13 +936,13 @@ static void grpcsharp_get_metadata_handler(
     grpc_credentials_plugin_metadata_cb cb, void *user_data) {
   grpcsharp_metadata_interceptor_func interceptor =
       (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
-  interceptor(state, context.service_url, cb, user_data, 0);
+  interceptor(state, context.service_url, context.method_name, cb, user_data, 0);
 }
 
 static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
   grpcsharp_metadata_interceptor_func interceptor =
       (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
-  interceptor(state, NULL, NULL, NULL, 1);
+  interceptor(state, NULL, NULL, NULL, NULL, 1);
 }
 
 GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index 92348d13942e4f36219eb8fba90011eb39ca57b6..4dbd9c33085ac4378e7d6dddd6650d5b04d575e0 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -30,19 +30,19 @@
 
 # Regenerates gRPC service stubs from proto files.
 set +e
-cd $(dirname $0)
+cd $(dirname $0)/../..
 
-PROTOC=../../bins/opt/protobuf/protoc
-PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
-EXAMPLES_DIR=Grpc.Examples
-TESTING_DIR=Grpc.IntegrationTesting
-HEALTHCHECK_DIR=Grpc.HealthCheck
+PROTOC=bins/opt/protobuf/protoc
+PLUGIN=protoc-gen-grpc=bins/opt/grpc_csharp_plugin
+EXAMPLES_DIR=src/csharp/Grpc.Examples
+HEALTHCHECK_DIR=src/csharp/Grpc.HealthCheck
+TESTING_DIR=src/csharp/Grpc.IntegrationTesting
 
 $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-    -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
-
-$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
-    -I ../.. ../../test/proto/*.proto ../../test/proto/benchmarks/*.proto
+    -I src/proto/math src/proto/math/math.proto
 
 $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-    -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
+    -I src/proto/grpc/health/v1alpha src/proto/grpc/health/v1alpha/health.proto
+
+$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
+    -I . test/proto/{empty,messages,test}.proto test/proto/benchmarks/*.proto
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 1b2ab21dfe3d96b791bf7a50e8aeaa9bdb1848b5..c0e2b0f0e8fac71f8550eca326eec74721a4d21b 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -234,7 +234,9 @@ class SendMetadataOp : public Op {
 
 class SendMessageOp : public Op {
  public:
-  SendMessageOp() { send_message = NULL; }
+  SendMessageOp() {
+    send_message = NULL;
+  }
   ~SendMessageOp() {
     if (send_message != NULL) {
       grpc_byte_buffer_destroy(send_message);
@@ -269,7 +271,6 @@ class SendMessageOp : public Op {
   std::string GetTypeString() const {
     return "send_message";
   }
-
  private:
   grpc_byte_buffer *send_message;
 };
diff --git a/src/node/health_check/health.js b/src/node/health_check/health.js
index 84d7e0568e50d58489b6733419fbcf2f6e1cf58e..1a2c0366875701b6b57cf52e0bbfabaf9137f2a2 100644
--- a/src/node/health_check/health.js
+++ b/src/node/health_check/health.js
@@ -37,7 +37,8 @@ var grpc = require('../');
 
 var _ = require('lodash');
 
-var health_proto = grpc.load(__dirname + '/health.proto');
+var health_proto = grpc.load(__dirname +
+    '/../../proto/grpc/health/v1alpha/health.proto');
 
 var HealthClient = health_proto.grpc.health.v1alpha.Health;
 
diff --git a/src/node/health_check/health.proto b/src/node/health_check/health.proto
deleted file mode 100644
index 57f4aaa9c08d9bbc81aa755cf6b0b3efb76d8adb..0000000000000000000000000000000000000000
--- a/src/node/health_check/health.proto
+++ /dev/null
@@ -1,49 +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.
-
-syntax = "proto3";
-
-package grpc.health.v1alpha;
-
-message HealthCheckRequest {
-  string service = 1;
-}
-
-message HealthCheckResponse {
-  enum ServingStatus {
-    UNKNOWN = 0;
-    SERVING = 1;
-    NOT_SERVING = 2;
-  }
-  ServingStatus status = 1;
-}
-
-service Health {
-  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
-}
diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js
new file mode 100644
index 0000000000000000000000000000000000000000..d97bdbbcaf7d6f337ca8e81d70479a2f68903e38
--- /dev/null
+++ b/src/node/performance/benchmark_client.js
@@ -0,0 +1,336 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Benchmark client module
+ * @module
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var EventEmitter = require('events');
+var _ = require('lodash');
+var PoissonProcess = require('poisson-process');
+var Histogram = require('./histogram');
+var grpc = require('../../../');
+var serviceProto = grpc.load({
+  root: __dirname + '/../../..',
+  file: 'test/proto/benchmarks/services.proto'}).grpc.testing;
+
+/**
+ * Create a buffer filled with size zeroes
+ * @param {number} size The length of the buffer
+ * @return {Buffer} The new buffer
+ */
+function zeroBuffer(size) {
+  var zeros = new Buffer(size);
+  zeros.fill(0);
+  return zeros;
+}
+
+/**
+ * Convert a time difference, as returned by process.hrtime, to a number of
+ * nanoseconds.
+ * @param {Array.<number>} time_diff The time diff, represented as
+ *     [seconds, nanoseconds]
+ * @return {number} The total number of nanoseconds
+ */
+function timeDiffToNanos(time_diff) {
+  return time_diff[0] * 1e9 + time_diff[1];
+}
+
+/**
+ * The BenchmarkClient class. Opens channels to servers and makes RPCs based on
+ * parameters from the driver, and records statistics about those RPCs.
+ * @param {Array.<string>} server_targets List of servers to connect to
+ * @param {number} channels The total number of channels to open
+ * @param {Object} histogram_params Options for setting up the histogram
+ * @param {Object=} security_params Options for TLS setup. If absent, don't use
+ *     TLS
+ */
+function BenchmarkClient(server_targets, channels, histogram_params,
+    security_params) {
+  var options = {};
+  var creds;
+  if (security_params) {
+    var ca_path;
+    if (security_params.use_test_ca) {
+      ca_path = path.join(__dirname, '../test/data/ca.pem');
+      var ca_data = fs.readFileSync(ca_path);
+      creds = grpc.credentials.createSsl(ca_data);
+    } else {
+      creds = grpc.credentials.createSsl();
+    }
+    if (security_params.server_host_override) {
+      var host_override = security_params.server_host_override;
+      options['grpc.ssl_target_name_override'] = host_override;
+      options['grpc.default_authority'] = host_override;
+    }
+  } else {
+    creds = grpc.credentials.createInsecure();
+  }
+
+  this.clients = [];
+
+  for (var i = 0; i < channels; i++) {
+    this.clients[i] = new serviceProto.BenchmarkService(
+        server_targets[i % server_targets.length], creds, options);
+  }
+
+  this.histogram = new Histogram(histogram_params.resolution,
+                                 histogram_params.max_possible);
+
+  this.running = false;
+
+  this.pending_calls = 0;
+};
+
+util.inherits(BenchmarkClient, EventEmitter);
+
+/**
+ * Start a closed-loop test. For each channel, start
+ * outstanding_rpcs_per_channel RPCs. Then, whenever an RPC finishes, start
+ * another one.
+ * @param {number} outstanding_rpcs_per_channel Number of RPCs to start per
+ *     channel
+ * @param {string} rpc_type Which method to call. Should be 'UNARY' or
+ *     'STREAMING'
+ * @param {number} req_size The size of the payload to send with each request
+ * @param {number} resp_size The size of payload to request be sent in responses
+ */
+BenchmarkClient.prototype.startClosedLoop = function(
+    outstanding_rpcs_per_channel, rpc_type, req_size, resp_size) {
+  var self = this;
+
+  self.running = true;
+
+  self.last_wall_time = process.hrtime();
+
+  var makeCall;
+
+  var argument = {
+    response_size: resp_size,
+    payload: {
+      body: zeroBuffer(req_size)
+    }
+  };
+
+  if (rpc_type == 'UNARY') {
+    makeCall = function(client) {
+      if (self.running) {
+        self.pending_calls++;
+        var start_time = process.hrtime();
+        client.unaryCall(argument, function(error, response) {
+          if (error) {
+            self.emit('error', new Error('Client error: ' + error.message));
+            self.running = false;
+            return;
+          }
+          var time_diff = process.hrtime(start_time);
+          self.histogram.add(timeDiffToNanos(time_diff));
+          makeCall(client);
+          self.pending_calls--;
+          if ((!self.running) && self.pending_calls == 0) {
+            self.emit('finished');
+          }
+        });
+      }
+    };
+  } else {
+    makeCall = function(client) {
+      if (self.running) {
+        self.pending_calls++;
+        var start_time = process.hrtime();
+        var call = client.streamingCall();
+        call.write(argument);
+        call.on('data', function() {
+        });
+        call.on('end', function() {
+          var time_diff = process.hrtime(start_time);
+          self.histogram.add(timeDiffToNanos(time_diff));
+          makeCall(client);
+          self.pending_calls--;
+          if ((!self.running) && self.pending_calls == 0) {
+            self.emit('finished');
+          }
+        });
+        call.on('error', function(error) {
+          self.emit('error', new Error('Client error: ' + error.message));
+          self.running = false;
+        });
+      }
+    };
+  }
+
+  _.each(self.clients, function(client) {
+    _.times(outstanding_rpcs_per_channel, function() {
+      makeCall(client);
+    });
+  });
+};
+
+/**
+ * Start a poisson test. For each channel, this initiates a number of Poisson
+ * processes equal to outstanding_rpcs_per_channel, where each Poisson process
+ * has the load parameter offered_load.
+ * @param {number} outstanding_rpcs_per_channel Number of RPCs to start per
+ *     channel
+ * @param {string} rpc_type Which method to call. Should be 'UNARY' or
+ *     'STREAMING'
+ * @param {number} req_size The size of the payload to send with each request
+ * @param {number} resp_size The size of payload to request be sent in responses
+ * @param {number} offered_load The load parameter for the Poisson process
+ */
+BenchmarkClient.prototype.startPoisson = function(
+    outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, offered_load) {
+  var self = this;
+
+  self.running = true;
+
+  self.last_wall_time = process.hrtime();
+
+  var makeCall;
+
+  var argument = {
+    response_size: resp_size,
+    payload: {
+      body: zeroBuffer(req_size)
+    }
+  };
+
+  if (rpc_type == 'UNARY') {
+    makeCall = function(client, poisson) {
+      if (self.running) {
+        self.pending_calls++;
+        var start_time = process.hrtime();
+        client.unaryCall(argument, function(error, response) {
+          if (error) {
+            self.emit('error', new Error('Client error: ' + error.message));
+            self.running = false;
+            return;
+          }
+          var time_diff = process.hrtime(start_time);
+          self.histogram.add(timeDiffToNanos(time_diff));
+          self.pending_calls--;
+          if ((!self.running) && self.pending_calls == 0) {
+            self.emit('finished');
+          }
+        });
+      } else {
+        poisson.stop();
+      }
+    };
+  } else {
+    makeCall = function(client, poisson) {
+      if (self.running) {
+        self.pending_calls++;
+        var start_time = process.hrtime();
+        var call = client.streamingCall();
+        call.write(argument);
+        call.on('data', function() {
+        });
+        call.on('end', function() {
+          var time_diff = process.hrtime(start_time);
+          self.histogram.add(timeDiffToNanos(time_diff));
+          self.pending_calls--;
+          if ((!self.running) && self.pending_calls == 0) {
+            self.emit('finished');
+          }
+        });
+        call.on('error', function(error) {
+          self.emit('error', new Error('Client error: ' + error.message));
+          self.running = false;
+        });
+      } else {
+        poisson.stop();
+      }
+    };
+  }
+
+  var averageIntervalMs = (1 / offered_load) * 1000;
+
+  _.each(self.clients, function(client) {
+    _.times(outstanding_rpcs_per_channel, function() {
+      var p = PoissonProcess.create(averageIntervalMs, function() {
+        makeCall(client, p);
+      });
+      p.start();
+    });
+  });
+};
+
+/**
+ * Return curent statistics for the client. If reset is set, restart
+ * statistic collection.
+ * @param {boolean} reset Indicates that statistics should be reset
+ * @return {object} Client statistics
+ */
+BenchmarkClient.prototype.mark = function(reset) {
+  var wall_time_diff = process.hrtime(this.last_wall_time);
+  var histogram = this.histogram;
+  if (reset) {
+    this.last_wall_time = process.hrtime();
+    this.histogram = new Histogram(histogram.resolution,
+                                   histogram.max_possible);
+  }
+
+  return {
+    latencies: {
+      bucket: histogram.getContents(),
+      min_seen: histogram.minimum(),
+      max_seen: histogram.maximum(),
+      sum: histogram.getSum(),
+      sum_of_squares: histogram.sumOfSquares(),
+      count: histogram.getCount()
+    },
+    time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
+    // Not sure how to measure these values
+    time_user: 0,
+    time_system: 0
+  };
+};
+
+/**
+ * Stop the clients.
+ * @param {function} callback Called when the clients have finished shutting
+ *     down
+ */
+BenchmarkClient.prototype.stop = function(callback) {
+  this.running = false;
+  this.on('finished', callback);
+};
+
+module.exports = BenchmarkClient;
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac96fc5edb32270a7dd77ddd65bc9079854cb791
--- /dev/null
+++ b/src/node/performance/benchmark_server.js
@@ -0,0 +1,162 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Benchmark server module
+ * @module
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+
+var grpc = require('../../../');
+var serviceProto = grpc.load({
+  root: __dirname + '/../../..',
+  file: 'test/proto/benchmarks/services.proto'}).grpc.testing;
+
+/**
+ * Create a buffer filled with size zeroes
+ * @param {number} size The length of the buffer
+ * @return {Buffer} The new buffer
+ */
+function zeroBuffer(size) {
+  var zeros = new Buffer(size);
+  zeros.fill(0);
+  return zeros;
+}
+
+/**
+ * Handler for the unary benchmark method. Simply responds with a payload
+ * containing the requested number of zero bytes.
+ * @param {Call} call The call object to be handled
+ * @param {function} callback The callback to call with the response
+ */
+function unaryCall(call, callback) {
+  var req = call.request;
+  var payload = {body: zeroBuffer(req.response_size)};
+  callback(null, {payload: payload});
+}
+
+/**
+ * Handler for the streaming benchmark method. Simply responds to each request
+ * with a payload containing the requested number of zero bytes.
+ * @param {Call} call The call object to be handled
+ */
+function streamingCall(call) {
+  call.on('data', function(value) {
+    var payload = {body: zeroBuffer(value.repsonse_size)};
+    call.write({payload: payload});
+  });
+  call.on('end', function() {
+    call.end();
+  });
+}
+
+/**
+ * BenchmarkServer class. Constructed based on parameters from the driver and
+ * stores statistics.
+ * @param {string} host The host to serve on
+ * @param {number} port The port to listen to
+ * @param {tls} Indicates whether TLS should be used
+ */
+function BenchmarkServer(host, port, tls) {
+  var server_creds;
+  var host_override;
+  if (tls) {
+    var key_path = path.join(__dirname, '../test/data/server1.key');
+    var pem_path = path.join(__dirname, '../test/data/server1.pem');
+
+    var key_data = fs.readFileSync(key_path);
+    var pem_data = fs.readFileSync(pem_path);
+    server_creds = grpc.ServerCredentials.createSsl(null,
+                                                    [{private_key: key_data,
+                                                      cert_chain: pem_data}]);
+  } else {
+    server_creds = grpc.ServerCredentials.createInsecure();
+  }
+
+  var server = new grpc.Server();
+  this.port = server.bind(host + ':' + port, server_creds);
+  server.addProtoService(serviceProto.BenchmarkService.service, {
+    unaryCall: unaryCall,
+    streamingCall: streamingCall
+  });
+  this.server = server;
+}
+
+/**
+ * Start the benchmark server.
+ */
+BenchmarkServer.prototype.start = function() {
+  this.server.start();
+  this.last_wall_time = process.hrtime();
+};
+
+/**
+ * Return the port number that the server is bound to.
+ * @return {Number} The port number
+ */
+BenchmarkServer.prototype.getPort = function() {
+  return this.port;
+};
+
+/**
+ * Return current statistics for the server. If reset is set, restart
+ * statistic collection.
+ * @param {boolean} reset Indicates that statistics should be reset
+ * @return {object} Server statistics
+ */
+BenchmarkServer.prototype.mark = function(reset) {
+  var wall_time_diff = process.hrtime(this.last_wall_time);
+  if (reset) {
+    this.last_wall_time = process.hrtime();
+  }
+  return {
+    time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
+    // Not sure how to measure these values
+    time_user: 0,
+    time_system: 0
+  };
+};
+
+/**
+ * Stop the server.
+ * @param {function} callback Called when the server has finished shutting down
+ */
+BenchmarkServer.prototype.stop = function(callback) {
+  this.server.tryShutdown(callback);
+};
+
+module.exports = BenchmarkServer;
diff --git a/src/node/performance/histogram.js b/src/node/performance/histogram.js
new file mode 100644
index 0000000000000000000000000000000000000000..204d7d47dafffc6406602a771a52ac6859e5ab5f
--- /dev/null
+++ b/src/node/performance/histogram.js
@@ -0,0 +1,180 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Histogram module. Exports the Histogram class
+ * @module
+ */
+
+'use strict';
+
+/**
+ * Histogram class. Collects data and exposes a histogram and other statistics.
+ * This data structure is taken directly from src/core/support/histogram.c, but
+ * pared down to the statistics needed for client stats in
+ * test/proto/benchmarks/stats.proto.
+ * @constructor
+ * @param {number} resolution The histogram's bucket resolution. Must be positive
+ * @param {number} max_possible The maximum allowed value. Must be greater than 1
+ */
+function Histogram(resolution, max_possible) {
+  this.resolution = resolution;
+  this.max_possible = max_possible;
+
+  this.sum = 0;
+  this.sum_of_squares = 0;
+  this.multiplier = 1 + resolution;
+  this.count = 0;
+  this.min_seen = max_possible;
+  this.max_seen = 0;
+  this.buckets = [];
+  for (var i = 0; i < this.bucketFor(max_possible) + 1; i++) {
+    this.buckets[i] = 0;
+  }
+}
+
+/**
+ * Get the bucket index for a given value.
+ * @param {number} value The value to check
+ * @return {number} The bucket index
+ */
+Histogram.prototype.bucketFor = function(value) {
+  return Math.floor(Math.log(value) / Math.log(this.multiplier));
+};
+
+/**
+ * Get the minimum value for a given bucket index
+ * @param {number} The bucket index to check
+ * @return {number} The minimum value for that bucket
+ */
+Histogram.prototype.bucketStart = function(index) {
+  return Math.pow(this.multiplier, index);
+};
+
+/**
+ * Add a value to the histogram. This updates all statistics with the new
+ * value. Those statistics should not be modified except with this function
+ * @param {number} value The value to add
+ */
+Histogram.prototype.add = function(value) {
+  // Ensure value is a number
+  value = +value;
+  this.sum += value;
+  this.sum_of_squares += value * value;
+  this.count++;
+  if (value < this.min_seen) {
+    this.min_seen = value;
+  }
+  if (value > this.max_seen) {
+    this.max_seen = value;
+  }
+  this.buckets[this.bucketFor(value)]++;
+};
+
+/**
+ * Get the mean of all added values
+ * @return {number} The mean
+ */
+Histogram.prototype.mean = function() {
+  return this.sum / this.count;
+};
+
+/**
+ * Get the variance of all added values. Used to calulate the standard deviation
+ * @return {number} The variance
+ */
+Histogram.prototype.variance = function() {
+  if (this.count == 0) {
+    return 0;
+  }
+  return (this.sum_of_squares * this.count - this.sum * this.sum) /
+      (this.count * this.count);
+};
+
+/**
+ * Get the standard deviation of all added values
+ * @return {number} The standard deviation
+ */
+Histogram.prototype.stddev = function() {
+  return Math.sqrt(this.variance);
+};
+
+/**
+ * Get the maximum among all added values
+ * @return {number} The maximum
+ */
+Histogram.prototype.maximum = function() {
+  return this.max_seen;
+};
+
+/**
+ * Get the minimum among all added values
+ * @return {number} The minimum
+ */
+Histogram.prototype.minimum = function() {
+  return this.min_seen;
+};
+
+/**
+ * Get the number of all added values
+ * @return {number} The count
+ */
+Histogram.prototype.getCount = function() {
+  return this.count;
+};
+
+/**
+ * Get the sum of all added values
+ * @return {number} The sum
+ */
+Histogram.prototype.getSum = function() {
+  return this.sum;
+};
+
+/**
+ * Get the sum of squares of all added values
+ * @return {number} The sum of squares
+ */
+Histogram.prototype.sumOfSquares = function() {
+  return this.sum_of_squares;
+};
+
+/**
+ * Get the raw histogram as a list of bucket sizes
+ * @return {Array.<number>} The buckets
+ */
+Histogram.prototype.getContents = function() {
+  return this.buckets;
+};
+
+module.exports = Histogram;
diff --git a/src/node/performance/perf_test.js b/src/node/performance/perf_test.js
deleted file mode 100644
index fe51e4a603e09004092eb6ba5d46d42a5dc93e8f..0000000000000000000000000000000000000000
--- a/src/node/performance/perf_test.js
+++ /dev/null
@@ -1,119 +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.
- *
- */
-
-'use strict';
-
-var grpc = require('..');
-var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
-var _ = require('lodash');
-var interop_server = require('../interop/interop_server.js');
-
-function runTest(iterations, callback) {
-  var testServer = interop_server.getServer(0, false);
-  testServer.server.start();
-  var client = new testProto.TestService('localhost:' + testServer.port,
-                                         grpc.credentials.createInsecure());
-
-  function runIterations(finish) {
-    var start = process.hrtime();
-    var intervals = [];
-    function next(i) {
-      if (i >= iterations) {
-        testServer.server.shutdown();
-        var totalDiff = process.hrtime(start);
-        finish({
-          total: totalDiff[0] * 1000000 + totalDiff[1] / 1000,
-          intervals: intervals
-        });
-      } else{
-        var deadline = new Date();
-        deadline.setSeconds(deadline.getSeconds() + 3);
-        var startTime = process.hrtime();
-        client.emptyCall({}, function(err, resp) {
-          var timeDiff = process.hrtime(startTime);
-          intervals[i] = timeDiff[0] * 1000000 + timeDiff[1] / 1000;
-          next(i+1);
-        }, {}, {deadline: deadline});
-      }
-    }
-    next(0);
-  }
-
-  function warmUp(num) {
-    var pending = num;
-    function startCall() {
-      client.emptyCall({}, function(err, resp) {
-        pending--;
-        if (pending === 0) {
-          runIterations(callback);
-        }
-      });
-    }
-    for (var i = 0; i < num; i++) {
-      startCall();
-    }
-  }
-  warmUp(100);
-}
-
-function percentile(arr, pct) {
-  if (pct > 99) {
-    pct = 99;
-  }
-  if (pct < 0) {
-    pct = 0;
-  }
-  var index = Math.floor(arr.length * pct / 100);
-  return arr[index];
-}
-
-if (require.main === module) {
-  var count;
-  if (process.argv.length >= 3) {
-    count = process.argv[2];
-  } else {
-    count = 100;
-  }
-  runTest(count, function(results) {
-    var sorted_intervals = _.sortBy(results.intervals, _.identity);
-    console.log('count:', count);
-    console.log('total time:', results.total, 'us');
-    console.log('median:', percentile(sorted_intervals, 50), 'us');
-    console.log('90th percentile:', percentile(sorted_intervals, 90), 'us');
-    console.log('95th percentile:', percentile(sorted_intervals, 95), 'us');
-    console.log('99th percentile:', percentile(sorted_intervals, 99), 'us');
-    console.log('QPS:', (count / results.total) * 1000000);
-  });
-}
-
-module.exports = runTest;
diff --git a/src/node/performance/qps_test.js b/src/node/performance/qps_test.js
deleted file mode 100644
index 491f47364c08922e29337502b450d66bf440b363..0000000000000000000000000000000000000000
--- a/src/node/performance/qps_test.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/**
- * This script runs a QPS test. It sends requests for a specified length of time
- * with a specified number pending at any one time. It then outputs the measured
- * QPS. Usage:
- * node qps_test.js [--concurrent=count] [--time=seconds]
- * concurrent defaults to 100 and time defaults to 10
- */
-
-'use strict';
-
-var async = require('async');
-var parseArgs = require('minimist');
-
-var grpc = require('..');
-var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
-var interop_server = require('../interop/interop_server.js');
-
-/**
- * Runs the QPS test. Sends requests constantly for the given number of seconds,
- * and keeps concurrent_calls requests pending at all times. When the test ends,
- * the callback is called with the number of calls that completed within the
- * time limit.
- * @param {number} concurrent_calls The number of calls to have pending
- *     simultaneously
- * @param {number} seconds The number of seconds to run the test for
- * @param {function(Error, number)} callback Callback for test completion
- */
-function runTest(concurrent_calls, seconds, callback) {
-  var testServer = interop_server.getServer(0, false);
-  testServer.server.start();
-  var client = new testProto.TestService('localhost:' + testServer.port,
-                                         grpc.credentials.createInsecure());
-
-  var warmup_num = 100;
-
-  /**
-   * Warms up the client to avoid counting startup time in the test result
-   * @param {function(Error)} callback Called when warmup is complete
-   */
-  function warmUp(callback) {
-    var pending = warmup_num;
-    function startCall() {
-      client.emptyCall({}, function(err, resp) {
-        if (err) {
-          callback(err);
-          return;
-        }
-        pending--;
-        if (pending === 0) {
-          callback(null);
-        }
-      });
-    }
-    for (var i = 0; i < warmup_num; i++) {
-      startCall();
-    }
-  }
-  /**
-   * Run the QPS test. Starts concurrent_calls requests, then starts a new
-   * request whenever one completes until time runs out.
-   * @param {function(Error, number)} callback Called when the test is complete.
-   *     The second argument is the number of calls that finished within the
-   *     time limit
-   */
-  function run(callback) {
-    var running = 0;
-    var count = 0;
-    var start = process.hrtime();
-    function responseCallback(err, resp) {
-      if (process.hrtime(start)[0] < seconds) {
-        count += 1;
-        client.emptyCall({}, responseCallback);
-      } else {
-        running -= 1;
-        if (running <= 0) {
-          callback(null, count);
-        }
-      }
-    }
-    for (var i = 0; i < concurrent_calls; i++) {
-      running += 1;
-      client.emptyCall({}, responseCallback);
-    }
-  }
-  async.waterfall([warmUp, run], function(err, count) {
-      testServer.server.shutdown();
-      callback(err, count);
-    });
-}
-
-if (require.main === module) {
-  var argv = parseArgs(process.argv.slice(2), {
-    default: {'concurrent': 100,
-              'time': 10}
-  });
-  runTest(argv.concurrent, argv.time, function(err, count) {
-    if (err) {
-      throw err;
-    }
-    console.log('Concurrent calls:', argv.concurrent);
-    console.log('Time:', argv.time, 'seconds');
-    console.log('QPS:', (count/argv.time));
-  });
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/module.c b/src/node/performance/worker_server.js
similarity index 65%
rename from src/python/grpcio/grpc/_adapter/_c/module.c
rename to src/node/performance/worker_server.js
index 9b93b051f67e4f025654f7cb4405f1c8744900dd..43b86e5ecfa68fcbe7a2bf85fa62cd118298112b 100644
--- a/src/python/grpcio/grpc/_adapter/_c/module.c
+++ b/src/node/performance/worker_server.js
@@ -31,37 +31,33 @@
  *
  */
 
-#include <stdlib.h>
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-
-#include "grpc/_adapter/_c/types.h"
-
-static PyMethodDef c_methods[] = {
-    {NULL}
-};
-
-PyMODINIT_FUNC init_c(void) {
-  PyObject *module;
-
-  module = Py_InitModule3("_c", c_methods,
-                          "Wrappings of C structures and functions.");
-
-  if (pygrpc_module_add_types(module) < 0) {
-    return;
-  }
-
-  if (PyModule_AddStringConstant(
-          module, "PRIMARY_USER_AGENT_KEY",
-          GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) {
-    return;
-  }
+'use strict';
+
+var worker_service_impl = require('./worker_service_impl');
+
+var grpc = require('../../../');
+var serviceProto = grpc.load({
+  root: __dirname + '/../../..',
+  file: 'test/proto/benchmarks/services.proto'}).grpc.testing;
+
+function runServer(port) {
+  var server_creds = grpc.ServerCredentials.createInsecure();
+  var server = new grpc.Server();
+  server.addProtoService(serviceProto.WorkerService.service,
+                         worker_service_impl);
+  var address = '0.0.0.0:' + port;
+  server.bind(address, server_creds);
+  server.start();
+  return server;
+}
 
-  /* GRPC maintains an internal counter of how many times it has been
-     initialized and handles multiple pairs of grpc_init()/grpc_shutdown()
-     invocations accordingly. */
-  grpc_init();
-  atexit(&grpc_shutdown);
+if (require.main === module) {
+  Error.stackTraceLimit = Infinity;
+  var parseArgs = require('minimist');
+  var argv = parseArgs(process.argv, {
+    string: ['driver_port']
+  });
+  runServer(argv.driver_port);
 }
+
+exports.runServer = runServer;
diff --git a/src/node/performance/worker_service_impl.js b/src/node/performance/worker_service_impl.js
new file mode 100644
index 0000000000000000000000000000000000000000..8841ae13c3e194bb3ca47087672403bbef9f0033
--- /dev/null
+++ b/src/node/performance/worker_service_impl.js
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+'use strict';
+
+var BenchmarkClient = require('./benchmark_client');
+var BenchmarkServer = require('./benchmark_server');
+
+exports.runClient = function runClient(call) {
+  var client;
+  call.on('data', function(request) {
+    var stats;
+    switch (request.argtype) {
+      case 'setup':
+      var setup = request.setup;
+      client = new BenchmarkClient(setup.server_targets,
+                                   setup.client_channels,
+                                   setup.histogram_params,
+                                   setup.security_params);
+      client.on('error', function(error) {
+        call.emit('error', error);
+      });
+      switch (setup.load_params.load) {
+        case 'closed_loop':
+        client.startClosedLoop(setup.outstanding_rpcs_per_channel,
+                               setup.rpc_type,
+                               setup.payload_config.simple_params.req_size,
+                               setup.payload_config.simple_params.resp_size);
+        break;
+        case 'poisson':
+        client.startPoisson(setup.outstanding_rpcs_per_channel,
+                            setup.rpc_type, setup.payload_config.req_size,
+                            setup.payload_config.resp_size,
+                            setup.load_params.poisson.offered_load);
+        break;
+        default:
+        call.emit('error', new Error('Unsupported LoadParams type' +
+            setup.load_params.load));
+      }
+      stats = client.mark();
+      call.write({
+        stats: stats
+      });
+      break;
+      case 'mark':
+      if (client) {
+        stats = client.mark(request.mark.reset);
+        call.write({
+          stats: stats
+        });
+      } else {
+        call.emit('error', new Error('Got Mark before ClientConfig'));
+      }
+      break;
+      default:
+      throw new Error('Nonexistent client argtype option: ' + request.argtype);
+    }
+  });
+  call.on('end', function() {
+    client.stop(function() {
+      call.end();
+    });
+  });
+};
+
+exports.runServer = function runServer(call) {
+  var server;
+  call.on('data', function(request) {
+    var stats;
+    switch (request.argtype) {
+      case 'setup':
+      server = new BenchmarkServer(request.setup.host, request.setup.port,
+                                   request.setup.security_params);
+      server.start();
+      stats = server.mark();
+      call.write({
+        stats: stats,
+        port: server.getPort()
+      });
+      break;
+      case 'mark':
+      if (server) {
+        stats = server.mark(request.mark.reset);
+        call.write({
+          stats: stats,
+          port: server.getPort(),
+          cores: 1
+        });
+      } else {
+        call.emit('error', new Error('Got Mark before ServerConfig'));
+      }
+      break;
+      default:
+      throw new Error('Nonexistent server argtype option');
+    }
+  });
+  call.on('end', function() {
+    server.stop(function() {
+      call.end();
+    });
+  });
+};
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index ff10a22e6a9ae650eedc97a5d57ab546a379d7d2..dcbfac18f4647900db5fd9496663d133ecd5f3ba 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -91,7 +91,7 @@ exports.createSsl = ChannelCredentials.createSsl;
  */
 exports.createFromMetadataGenerator = function(metadata_generator) {
   return CallCredentials.createFromPlugin(function(service_url, callback) {
-    metadata_generator(service_url, function(error, metadata) {
+    metadata_generator({service_url: service_url}, function(error, metadata) {
       var code = grpc.status.OK;
       var message = '';
       if (error) {
@@ -114,7 +114,8 @@ exports.createFromMetadataGenerator = function(metadata_generator) {
  * @return {CallCredentials} The resulting credentials object
  */
 exports.createFromGoogleCredential = function(google_credential) {
-  return exports.createFromMetadataGenerator(function(service_url, callback) {
+  return exports.createFromMetadataGenerator(function(auth_context, callback) {
+    var service_url = auth_context.service_url;
     google_credential.getRequestMetadata(service_url, function(err, header) {
       if (err) {
         callback(err);
diff --git a/src/node/src/server.js b/src/node/src/server.js
index d1fb627e6cb3f4be4d404d638fdb21229db423fc..ceaa9f5d1fcbfe840653f98ef1d9599aeff03555 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -100,28 +100,6 @@ function handleError(call, error) {
   call.startBatch(error_batch, function(){});
 }
 
-/**
- * Wait for the client to close, then emit a cancelled event if the client
- * cancelled.
- * @access private
- * @param {grpc.Call} call The call object to wait on
- * @param {EventEmitter} emitter The event emitter to emit the cancelled event
- *     on
- */
-function waitForCancel(call, emitter) {
-  var cancel_batch = {};
-  cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
-  call.startBatch(cancel_batch, function(err, result) {
-    if (err) {
-      emitter.emit('error', err);
-    }
-    if (result.cancelled) {
-      emitter.cancelled = true;
-      emitter.emit('cancelled');
-    }
-  });
-}
-
 /**
  * Send a response to a unary or client streaming call.
  * @access private
@@ -258,6 +236,13 @@ function setUpReadable(stream, deserialize) {
   });
 }
 
+util.inherits(ServerUnaryCall, EventEmitter);
+
+function ServerUnaryCall(call) {
+  EventEmitter.call(this);
+  this.call = call;
+}
+
 util.inherits(ServerWritableStream, Writable);
 
 /**
@@ -311,33 +296,6 @@ function _write(chunk, encoding, callback) {
 
 ServerWritableStream.prototype._write = _write;
 
-/**
- * Send the initial metadata for a writable stream.
- * @param {Metadata} responseMetadata Metadata to send
- */
-function sendMetadata(responseMetadata) {
-  /* jshint validthis: true */
-  var self = this;
-  if (!this.call.metadataSent) {
-    this.call.metadataSent = true;
-    var batch = [];
-    batch[grpc.opType.SEND_INITIAL_METADATA] =
-        responseMetadata._getCoreRepresentation();
-    this.call.startBatch(batch, function(err) {
-      if (err) {
-        self.emit('error', err);
-        return;
-      }
-    });
-  }
-}
-
-/**
- * @inheritdoc
- * @alias module:src/server~ServerWritableStream#sendMetadata
- */
-ServerWritableStream.prototype.sendMetadata = sendMetadata;
-
 util.inherits(ServerReadableStream, Readable);
 
 /**
@@ -427,6 +385,31 @@ function ServerDuplexStream(call, serialize, deserialize) {
 
 ServerDuplexStream.prototype._read = _read;
 ServerDuplexStream.prototype._write = _write;
+
+/**
+ * Send the initial metadata for a writable stream.
+ * @param {Metadata} responseMetadata Metadata to send
+ */
+function sendMetadata(responseMetadata) {
+  /* jshint validthis: true */
+  var self = this;
+  if (!this.call.metadataSent) {
+    this.call.metadataSent = true;
+    var batch = {};
+    batch[grpc.opType.SEND_INITIAL_METADATA] =
+        responseMetadata._getCoreRepresentation();
+    this.call.startBatch(batch, function(err) {
+      if (err) {
+        self.emit('error', err);
+        return;
+      }
+    });
+  }
+}
+
+ServerUnaryCall.prototype.sendMetadata = sendMetadata;
+ServerWritableStream.prototype.sendMetadata = sendMetadata;
+ServerReadableStream.prototype.sendMetadata = sendMetadata;
 ServerDuplexStream.prototype.sendMetadata = sendMetadata;
 
 /**
@@ -438,10 +421,36 @@ function getPeer() {
   return this.call.getPeer();
 }
 
+ServerUnaryCall.prototype.getPeer = getPeer;
 ServerReadableStream.prototype.getPeer = getPeer;
 ServerWritableStream.prototype.getPeer = getPeer;
 ServerDuplexStream.prototype.getPeer = getPeer;
 
+/**
+ * Wait for the client to close, then emit a cancelled event if the client
+ * cancelled.
+ */
+function waitForCancel() {
+  /* jshint validthis: true */
+  var self = this;
+  var cancel_batch = {};
+  cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+  self.call.startBatch(cancel_batch, function(err, result) {
+    if (err) {
+      self.emit('error', err);
+    }
+    if (result.cancelled) {
+      self.cancelled = true;
+      self.emit('cancelled');
+    }
+  });
+}
+
+ServerUnaryCall.prototype.waitForCancel = waitForCancel;
+ServerReadableStream.prototype.waitForCancel = waitForCancel;
+ServerWritableStream.prototype.waitForCancel = waitForCancel;
+ServerDuplexStream.prototype.waitForCancel = waitForCancel;
+
 /**
  * Fully handle a unary call
  * @access private
@@ -450,25 +459,12 @@ ServerDuplexStream.prototype.getPeer = getPeer;
  * @param {Metadata} metadata Metadata from the client
  */
 function handleUnary(call, handler, metadata) {
-  var emitter = new EventEmitter();
-  emitter.sendMetadata = function(responseMetadata) {
-    if (!call.metadataSent) {
-      call.metadataSent = true;
-      var batch = {};
-      batch[grpc.opType.SEND_INITIAL_METADATA] =
-          responseMetadata._getCoreRepresentation();
-      call.startBatch(batch, function() {});
-    }
-  };
-  emitter.getPeer = function() {
-    return call.getPeer();
-  };
+  var emitter = new ServerUnaryCall(call);
   emitter.on('error', function(error) {
     handleError(call, error);
   });
   emitter.metadata = metadata;
-  waitForCancel(call, emitter);
-  emitter.call = call;
+  emitter.waitForCancel();
   var batch = {};
   batch[grpc.opType.RECV_MESSAGE] = true;
   call.startBatch(batch, function(err, result) {
@@ -508,7 +504,7 @@ function handleUnary(call, handler, metadata) {
  */
 function handleServerStreaming(call, handler, metadata) {
   var stream = new ServerWritableStream(call, handler.serialize);
-  waitForCancel(call, stream);
+  stream.waitForCancel();
   stream.metadata = metadata;
   var batch = {};
   batch[grpc.opType.RECV_MESSAGE] = true;
@@ -537,19 +533,10 @@ function handleServerStreaming(call, handler, metadata) {
  */
 function handleClientStreaming(call, handler, metadata) {
   var stream = new ServerReadableStream(call, handler.deserialize);
-  stream.sendMetadata = function(responseMetadata) {
-    if (!call.metadataSent) {
-      call.metadataSent = true;
-      var batch = {};
-      batch[grpc.opType.SEND_INITIAL_METADATA] =
-          responseMetadata._getCoreRepresentation();
-      call.startBatch(batch, function() {});
-    }
-  };
   stream.on('error', function(error) {
     handleError(call, error);
   });
-  waitForCancel(call, stream);
+  stream.waitForCancel();
   stream.metadata = metadata;
   handler.func(stream, function(err, value, trailer, flags) {
     stream.terminate();
@@ -574,7 +561,7 @@ function handleClientStreaming(call, handler, metadata) {
 function handleBidiStreaming(call, handler, metadata) {
   var stream = new ServerDuplexStream(call, handler.serialize,
                                       handler.deserialize);
-  waitForCancel(call, stream);
+  stream.waitForCancel();
   stream.metadata = metadata;
   handler.func(stream);
 }
diff --git a/src/node/test/async_test.js b/src/node/test/async_test.js
index 0af63c379e148e1f3b71b7bf31661668e7162e94..c46e745116ecd2aa01540ca03121058f7b4f53cd 100644
--- a/src/node/test/async_test.js
+++ b/src/node/test/async_test.js
@@ -36,7 +36,7 @@
 var assert = require('assert');
 
 var grpc = require('..');
-var math = grpc.load(__dirname + '/math/math.proto').math;
+var math = grpc.load(__dirname + '/../../proto/math/math.proto').math;
 
 
 /**
diff --git a/src/node/test/math/math.proto b/src/node/test/math/math.proto
deleted file mode 100644
index 311e148c021f66a8ed450e8258c60961314f546f..0000000000000000000000000000000000000000
--- a/src/node/test/math/math.proto
+++ /dev/null
@@ -1,80 +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.
-
-syntax = "proto3";
-
-package math;
-
-message DivArgs {
-  int64 dividend = 1;
-  int64 divisor = 2;
-}
-
-message DivReply {
-  int64 quotient = 1;
-  int64 remainder = 2;
-}
-
-message FibArgs {
-  int64 limit = 1;
-}
-
-message Num {
-  int64 num = 1;
-}
-
-message FibReply {
-  int64 count = 1;
-}
-
-service Math {
-  // Div divides args.dividend by args.divisor and returns the quotient and
-  // remainder.
-  rpc Div (DivArgs) returns (DivReply) {
-  }
-
-  // DivMany accepts an arbitrary number of division args from the client stream
-  // and sends back the results in the reply stream.  The stream continues until
-  // the client closes its end; the server does the same after sending all the
-  // replies.  The stream ends immediately if either end aborts.
-  rpc DivMany (stream DivArgs) returns (stream DivReply) {
-  }
-
-  // Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
-  // generates up to limit numbers; otherwise it continues until the call is
-  // canceled.  Unlike Fib above, Fib has no final FibReply.
-  rpc Fib (FibArgs) returns (stream Num) {
-  }
-
-  // Sum sums a stream of numbers, returning the final result once the stream
-  // is closed.
-  rpc Sum (stream Num) returns (Num) {
-  }
-}
diff --git a/src/node/test/math/math_server.js b/src/node/test/math/math_server.js
index 9d06596f3d3c3bdcf238a77f906681891dd2e18f..9f67c52ab0c5a6ad51ea088f7632413628a36cf2 100644
--- a/src/node/test/math/math_server.js
+++ b/src/node/test/math/math_server.js
@@ -34,7 +34,8 @@
 'use strict';
 
 var grpc = require('../..');
-var math = grpc.load(__dirname + '/math.proto').math;
+var math = grpc.load(__dirname + '/../../../proto/math/math.proto').math;
+
 
 /**
  * Server function for division. Provides the /Math/DivMany and /Math/Div
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 6361d97857aa88bed6da0ebbfd0cedbe97fb8f57..3d446105364642bf822aabb5a37d193a9ea4ebaf 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -36,7 +36,7 @@
 var assert = require('assert');
 
 var grpc = require('..');
-var math = grpc.load(__dirname + '/math/math.proto').math;
+var math = grpc.load(__dirname + '/../../proto/math/math.proto').math;
 
 /**
  * Client to use to make requests to a running server.
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 39673e4e05beb89543efcbd13097c970488ec48a..fc765ed7314ff8b1239a56ca49d9e3c8ab19148a 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -41,7 +41,8 @@ var ProtoBuf = require('protobufjs');
 
 var grpc = require('..');
 
-var math_proto = ProtoBuf.loadProtoFile(__dirname + '/math/math.proto');
+var math_proto = ProtoBuf.loadProtoFile(__dirname +
+    '/../../proto/math/math.proto');
 
 var mathService = math_proto.lookup('math.Math');
 
@@ -312,6 +313,54 @@ describe('Generic client and server', function() {
     });
   });
 });
+describe('Server-side getPeer', function() {
+  function toString(val) {
+    return val.toString();
+  }
+  function toBuffer(str) {
+    return new Buffer(str);
+  }
+  var string_service_attrs = {
+    'getPeer' : {
+      path: '/string/getPeer',
+      requestStream: false,
+      responseStream: false,
+      requestSerialize: toBuffer,
+      requestDeserialize: toString,
+      responseSerialize: toBuffer,
+      responseDeserialize: toString
+    }
+  };
+  var client;
+  var server;
+  before(function() {
+    server = new grpc.Server();
+    server.addService(string_service_attrs, {
+      getPeer: function(call, callback) {
+        try {
+          callback(null, call.getPeer());
+        } catch (e) {
+          call.emit('error', e);
+        }
+      }
+    });
+    var port = server.bind('localhost:0', server_insecure_creds);
+    server.start();
+    var Client = grpc.makeGenericClientConstructor(string_service_attrs);
+    client = new Client('localhost:' + port,
+                        grpc.credentials.createInsecure());
+  });
+  after(function() {
+    server.forceShutdown();
+  });
+  it('should respond with a string representing the client', function(done) {
+    client.getPeer('', function(err, response) {
+      assert.ifError(err);
+      // We don't expect a specific value, just that it worked without error
+      done();
+    });
+  });
+});
 describe('Echo metadata', function() {
   var client;
   var server;
diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec
new file mode 100644
index 0000000000000000000000000000000000000000..f5b738203d6d6ca3d69d5bf60b8ba2dfed0b1375
--- /dev/null
+++ b/src/objective-c/BoringSSL.podspec
@@ -0,0 +1,1428 @@
+# BoringSSL CocoaPods podspec
+
+# 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.
+
+Pod::Spec.new do |s|
+  s.name     = 'BoringSSL'
+  s.version  = '1.0'
+  s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
+  # Adapted from the homepage:
+  s.description = <<-DESC
+    BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.
+
+    Although BoringSSL is an open source project, it is not intended for general use, as OpenSSL is.
+    We don’t recommend that third parties depend upon it. Doing so is likely to be frustrating
+    because there are no guarantees of API stability. Only the latest version of this pod is
+    supported, and every new version is a new major version.
+
+    We update Google libraries and programs that use BoringSSL as needed when deciding to make API
+    changes. This allows us to mostly avoid compromises in the name of compatibility. It works for
+    us, but it may not work for you.
+
+    As a Cocoapods pod, it has the advantage over OpenSSL's pods that the library doesn't need to
+    be precompiled. This eliminates the 10 - 20 minutes of wait the first time a user does "pod
+    install", lets it be used as a dynamic framework (pending solution of Cocoapods' issue #4605),
+    and works with bitcode automatically. It's also thought to be smaller than OpenSSL (which takes
+    1MB - 2MB per ARM architecture), but we don't have specific numbers yet.
+
+    BoringSSL arose because Google used OpenSSL for many years in various ways and, over time, built
+    up a large number of patches that were maintained while tracking upstream OpenSSL. As Google’s
+    product portfolio became more complex, more copies of OpenSSL sprung up and the effort involved
+    in maintaining all these patches in multiple places was growing steadily.
+
+    Currently BoringSSL is the SSL library in Chrome/Chromium, Android (but it’s not part of the
+    NDK) and a number of other apps/programs.
+  DESC
+  s.homepage = 'https://boringssl.googlesource.com/boringssl/'
+  s.documentation_url = 'https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html'
+  s.license  = { :type => 'Mixed', :file => 'LICENSE' }
+  # "The name and email addresses of the library maintainers, not the Podspec maintainer."
+  s.authors  = 'Adam Langley', 'David Benjamin', 'Matt Braithwaite'
+
+  s.source = { :git => 'https://boringssl.googlesource.com/boringssl',
+               :tag => 'version_for_cocoapods_1.0' }
+
+  s.source_files = 'ssl/*.{h,c}',
+                   'ssl/**/*.{h,c}',
+                   '*.{h,c}',
+                   'crypto/*.{h,c}',
+                   'crypto/**/*.{h,c}',
+                   'include/openssl/*.h'
+
+  s.public_header_files = 'include/openssl/*.h'
+  s.header_mappings_dir = 'include'
+
+  s.exclude_files = "**/*_test.*"
+
+  # We don't need to inhibit all warnings; only -Wno-shorten-64-to-32. But Cocoapods' linter doesn't
+  # want that for some reason.
+  s.compiler_flags = '-DOPENSSL_NO_ASM', '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
+  s.requires_arc = false
+
+  s.prepare_command = <<-END_OF_COMMAND
+    # Replace "const BIGNUM *I" in rsa.h with a lowercase i, as the former fails when including
+    # OpenSSL in a Swift bridging header (complex.h defines "I", and it's as if the compiler
+    # included it in every bridged header).
+    sed -E -i '.back' 's/\\*I,/*i,/g' include/openssl/rsa.h
+
+    # This is a bit ridiculous, but requiring people to install Go in order to build is slightly
+    # more ridiculous IMO. To save you from scrolling, this is the last part of the podspec.
+    # TODO(jcanizales): Translate err_data_generate.go into a Bash or Ruby script.
+    cat > err_data.c <<EOF
+      /* Copyright (c) 2015, Google Inc.
+       *
+       * Permission to use, copy, modify, and/or distribute this software for any
+       * purpose with or without fee is hereby granted, provided that the above
+       * copyright notice and this permission notice appear in all copies.
+       *
+       * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+       * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+       * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+       * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+       * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+       * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+       * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+       /* This file was generated by err_data_generate.go. */
+
+      #include <openssl/base.h>
+      #include <openssl/err.h>
+      #include <openssl/type_check.h>
+
+
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_NONE == 1, library_values_changed_1);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_SYS == 2, library_values_changed_2);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_BN == 3, library_values_changed_3);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_RSA == 4, library_values_changed_4);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_DH == 5, library_values_changed_5);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_EVP == 6, library_values_changed_6);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_BUF == 7, library_values_changed_7);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_OBJ == 8, library_values_changed_8);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_PEM == 9, library_values_changed_9);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_DSA == 10, library_values_changed_10);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_X509 == 11, library_values_changed_11);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_ASN1 == 12, library_values_changed_12);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_CONF == 13, library_values_changed_13);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_CRYPTO == 14, library_values_changed_14);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_EC == 15, library_values_changed_15);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_SSL == 16, library_values_changed_16);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_BIO == 17, library_values_changed_17);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS7 == 18, library_values_changed_18);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS8 == 19, library_values_changed_19);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_X509V3 == 20, library_values_changed_20);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_RAND == 21, library_values_changed_21);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_ENGINE == 22, library_values_changed_22);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_OCSP == 23, library_values_changed_23);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_UI == 24, library_values_changed_24);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_COMP == 25, library_values_changed_25);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDSA == 26, library_values_changed_26);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDH == 27, library_values_changed_27);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_HMAC == 28, library_values_changed_28);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_DIGEST == 29, library_values_changed_29);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_CIPHER == 30, library_values_changed_30);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_HKDF == 31, library_values_changed_31);
+      OPENSSL_COMPILE_ASSERT(ERR_LIB_USER == 32, library_values_changed_32);
+      OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == 33, library_values_changed_num);
+
+      const uint32_t kOpenSSLReasonValues[] = {
+          0xc3207ba,
+          0xc3287d4,
+          0xc3307e3,
+          0xc3387f3,
+          0xc340802,
+          0xc34881b,
+          0xc350827,
+          0xc358844,
+          0xc360856,
+          0xc368864,
+          0xc370874,
+          0xc378881,
+          0xc380891,
+          0xc38889c,
+          0xc3908b2,
+          0xc3988c1,
+          0xc3a08d5,
+          0xc3a87c7,
+          0xc3b00b0,
+          0x10321478,
+          0x10329484,
+          0x1033149d,
+          0x103394b0,
+          0x10340de1,
+          0x103494cf,
+          0x103514e4,
+          0x10359516,
+          0x1036152f,
+          0x10369544,
+          0x10371562,
+          0x10379571,
+          0x1038158d,
+          0x103895a8,
+          0x103915b7,
+          0x103995d3,
+          0x103a15ee,
+          0x103a9605,
+          0x103b1616,
+          0x103b962a,
+          0x103c1649,
+          0x103c9658,
+          0x103d166f,
+          0x103d9682,
+          0x103e0b6c,
+          0x103e96b3,
+          0x103f16c6,
+          0x103f96e0,
+          0x104016f0,
+          0x10409704,
+          0x1041171a,
+          0x10419732,
+          0x10421747,
+          0x1042975b,
+          0x1043176d,
+          0x104385d0,
+          0x104408c1,
+          0x10449782,
+          0x10451799,
+          0x104597ae,
+          0x104617bc,
+          0x10469695,
+          0x104714f7,
+          0x104787c7,
+          0x104800b0,
+          0x104894c3,
+          0x14320b4f,
+          0x14328b5d,
+          0x14330b6c,
+          0x14338b7e,
+          0x18320083,
+          0x18328e47,
+          0x18340e75,
+          0x18348e89,
+          0x18358ec0,
+          0x18368eed,
+          0x18370f00,
+          0x18378f14,
+          0x18380f38,
+          0x18388f46,
+          0x18390f5c,
+          0x18398f70,
+          0x183a0f80,
+          0x183b0f90,
+          0x183b8fa5,
+          0x183c8fd0,
+          0x183d0fe4,
+          0x183d8ff4,
+          0x183e0b9b,
+          0x183e9001,
+          0x183f1013,
+          0x183f901e,
+          0x1840102e,
+          0x1840903f,
+          0x18411050,
+          0x18419062,
+          0x1842108b,
+          0x184290bd,
+          0x184310cc,
+          0x18451135,
+          0x1845914b,
+          0x18461166,
+          0x18468ed8,
+          0x184709d9,
+          0x18478094,
+          0x18480fbc,
+          0x18489101,
+          0x18490e5d,
+          0x18498e9e,
+          0x184a119c,
+          0x184a9119,
+          0x184b10e0,
+          0x184b8e37,
+          0x184c10a4,
+          0x184c866b,
+          0x184d1181,
+          0x203211c3,
+          0x243211cf,
+          0x24328907,
+          0x243311e1,
+          0x243391ee,
+          0x243411fb,
+          0x2434920d,
+          0x2435121c,
+          0x24359239,
+          0x24361246,
+          0x24369254,
+          0x24371262,
+          0x24379270,
+          0x24381279,
+          0x24389286,
+          0x24391299,
+          0x28320b8f,
+          0x28328b9b,
+          0x28330b6c,
+          0x28338bae,
+          0x2c322c0b,
+          0x2c32ac19,
+          0x2c332c2b,
+          0x2c33ac3d,
+          0x2c342c51,
+          0x2c34ac63,
+          0x2c352c7e,
+          0x2c35ac90,
+          0x2c362ca3,
+          0x2c3682f3,
+          0x2c372cb0,
+          0x2c37acc2,
+          0x2c382cd5,
+          0x2c38ace3,
+          0x2c392cf3,
+          0x2c39ad05,
+          0x2c3a2d19,
+          0x2c3aad2a,
+          0x2c3b1359,
+          0x2c3bad3b,
+          0x2c3c2d4f,
+          0x2c3cad65,
+          0x2c3d2d7e,
+          0x2c3dadac,
+          0x2c3e2dba,
+          0x2c3eadd2,
+          0x2c3f2dea,
+          0x2c3fadf7,
+          0x2c402e1a,
+          0x2c40ae39,
+          0x2c4111c3,
+          0x2c41ae4a,
+          0x2c422e5d,
+          0x2c429135,
+          0x2c432e6e,
+          0x2c4386a2,
+          0x2c442d9b,
+          0x30320000,
+          0x30328015,
+          0x3033001f,
+          0x30338038,
+          0x3034004a,
+          0x30348064,
+          0x3035006b,
+          0x30358083,
+          0x30360094,
+          0x303680a1,
+          0x303700b0,
+          0x303780bd,
+          0x303800d0,
+          0x303880eb,
+          0x30390100,
+          0x30398114,
+          0x303a0128,
+          0x303a8139,
+          0x303b0152,
+          0x303b816f,
+          0x303c017d,
+          0x303c8191,
+          0x303d01a1,
+          0x303d81ba,
+          0x303e01ca,
+          0x303e81dd,
+          0x303f01ec,
+          0x303f81f8,
+          0x3040020d,
+          0x3040821d,
+          0x30410234,
+          0x30418241,
+          0x30420254,
+          0x30428263,
+          0x30430278,
+          0x30438299,
+          0x304402ac,
+          0x304482bf,
+          0x304502d8,
+          0x304582f3,
+          0x30460310,
+          0x30468329,
+          0x30470337,
+          0x30478348,
+          0x30480357,
+          0x3048836f,
+          0x30490381,
+          0x30498395,
+          0x304a03b4,
+          0x304a83c7,
+          0x304b03d2,
+          0x304b83e1,
+          0x304c03f2,
+          0x304c83fe,
+          0x304d0414,
+          0x304d8422,
+          0x304e0438,
+          0x304e844a,
+          0x304f045c,
+          0x304f846f,
+          0x30500482,
+          0x30508493,
+          0x305104a3,
+          0x305184bb,
+          0x305204d0,
+          0x305284e8,
+          0x305304fc,
+          0x30538514,
+          0x3054052d,
+          0x30548546,
+          0x30550563,
+          0x3055856e,
+          0x30560586,
+          0x30568596,
+          0x305705a7,
+          0x305785ba,
+          0x305805d0,
+          0x305885d9,
+          0x305905ee,
+          0x30598601,
+          0x305a0610,
+          0x305a8630,
+          0x305b063f,
+          0x305b864b,
+          0x305c066b,
+          0x305c8687,
+          0x305d0698,
+          0x305d86a2,
+          0x34320ac9,
+          0x34328add,
+          0x34330afa,
+          0x34338b0d,
+          0x34340b1c,
+          0x34348b39,
+          0x3c320083,
+          0x3c328bd8,
+          0x3c330bf1,
+          0x3c338c0c,
+          0x3c340c29,
+          0x3c348c44,
+          0x3c350c5f,
+          0x3c358c74,
+          0x3c360c8d,
+          0x3c368ca5,
+          0x3c370cb6,
+          0x3c378cc4,
+          0x3c380cd1,
+          0x3c388ce5,
+          0x3c390b9b,
+          0x3c398cf9,
+          0x3c3a0d0d,
+          0x3c3a8881,
+          0x3c3b0d1d,
+          0x3c3b8d38,
+          0x3c3c0d4a,
+          0x3c3c8d60,
+          0x3c3d0d6a,
+          0x3c3d8d7e,
+          0x3c3e0d8c,
+          0x3c3e8db1,
+          0x3c3f0bc4,
+          0x3c3f8d9a,
+          0x403217d3,
+          0x403297e9,
+          0x40331817,
+          0x40339821,
+          0x40341838,
+          0x40349856,
+          0x40351866,
+          0x40359878,
+          0x40361885,
+          0x40369891,
+          0x403718a6,
+          0x403798bb,
+          0x403818cd,
+          0x403898d8,
+          0x403918ea,
+          0x40398de1,
+          0x403a18fa,
+          0x403a990d,
+          0x403b192e,
+          0x403b993f,
+          0x403c194f,
+          0x403c8064,
+          0x403d195b,
+          0x403d9977,
+          0x403e198d,
+          0x403e999c,
+          0x403f19af,
+          0x403f99c9,
+          0x404019d7,
+          0x404099ec,
+          0x40411a00,
+          0x40419a1d,
+          0x40421a36,
+          0x40429a51,
+          0x40431a6a,
+          0x40439a7d,
+          0x40441a91,
+          0x40449aa9,
+          0x40451af4,
+          0x40459b02,
+          0x40461b20,
+          0x40468094,
+          0x40471b35,
+          0x40479b47,
+          0x40481b6b,
+          0x40489b99,
+          0x40491bad,
+          0x40499bc2,
+          0x404a1bdb,
+          0x404a9c15,
+          0x404b1c46,
+          0x404b9c7c,
+          0x404c1c97,
+          0x404c9cb1,
+          0x404d1cc8,
+          0x404d9cf0,
+          0x404e1d07,
+          0x404e9d23,
+          0x404f1d3f,
+          0x404f9d60,
+          0x40501d82,
+          0x40509d9e,
+          0x40511db2,
+          0x40519dbf,
+          0x40521dd6,
+          0x40529de6,
+          0x40531df6,
+          0x40539e0a,
+          0x40541e25,
+          0x40549e35,
+          0x40551e4c,
+          0x40559e5b,
+          0x40561e88,
+          0x40569ea0,
+          0x40571ebc,
+          0x40579ed5,
+          0x40581ee8,
+          0x40589efd,
+          0x40591f20,
+          0x40599f4b,
+          0x405a1f58,
+          0x405a9f71,
+          0x405b1f89,
+          0x405b9f9c,
+          0x405c1fb1,
+          0x405c9fc3,
+          0x405d1fd8,
+          0x405d9fe8,
+          0x405e2001,
+          0x405ea015,
+          0x405f2025,
+          0x405fa03d,
+          0x4060204e,
+          0x4060a061,
+          0x40612072,
+          0x4061a090,
+          0x406220a1,
+          0x4062a0ae,
+          0x406320c5,
+          0x4063a106,
+          0x4064211d,
+          0x4064a12a,
+          0x40652138,
+          0x4065a15a,
+          0x40662182,
+          0x4066a197,
+          0x406721ae,
+          0x4067a1bf,
+          0x406821d0,
+          0x4068a1e1,
+          0x406921f6,
+          0x4069a20d,
+          0x406a221e,
+          0x406aa237,
+          0x406b2252,
+          0x406ba269,
+          0x406c22d6,
+          0x406ca2f7,
+          0x406d230a,
+          0x406da32b,
+          0x406e2346,
+          0x406ea38f,
+          0x406f23b0,
+          0x406fa3d6,
+          0x407023f6,
+          0x4070a412,
+          0x4071259f,
+          0x4071a5c2,
+          0x407225d8,
+          0x4072a5f7,
+          0x4073260f,
+          0x4073a62f,
+          0x40742859,
+          0x4074a87e,
+          0x40752899,
+          0x4075a8b8,
+          0x407628e7,
+          0x4076a90f,
+          0x40772940,
+          0x4077a95f,
+          0x40782999,
+          0x4078a9b0,
+          0x407929c3,
+          0x4079a9e0,
+          0x407a0782,
+          0x407aa9f2,
+          0x407b2a05,
+          0x407baa1e,
+          0x407c2a36,
+          0x407c90bd,
+          0x407d2a4a,
+          0x407daa64,
+          0x407e2a75,
+          0x407eaa89,
+          0x407f2a97,
+          0x407faab2,
+          0x40801286,
+          0x4080aad7,
+          0x40812af9,
+          0x4081ab14,
+          0x40822b29,
+          0x4082ab41,
+          0x40832b59,
+          0x4083ab70,
+          0x40842b86,
+          0x4084ab92,
+          0x40852ba5,
+          0x4085abba,
+          0x40862bcc,
+          0x4086abe1,
+          0x40872bea,
+          0x40879cde,
+          0x40880083,
+          0x4088a0e5,
+          0x40890a17,
+          0x4089a281,
+          0x408a1bfe,
+          0x408aa2ab,
+          0x408b2928,
+          0x408ba984,
+          0x408c2361,
+          0x408c9c2f,
+          0x408d1c64,
+          0x408d9e76,
+          0x408e1ab9,
+          0x408e9add,
+          0x408f1f2e,
+          0x408f9b8b,
+          0x41f424ca,
+          0x41f9255c,
+          0x41fe244f,
+          0x41fea680,
+          0x41ff2771,
+          0x420324e3,
+          0x42082505,
+          0x4208a541,
+          0x42092433,
+          0x4209a57b,
+          0x420a248a,
+          0x420aa46a,
+          0x420b24aa,
+          0x420ba523,
+          0x420c278d,
+          0x420ca64d,
+          0x420d2667,
+          0x420da69e,
+          0x421226b8,
+          0x42172754,
+          0x4217a6fa,
+          0x421c271c,
+          0x421f26d7,
+          0x422127a4,
+          0x42262737,
+          0x422b283d,
+          0x422ba806,
+          0x422c2825,
+          0x422ca7e0,
+          0x422d27bf,
+          0x443206ad,
+          0x443286bc,
+          0x443306c8,
+          0x443386d6,
+          0x443406e9,
+          0x443486fa,
+          0x44350701,
+          0x4435870b,
+          0x4436071e,
+          0x44368734,
+          0x44370746,
+          0x44378753,
+          0x44380762,
+          0x4438876a,
+          0x44390782,
+          0x44398790,
+          0x443a07a3,
+          0x4c3212b0,
+          0x4c3292c0,
+          0x4c3312d3,
+          0x4c3392f3,
+          0x4c340094,
+          0x4c3480b0,
+          0x4c3512ff,
+          0x4c35930d,
+          0x4c361329,
+          0x4c36933c,
+          0x4c37134b,
+          0x4c379359,
+          0x4c38136e,
+          0x4c38937a,
+          0x4c39139a,
+          0x4c3993c4,
+          0x4c3a13dd,
+          0x4c3a93f6,
+          0x4c3b05d0,
+          0x4c3b940f,
+          0x4c3c1421,
+          0x4c3c9430,
+          0x4c3d10bd,
+          0x4c3d9449,
+          0x4c3e1456,
+          0x50322e80,
+          0x5032ae8f,
+          0x50332e9a,
+          0x5033aeaa,
+          0x50342ec3,
+          0x5034aedd,
+          0x50352eeb,
+          0x5035af01,
+          0x50362f13,
+          0x5036af29,
+          0x50372f42,
+          0x5037af55,
+          0x50382f6d,
+          0x5038af7e,
+          0x50392f93,
+          0x5039afa7,
+          0x503a2fc7,
+          0x503aafdd,
+          0x503b2ff5,
+          0x503bb007,
+          0x503c3023,
+          0x503cb03a,
+          0x503d3053,
+          0x503db069,
+          0x503e3076,
+          0x503eb08c,
+          0x503f309e,
+          0x503f8348,
+          0x504030b1,
+          0x5040b0c1,
+          0x504130db,
+          0x5041b0ea,
+          0x50423104,
+          0x5042b121,
+          0x50433131,
+          0x5043b141,
+          0x50443150,
+          0x50448414,
+          0x50453164,
+          0x5045b182,
+          0x50463195,
+          0x5046b1ab,
+          0x504731bd,
+          0x5047b1d2,
+          0x504831f8,
+          0x5048b206,
+          0x50493219,
+          0x5049b22e,
+          0x504a3244,
+          0x504ab254,
+          0x504b3274,
+          0x504bb287,
+          0x504c32aa,
+          0x504cb2d8,
+          0x504d32ea,
+          0x504db307,
+          0x504e3322,
+          0x504eb33e,
+          0x504f3350,
+          0x504fb367,
+          0x50503376,
+          0x50508687,
+          0x50513389,
+          0x58320e1f,
+          0x68320de1,
+          0x68328b9b,
+          0x68330bae,
+          0x68338def,
+          0x68340dff,
+          0x683480b0,
+          0x6c320dbd,
+          0x6c328b7e,
+          0x6c330dc8,
+          0x7432098d,
+          0x783208f2,
+          0x78328907,
+          0x78330913,
+          0x78338083,
+          0x78340922,
+          0x78348937,
+          0x78350956,
+          0x78358978,
+          0x7836098d,
+          0x783689a3,
+          0x783709b3,
+          0x783789c6,
+          0x783809d9,
+          0x783889eb,
+          0x783909f8,
+          0x78398a17,
+          0x783a0a2c,
+          0x783a8a3a,
+          0x783b0a44,
+          0x783b8a58,
+          0x783c0a6f,
+          0x783c8a84,
+          0x783d0a9b,
+          0x783d8ab0,
+          0x783e0a06,
+          0x7c3211b2,
+      };
+
+      const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
+
+      const char kOpenSSLReasonStringData[] =
+          "ASN1_LENGTH_MISMATCH\\0"
+          "AUX_ERROR\\0"
+          "BAD_GET_ASN1_OBJECT_CALL\\0"
+          "BAD_OBJECT_HEADER\\0"
+          "BMPSTRING_IS_WRONG_LENGTH\\0"
+          "BN_LIB\\0"
+          "BOOLEAN_IS_WRONG_LENGTH\\0"
+          "BUFFER_TOO_SMALL\\0"
+          "DECODE_ERROR\\0"
+          "DEPTH_EXCEEDED\\0"
+          "ENCODE_ERROR\\0"
+          "ERROR_GETTING_TIME\\0"
+          "EXPECTING_AN_ASN1_SEQUENCE\\0"
+          "EXPECTING_AN_INTEGER\\0"
+          "EXPECTING_AN_OBJECT\\0"
+          "EXPECTING_A_BOOLEAN\\0"
+          "EXPECTING_A_TIME\\0"
+          "EXPLICIT_LENGTH_MISMATCH\\0"
+          "EXPLICIT_TAG_NOT_CONSTRUCTED\\0"
+          "FIELD_MISSING\\0"
+          "FIRST_NUM_TOO_LARGE\\0"
+          "HEADER_TOO_LONG\\0"
+          "ILLEGAL_BITSTRING_FORMAT\\0"
+          "ILLEGAL_BOOLEAN\\0"
+          "ILLEGAL_CHARACTERS\\0"
+          "ILLEGAL_FORMAT\\0"
+          "ILLEGAL_HEX\\0"
+          "ILLEGAL_IMPLICIT_TAG\\0"
+          "ILLEGAL_INTEGER\\0"
+          "ILLEGAL_NESTED_TAGGING\\0"
+          "ILLEGAL_NULL\\0"
+          "ILLEGAL_NULL_VALUE\\0"
+          "ILLEGAL_OBJECT\\0"
+          "ILLEGAL_OPTIONAL_ANY\\0"
+          "ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE\\0"
+          "ILLEGAL_TAGGED_ANY\\0"
+          "ILLEGAL_TIME_VALUE\\0"
+          "INTEGER_NOT_ASCII_FORMAT\\0"
+          "INTEGER_TOO_LARGE_FOR_LONG\\0"
+          "INVALID_BIT_STRING_BITS_LEFT\\0"
+          "INVALID_BMPSTRING_LENGTH\\0"
+          "INVALID_DIGIT\\0"
+          "INVALID_MODIFIER\\0"
+          "INVALID_NUMBER\\0"
+          "INVALID_OBJECT_ENCODING\\0"
+          "INVALID_SEPARATOR\\0"
+          "INVALID_TIME_FORMAT\\0"
+          "INVALID_UNIVERSALSTRING_LENGTH\\0"
+          "INVALID_UTF8STRING\\0"
+          "LIST_ERROR\\0"
+          "MALLOC_FAILURE\\0"
+          "MISSING_ASN1_EOS\\0"
+          "MISSING_EOC\\0"
+          "MISSING_SECOND_NUMBER\\0"
+          "MISSING_VALUE\\0"
+          "MSTRING_NOT_UNIVERSAL\\0"
+          "MSTRING_WRONG_TAG\\0"
+          "NESTED_ASN1_ERROR\\0"
+          "NESTED_ASN1_STRING\\0"
+          "NON_HEX_CHARACTERS\\0"
+          "NOT_ASCII_FORMAT\\0"
+          "NOT_ENOUGH_DATA\\0"
+          "NO_MATCHING_CHOICE_TYPE\\0"
+          "NULL_IS_WRONG_LENGTH\\0"
+          "OBJECT_NOT_ASCII_FORMAT\\0"
+          "ODD_NUMBER_OF_CHARS\\0"
+          "SECOND_NUMBER_TOO_LARGE\\0"
+          "SEQUENCE_LENGTH_MISMATCH\\0"
+          "SEQUENCE_NOT_CONSTRUCTED\\0"
+          "SEQUENCE_OR_SET_NEEDS_CONFIG\\0"
+          "SHORT_LINE\\0"
+          "STREAMING_NOT_SUPPORTED\\0"
+          "STRING_TOO_LONG\\0"
+          "STRING_TOO_SHORT\\0"
+          "TAG_VALUE_TOO_HIGH\\0"
+          "TIME_NOT_ASCII_FORMAT\\0"
+          "TOO_LONG\\0"
+          "TYPE_NOT_CONSTRUCTED\\0"
+          "TYPE_NOT_PRIMITIVE\\0"
+          "UNEXPECTED_EOC\\0"
+          "UNIVERSALSTRING_IS_WRONG_LENGTH\\0"
+          "UNKNOWN_FORMAT\\0"
+          "UNKNOWN_TAG\\0"
+          "UNSUPPORTED_ANY_DEFINED_BY_TYPE\\0"
+          "UNSUPPORTED_PUBLIC_KEY_TYPE\\0"
+          "UNSUPPORTED_TYPE\\0"
+          "WRONG_TAG\\0"
+          "WRONG_TYPE\\0"
+          "BAD_FOPEN_MODE\\0"
+          "BROKEN_PIPE\\0"
+          "CONNECT_ERROR\\0"
+          "ERROR_SETTING_NBIO\\0"
+          "INVALID_ARGUMENT\\0"
+          "IN_USE\\0"
+          "KEEPALIVE\\0"
+          "NBIO_CONNECT_ERROR\\0"
+          "NO_HOSTNAME_SPECIFIED\\0"
+          "NO_PORT_SPECIFIED\\0"
+          "NO_SUCH_FILE\\0"
+          "NULL_PARAMETER\\0"
+          "SYS_LIB\\0"
+          "UNABLE_TO_CREATE_SOCKET\\0"
+          "UNINITIALIZED\\0"
+          "UNSUPPORTED_METHOD\\0"
+          "WRITE_TO_READ_ONLY_BIO\\0"
+          "ARG2_LT_ARG3\\0"
+          "BAD_ENCODING\\0"
+          "BAD_RECIPROCAL\\0"
+          "BIGNUM_TOO_LONG\\0"
+          "BITS_TOO_SMALL\\0"
+          "CALLED_WITH_EVEN_MODULUS\\0"
+          "DIV_BY_ZERO\\0"
+          "EXPAND_ON_STATIC_BIGNUM_DATA\\0"
+          "INPUT_NOT_REDUCED\\0"
+          "INVALID_RANGE\\0"
+          "NEGATIVE_NUMBER\\0"
+          "NOT_A_SQUARE\\0"
+          "NOT_INITIALIZED\\0"
+          "NO_INVERSE\\0"
+          "PRIVATE_KEY_TOO_LARGE\\0"
+          "P_IS_NOT_PRIME\\0"
+          "TOO_MANY_ITERATIONS\\0"
+          "TOO_MANY_TEMPORARY_VARIABLES\\0"
+          "AES_KEY_SETUP_FAILED\\0"
+          "BAD_DECRYPT\\0"
+          "BAD_KEY_LENGTH\\0"
+          "CTRL_NOT_IMPLEMENTED\\0"
+          "CTRL_OPERATION_NOT_IMPLEMENTED\\0"
+          "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH\\0"
+          "INITIALIZATION_ERROR\\0"
+          "INPUT_NOT_INITIALIZED\\0"
+          "INVALID_AD_SIZE\\0"
+          "INVALID_KEY_LENGTH\\0"
+          "INVALID_NONCE_SIZE\\0"
+          "INVALID_OPERATION\\0"
+          "IV_TOO_LARGE\\0"
+          "NO_CIPHER_SET\\0"
+          "NO_DIRECTION_SET\\0"
+          "OUTPUT_ALIASES_INPUT\\0"
+          "TAG_TOO_LARGE\\0"
+          "TOO_LARGE\\0"
+          "UNSUPPORTED_AD_SIZE\\0"
+          "UNSUPPORTED_INPUT_SIZE\\0"
+          "UNSUPPORTED_KEY_SIZE\\0"
+          "UNSUPPORTED_NONCE_SIZE\\0"
+          "UNSUPPORTED_TAG_SIZE\\0"
+          "WRONG_FINAL_BLOCK_LENGTH\\0"
+          "LIST_CANNOT_BE_NULL\\0"
+          "MISSING_CLOSE_SQUARE_BRACKET\\0"
+          "MISSING_EQUAL_SIGN\\0"
+          "NO_CLOSE_BRACE\\0"
+          "UNABLE_TO_CREATE_NEW_SECTION\\0"
+          "VARIABLE_HAS_NO_VALUE\\0"
+          "BAD_GENERATOR\\0"
+          "INVALID_PUBKEY\\0"
+          "MODULUS_TOO_LARGE\\0"
+          "NO_PRIVATE_VALUE\\0"
+          "BAD_Q_VALUE\\0"
+          "MISSING_PARAMETERS\\0"
+          "NEED_NEW_SETUP_VALUES\\0"
+          "BIGNUM_OUT_OF_RANGE\\0"
+          "COORDINATES_OUT_OF_RANGE\\0"
+          "D2I_ECPKPARAMETERS_FAILURE\\0"
+          "EC_GROUP_NEW_BY_NAME_FAILURE\\0"
+          "GROUP2PKPARAMETERS_FAILURE\\0"
+          "I2D_ECPKPARAMETERS_FAILURE\\0"
+          "INCOMPATIBLE_OBJECTS\\0"
+          "INVALID_COMPRESSED_POINT\\0"
+          "INVALID_COMPRESSION_BIT\\0"
+          "INVALID_ENCODING\\0"
+          "INVALID_FIELD\\0"
+          "INVALID_FORM\\0"
+          "INVALID_GROUP_ORDER\\0"
+          "INVALID_PRIVATE_KEY\\0"
+          "MISSING_PRIVATE_KEY\\0"
+          "NON_NAMED_CURVE\\0"
+          "PKPARAMETERS2GROUP_FAILURE\\0"
+          "POINT_AT_INFINITY\\0"
+          "POINT_IS_NOT_ON_CURVE\\0"
+          "SLOT_FULL\\0"
+          "UNDEFINED_GENERATOR\\0"
+          "UNKNOWN_GROUP\\0"
+          "UNKNOWN_ORDER\\0"
+          "WRONG_CURVE_PARAMETERS\\0"
+          "WRONG_ORDER\\0"
+          "KDF_FAILED\\0"
+          "POINT_ARITHMETIC_FAILURE\\0"
+          "BAD_SIGNATURE\\0"
+          "NOT_IMPLEMENTED\\0"
+          "RANDOM_NUMBER_GENERATION_FAILED\\0"
+          "OPERATION_NOT_SUPPORTED\\0"
+          "BN_DECODE_ERROR\\0"
+          "COMMAND_NOT_SUPPORTED\\0"
+          "CONTEXT_NOT_INITIALISED\\0"
+          "DIFFERENT_KEY_TYPES\\0"
+          "DIFFERENT_PARAMETERS\\0"
+          "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED\\0"
+          "EXPECTING_AN_EC_KEY_KEY\\0"
+          "EXPECTING_AN_RSA_KEY\\0"
+          "EXPECTING_A_DH_KEY\\0"
+          "EXPECTING_A_DSA_KEY\\0"
+          "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE\\0"
+          "INVALID_CURVE\\0"
+          "INVALID_DIGEST_LENGTH\\0"
+          "INVALID_DIGEST_TYPE\\0"
+          "INVALID_KEYBITS\\0"
+          "INVALID_MGF1_MD\\0"
+          "INVALID_PADDING_MODE\\0"
+          "INVALID_PSS_PARAMETERS\\0"
+          "INVALID_PSS_SALTLEN\\0"
+          "INVALID_SALT_LENGTH\\0"
+          "INVALID_TRAILER\\0"
+          "KEYS_NOT_SET\\0"
+          "NO_DEFAULT_DIGEST\\0"
+          "NO_KEY_SET\\0"
+          "NO_MDC2_SUPPORT\\0"
+          "NO_NID_FOR_CURVE\\0"
+          "NO_OPERATION_SET\\0"
+          "NO_PARAMETERS_SET\\0"
+          "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE\\0"
+          "OPERATON_NOT_INITIALIZED\\0"
+          "PARAMETER_ENCODING_ERROR\\0"
+          "UNKNOWN_DIGEST\\0"
+          "UNKNOWN_MASK_DIGEST\\0"
+          "UNKNOWN_MESSAGE_DIGEST_ALGORITHM\\0"
+          "UNKNOWN_PUBLIC_KEY_TYPE\\0"
+          "UNKNOWN_SIGNATURE_ALGORITHM\\0"
+          "UNSUPPORTED_ALGORITHM\\0"
+          "UNSUPPORTED_MASK_ALGORITHM\\0"
+          "UNSUPPORTED_MASK_PARAMETER\\0"
+          "UNSUPPORTED_SIGNATURE_TYPE\\0"
+          "WRONG_PUBLIC_KEY_TYPE\\0"
+          "OUTPUT_TOO_LARGE\\0"
+          "UNKNOWN_NID\\0"
+          "BAD_BASE64_DECODE\\0"
+          "BAD_END_LINE\\0"
+          "BAD_IV_CHARS\\0"
+          "BAD_PASSWORD_READ\\0"
+          "CIPHER_IS_NULL\\0"
+          "ERROR_CONVERTING_PRIVATE_KEY\\0"
+          "NOT_DEK_INFO\\0"
+          "NOT_ENCRYPTED\\0"
+          "NOT_PROC_TYPE\\0"
+          "NO_START_LINE\\0"
+          "READ_KEY\\0"
+          "SHORT_HEADER\\0"
+          "UNSUPPORTED_CIPHER\\0"
+          "UNSUPPORTED_ENCRYPTION\\0"
+          "BAD_PKCS12_DATA\\0"
+          "BAD_PKCS12_VERSION\\0"
+          "CIPHER_HAS_NO_OBJECT_IDENTIFIER\\0"
+          "CRYPT_ERROR\\0"
+          "ENCRYPT_ERROR\\0"
+          "ERROR_SETTING_CIPHER_PARAMS\\0"
+          "INCORRECT_PASSWORD\\0"
+          "KEYGEN_FAILURE\\0"
+          "KEY_GEN_ERROR\\0"
+          "METHOD_NOT_SUPPORTED\\0"
+          "MISSING_MAC\\0"
+          "MULTIPLE_PRIVATE_KEYS_IN_PKCS12\\0"
+          "PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED\\0"
+          "PKCS12_TOO_DEEPLY_NESTED\\0"
+          "PRIVATE_KEY_DECODE_ERROR\\0"
+          "PRIVATE_KEY_ENCODE_ERROR\\0"
+          "UNKNOWN_ALGORITHM\\0"
+          "UNKNOWN_CIPHER\\0"
+          "UNKNOWN_CIPHER_ALGORITHM\\0"
+          "UNKNOWN_HASH\\0"
+          "UNSUPPORTED_PRIVATE_KEY_ALGORITHM\\0"
+          "BAD_E_VALUE\\0"
+          "BAD_FIXED_HEADER_DECRYPT\\0"
+          "BAD_PAD_BYTE_COUNT\\0"
+          "BAD_RSA_PARAMETERS\\0"
+          "BAD_VERSION\\0"
+          "BLOCK_TYPE_IS_NOT_01\\0"
+          "BN_NOT_INITIALIZED\\0"
+          "CANNOT_RECOVER_MULTI_PRIME_KEY\\0"
+          "CRT_PARAMS_ALREADY_GIVEN\\0"
+          "CRT_VALUES_INCORRECT\\0"
+          "DATA_LEN_NOT_EQUAL_TO_MOD_LEN\\0"
+          "DATA_TOO_LARGE\\0"
+          "DATA_TOO_LARGE_FOR_KEY_SIZE\\0"
+          "DATA_TOO_LARGE_FOR_MODULUS\\0"
+          "DATA_TOO_SMALL\\0"
+          "DATA_TOO_SMALL_FOR_KEY_SIZE\\0"
+          "DIGEST_TOO_BIG_FOR_RSA_KEY\\0"
+          "D_E_NOT_CONGRUENT_TO_1\\0"
+          "EMPTY_PUBLIC_KEY\\0"
+          "FIRST_OCTET_INVALID\\0"
+          "INCONSISTENT_SET_OF_CRT_VALUES\\0"
+          "INTERNAL_ERROR\\0"
+          "INVALID_MESSAGE_LENGTH\\0"
+          "KEY_SIZE_TOO_SMALL\\0"
+          "LAST_OCTET_INVALID\\0"
+          "MUST_HAVE_AT_LEAST_TWO_PRIMES\\0"
+          "NO_PUBLIC_EXPONENT\\0"
+          "NULL_BEFORE_BLOCK_MISSING\\0"
+          "N_NOT_EQUAL_P_Q\\0"
+          "OAEP_DECODING_ERROR\\0"
+          "ONLY_ONE_OF_P_Q_GIVEN\\0"
+          "OUTPUT_BUFFER_TOO_SMALL\\0"
+          "PADDING_CHECK_FAILED\\0"
+          "PKCS_DECODING_ERROR\\0"
+          "SLEN_CHECK_FAILED\\0"
+          "SLEN_RECOVERY_FAILED\\0"
+          "UNKNOWN_ALGORITHM_TYPE\\0"
+          "UNKNOWN_PADDING_TYPE\\0"
+          "VALUE_MISSING\\0"
+          "WRONG_SIGNATURE_LENGTH\\0"
+          "APP_DATA_IN_HANDSHAKE\\0"
+          "ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT\\0"
+          "BAD_ALERT\\0"
+          "BAD_CHANGE_CIPHER_SPEC\\0"
+          "BAD_DATA_RETURNED_BY_CALLBACK\\0"
+          "BAD_DH_P_LENGTH\\0"
+          "BAD_DIGEST_LENGTH\\0"
+          "BAD_ECC_CERT\\0"
+          "BAD_ECPOINT\\0"
+          "BAD_HANDSHAKE_LENGTH\\0"
+          "BAD_HANDSHAKE_RECORD\\0"
+          "BAD_HELLO_REQUEST\\0"
+          "BAD_LENGTH\\0"
+          "BAD_PACKET_LENGTH\\0"
+          "BAD_RSA_ENCRYPT\\0"
+          "BAD_SRTP_MKI_VALUE\\0"
+          "BAD_SRTP_PROTECTION_PROFILE_LIST\\0"
+          "BAD_SSL_FILETYPE\\0"
+          "BAD_WRITE_RETRY\\0"
+          "BIO_NOT_SET\\0"
+          "CANNOT_SERIALIZE_PUBLIC_KEY\\0"
+          "CA_DN_LENGTH_MISMATCH\\0"
+          "CA_DN_TOO_LONG\\0"
+          "CCS_RECEIVED_EARLY\\0"
+          "CERTIFICATE_VERIFY_FAILED\\0"
+          "CERT_CB_ERROR\\0"
+          "CERT_LENGTH_MISMATCH\\0"
+          "CHANNEL_ID_NOT_P256\\0"
+          "CHANNEL_ID_SIGNATURE_INVALID\\0"
+          "CIPHER_CODE_WRONG_LENGTH\\0"
+          "CIPHER_OR_HASH_UNAVAILABLE\\0"
+          "CLIENTHELLO_PARSE_FAILED\\0"
+          "CLIENTHELLO_TLSEXT\\0"
+          "CONNECTION_REJECTED\\0"
+          "CONNECTION_TYPE_NOT_SET\\0"
+          "COOKIE_MISMATCH\\0"
+          "CUSTOM_EXTENSION_CONTENTS_TOO_LARGE\\0"
+          "CUSTOM_EXTENSION_ERROR\\0"
+          "D2I_ECDSA_SIG\\0"
+          "DATA_BETWEEN_CCS_AND_FINISHED\\0"
+          "DATA_LENGTH_TOO_LONG\\0"
+          "DECRYPTION_FAILED\\0"
+          "DECRYPTION_FAILED_OR_BAD_RECORD_MAC\\0"
+          "DH_PUBLIC_VALUE_LENGTH_IS_WRONG\\0"
+          "DH_P_TOO_LONG\\0"
+          "DIGEST_CHECK_FAILED\\0"
+          "DTLS_MESSAGE_TOO_BIG\\0"
+          "ECC_CERT_NOT_FOR_SIGNING\\0"
+          "EMPTY_SRTP_PROTECTION_PROFILE_LIST\\0"
+          "EMS_STATE_INCONSISTENT\\0"
+          "ENCRYPTED_LENGTH_TOO_LONG\\0"
+          "ERROR_ADDING_EXTENSION\\0"
+          "ERROR_IN_RECEIVED_CIPHER_LIST\\0"
+          "ERROR_PARSING_EXTENSION\\0"
+          "EVP_DIGESTSIGNFINAL_FAILED\\0"
+          "EVP_DIGESTSIGNINIT_FAILED\\0"
+          "EXCESSIVE_MESSAGE_SIZE\\0"
+          "EXTRA_DATA_IN_MESSAGE\\0"
+          "FRAGMENT_MISMATCH\\0"
+          "GOT_A_FIN_BEFORE_A_CCS\\0"
+          "GOT_CHANNEL_ID_BEFORE_A_CCS\\0"
+          "GOT_NEXT_PROTO_BEFORE_A_CCS\\0"
+          "GOT_NEXT_PROTO_WITHOUT_EXTENSION\\0"
+          "HANDSHAKE_FAILURE_ON_CLIENT_HELLO\\0"
+          "HANDSHAKE_RECORD_BEFORE_CCS\\0"
+          "HTTPS_PROXY_REQUEST\\0"
+          "HTTP_REQUEST\\0"
+          "INAPPROPRIATE_FALLBACK\\0"
+          "INVALID_COMMAND\\0"
+          "INVALID_MESSAGE\\0"
+          "INVALID_SSL_SESSION\\0"
+          "INVALID_TICKET_KEYS_LENGTH\\0"
+          "LENGTH_MISMATCH\\0"
+          "LIBRARY_HAS_NO_CIPHERS\\0"
+          "MISSING_DH_KEY\\0"
+          "MISSING_ECDSA_SIGNING_CERT\\0"
+          "MISSING_EXTENSION\\0"
+          "MISSING_RSA_CERTIFICATE\\0"
+          "MISSING_RSA_ENCRYPTING_CERT\\0"
+          "MISSING_RSA_SIGNING_CERT\\0"
+          "MISSING_TMP_DH_KEY\\0"
+          "MISSING_TMP_ECDH_KEY\\0"
+          "MIXED_SPECIAL_OPERATOR_WITH_GROUPS\\0"
+          "MTU_TOO_SMALL\\0"
+          "NEGOTIATED_BOTH_NPN_AND_ALPN\\0"
+          "NESTED_GROUP\\0"
+          "NO_CERTIFICATES_RETURNED\\0"
+          "NO_CERTIFICATE_ASSIGNED\\0"
+          "NO_CERTIFICATE_SET\\0"
+          "NO_CIPHERS_AVAILABLE\\0"
+          "NO_CIPHERS_PASSED\\0"
+          "NO_CIPHERS_SPECIFIED\\0"
+          "NO_CIPHER_MATCH\\0"
+          "NO_COMPRESSION_SPECIFIED\\0"
+          "NO_METHOD_SPECIFIED\\0"
+          "NO_P256_SUPPORT\\0"
+          "NO_PRIVATE_KEY_ASSIGNED\\0"
+          "NO_RENEGOTIATION\\0"
+          "NO_REQUIRED_DIGEST\\0"
+          "NO_SHARED_CIPHER\\0"
+          "NO_SHARED_SIGATURE_ALGORITHMS\\0"
+          "NO_SRTP_PROFILES\\0"
+          "NULL_SSL_CTX\\0"
+          "NULL_SSL_METHOD_PASSED\\0"
+          "OLD_SESSION_CIPHER_NOT_RETURNED\\0"
+          "OLD_SESSION_VERSION_NOT_RETURNED\\0"
+          "PACKET_LENGTH_TOO_LONG\\0"
+          "PARSE_TLSEXT\\0"
+          "PATH_TOO_LONG\\0"
+          "PEER_DID_NOT_RETURN_A_CERTIFICATE\\0"
+          "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\\0"
+          "PROTOCOL_IS_SHUTDOWN\\0"
+          "PSK_IDENTITY_NOT_FOUND\\0"
+          "PSK_NO_CLIENT_CB\\0"
+          "PSK_NO_SERVER_CB\\0"
+          "READ_BIO_NOT_SET\\0"
+          "READ_TIMEOUT_EXPIRED\\0"
+          "RECORD_LENGTH_MISMATCH\\0"
+          "RECORD_TOO_LARGE\\0"
+          "RENEGOTIATE_EXT_TOO_LONG\\0"
+          "RENEGOTIATION_ENCODING_ERR\\0"
+          "RENEGOTIATION_MISMATCH\\0"
+          "REQUIRED_CIPHER_MISSING\\0"
+          "RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION\\0"
+          "RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION\\0"
+          "SCSV_RECEIVED_WHEN_RENEGOTIATING\\0"
+          "SERVERHELLO_TLSEXT\\0"
+          "SESSION_ID_CONTEXT_UNINITIALIZED\\0"
+          "SESSION_MAY_NOT_BE_CREATED\\0"
+          "SIGNATURE_ALGORITHMS_ERROR\\0"
+          "SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER\\0"
+          "SRTP_COULD_NOT_ALLOCATE_PROFILES\\0"
+          "SRTP_PROTECTION_PROFILE_LIST_TOO_LONG\\0"
+          "SRTP_UNKNOWN_PROTECTION_PROFILE\\0"
+          "SSL3_EXT_INVALID_SERVERNAME\\0"
+          "SSL3_EXT_INVALID_SERVERNAME_TYPE\\0"
+          "SSLV3_ALERT_BAD_CERTIFICATE\\0"
+          "SSLV3_ALERT_BAD_RECORD_MAC\\0"
+          "SSLV3_ALERT_CERTIFICATE_EXPIRED\\0"
+          "SSLV3_ALERT_CERTIFICATE_REVOKED\\0"
+          "SSLV3_ALERT_CERTIFICATE_UNKNOWN\\0"
+          "SSLV3_ALERT_CLOSE_NOTIFY\\0"
+          "SSLV3_ALERT_DECOMPRESSION_FAILURE\\0"
+          "SSLV3_ALERT_HANDSHAKE_FAILURE\\0"
+          "SSLV3_ALERT_ILLEGAL_PARAMETER\\0"
+          "SSLV3_ALERT_NO_CERTIFICATE\\0"
+          "SSLV3_ALERT_UNEXPECTED_MESSAGE\\0"
+          "SSLV3_ALERT_UNSUPPORTED_CERTIFICATE\\0"
+          "SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION\\0"
+          "SSL_HANDSHAKE_FAILURE\\0"
+          "SSL_SESSION_ID_CALLBACK_FAILED\\0"
+          "SSL_SESSION_ID_CONFLICT\\0"
+          "SSL_SESSION_ID_CONTEXT_TOO_LONG\\0"
+          "SSL_SESSION_ID_HAS_BAD_LENGTH\\0"
+          "TLSV1_ALERT_ACCESS_DENIED\\0"
+          "TLSV1_ALERT_DECODE_ERROR\\0"
+          "TLSV1_ALERT_DECRYPTION_FAILED\\0"
+          "TLSV1_ALERT_DECRYPT_ERROR\\0"
+          "TLSV1_ALERT_EXPORT_RESTRICTION\\0"
+          "TLSV1_ALERT_INAPPROPRIATE_FALLBACK\\0"
+          "TLSV1_ALERT_INSUFFICIENT_SECURITY\\0"
+          "TLSV1_ALERT_INTERNAL_ERROR\\0"
+          "TLSV1_ALERT_NO_RENEGOTIATION\\0"
+          "TLSV1_ALERT_PROTOCOL_VERSION\\0"
+          "TLSV1_ALERT_RECORD_OVERFLOW\\0"
+          "TLSV1_ALERT_UNKNOWN_CA\\0"
+          "TLSV1_ALERT_USER_CANCELLED\\0"
+          "TLSV1_BAD_CERTIFICATE_HASH_VALUE\\0"
+          "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\\0"
+          "TLSV1_CERTIFICATE_UNOBTAINABLE\\0"
+          "TLSV1_UNRECOGNIZED_NAME\\0"
+          "TLSV1_UNSUPPORTED_EXTENSION\\0"
+          "TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER\\0"
+          "TLS_ILLEGAL_EXPORTER_LABEL\\0"
+          "TLS_INVALID_ECPOINTFORMAT_LIST\\0"
+          "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\\0"
+          "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG\\0"
+          "TOO_MANY_EMPTY_FRAGMENTS\\0"
+          "TOO_MANY_WARNING_ALERTS\\0"
+          "UNABLE_TO_FIND_ECDH_PARAMETERS\\0"
+          "UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS\\0"
+          "UNEXPECTED_EXTENSION\\0"
+          "UNEXPECTED_GROUP_CLOSE\\0"
+          "UNEXPECTED_MESSAGE\\0"
+          "UNEXPECTED_OPERATOR_IN_GROUP\\0"
+          "UNEXPECTED_RECORD\\0"
+          "UNKNOWN_ALERT_TYPE\\0"
+          "UNKNOWN_CERTIFICATE_TYPE\\0"
+          "UNKNOWN_CIPHER_RETURNED\\0"
+          "UNKNOWN_CIPHER_TYPE\\0"
+          "UNKNOWN_KEY_EXCHANGE_TYPE\\0"
+          "UNKNOWN_PROTOCOL\\0"
+          "UNKNOWN_SSL_VERSION\\0"
+          "UNKNOWN_STATE\\0"
+          "UNPROCESSED_HANDSHAKE_DATA\\0"
+          "UNSAFE_LEGACY_RENEGOTIATION_DISABLED\\0"
+          "UNSUPPORTED_COMPRESSION_ALGORITHM\\0"
+          "UNSUPPORTED_ELLIPTIC_CURVE\\0"
+          "UNSUPPORTED_PROTOCOL\\0"
+          "UNSUPPORTED_SSL_VERSION\\0"
+          "USE_SRTP_NOT_NEGOTIATED\\0"
+          "WRONG_CERTIFICATE_TYPE\\0"
+          "WRONG_CIPHER_RETURNED\\0"
+          "WRONG_CURVE\\0"
+          "WRONG_MESSAGE_TYPE\\0"
+          "WRONG_SIGNATURE_TYPE\\0"
+          "WRONG_SSL_VERSION\\0"
+          "WRONG_VERSION_NUMBER\\0"
+          "X509_LIB\\0"
+          "X509_VERIFICATION_SETUP_PROBLEMS\\0"
+          "AKID_MISMATCH\\0"
+          "BAD_PKCS7_VERSION\\0"
+          "BAD_X509_FILETYPE\\0"
+          "BASE64_DECODE_ERROR\\0"
+          "CANT_CHECK_DH_KEY\\0"
+          "CERT_ALREADY_IN_HASH_TABLE\\0"
+          "CRL_ALREADY_DELTA\\0"
+          "CRL_VERIFY_FAILURE\\0"
+          "IDP_MISMATCH\\0"
+          "INVALID_DIRECTORY\\0"
+          "INVALID_FIELD_NAME\\0"
+          "INVALID_TRUST\\0"
+          "ISSUER_MISMATCH\\0"
+          "KEY_TYPE_MISMATCH\\0"
+          "KEY_VALUES_MISMATCH\\0"
+          "LOADING_CERT_DIR\\0"
+          "LOADING_DEFAULTS\\0"
+          "NEWER_CRL_NOT_NEWER\\0"
+          "NOT_PKCS7_SIGNED_DATA\\0"
+          "NO_CERTIFICATES_INCLUDED\\0"
+          "NO_CERT_SET_FOR_US_TO_VERIFY\\0"
+          "NO_CRLS_INCLUDED\\0"
+          "NO_CRL_NUMBER\\0"
+          "PUBLIC_KEY_DECODE_ERROR\\0"
+          "PUBLIC_KEY_ENCODE_ERROR\\0"
+          "SHOULD_RETRY\\0"
+          "UNABLE_TO_FIND_PARAMETERS_IN_CHAIN\\0"
+          "UNABLE_TO_GET_CERTS_PUBLIC_KEY\\0"
+          "UNKNOWN_KEY_TYPE\\0"
+          "UNKNOWN_PURPOSE_ID\\0"
+          "UNKNOWN_TRUST_ID\\0"
+          "WRONG_LOOKUP_TYPE\\0"
+          "BAD_IP_ADDRESS\\0"
+          "BAD_OBJECT\\0"
+          "BN_DEC2BN_ERROR\\0"
+          "BN_TO_ASN1_INTEGER_ERROR\\0"
+          "CANNOT_FIND_FREE_FUNCTION\\0"
+          "DIRNAME_ERROR\\0"
+          "DISTPOINT_ALREADY_SET\\0"
+          "DUPLICATE_ZONE_ID\\0"
+          "ERROR_CONVERTING_ZONE\\0"
+          "ERROR_CREATING_EXTENSION\\0"
+          "ERROR_IN_EXTENSION\\0"
+          "EXPECTED_A_SECTION_NAME\\0"
+          "EXTENSION_EXISTS\\0"
+          "EXTENSION_NAME_ERROR\\0"
+          "EXTENSION_NOT_FOUND\\0"
+          "EXTENSION_SETTING_NOT_SUPPORTED\\0"
+          "EXTENSION_VALUE_ERROR\\0"
+          "ILLEGAL_EMPTY_EXTENSION\\0"
+          "ILLEGAL_HEX_DIGIT\\0"
+          "INCORRECT_POLICY_SYNTAX_TAG\\0"
+          "INVALID_BOOLEAN_STRING\\0"
+          "INVALID_EXTENSION_STRING\\0"
+          "INVALID_MULTIPLE_RDNS\\0"
+          "INVALID_NAME\\0"
+          "INVALID_NULL_ARGUMENT\\0"
+          "INVALID_NULL_NAME\\0"
+          "INVALID_NULL_VALUE\\0"
+          "INVALID_NUMBERS\\0"
+          "INVALID_OBJECT_IDENTIFIER\\0"
+          "INVALID_OPTION\\0"
+          "INVALID_POLICY_IDENTIFIER\\0"
+          "INVALID_PROXY_POLICY_SETTING\\0"
+          "INVALID_PURPOSE\\0"
+          "INVALID_SECTION\\0"
+          "INVALID_SYNTAX\\0"
+          "ISSUER_DECODE_ERROR\\0"
+          "NEED_ORGANIZATION_AND_NUMBERS\\0"
+          "NO_CONFIG_DATABASE\\0"
+          "NO_ISSUER_CERTIFICATE\\0"
+          "NO_ISSUER_DETAILS\\0"
+          "NO_POLICY_IDENTIFIER\\0"
+          "NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED\\0"
+          "NO_PUBLIC_KEY\\0"
+          "NO_SUBJECT_DETAILS\\0"
+          "ODD_NUMBER_OF_DIGITS\\0"
+          "OPERATION_NOT_DEFINED\\0"
+          "OTHERNAME_ERROR\\0"
+          "POLICY_LANGUAGE_ALREADY_DEFINED\\0"
+          "POLICY_PATH_LENGTH\\0"
+          "POLICY_PATH_LENGTH_ALREADY_DEFINED\\0"
+          "POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY\\0"
+          "SECTION_NOT_FOUND\\0"
+          "UNABLE_TO_GET_ISSUER_DETAILS\\0"
+          "UNABLE_TO_GET_ISSUER_KEYID\\0"
+          "UNKNOWN_BIT_STRING_ARGUMENT\\0"
+          "UNKNOWN_EXTENSION\\0"
+          "UNKNOWN_EXTENSION_NAME\\0"
+          "UNKNOWN_OPTION\\0"
+          "UNSUPPORTED_OPTION\\0"
+          "USER_TOO_LONG\\0"
+          "";
+    EOF
+  END_OF_COMMAND
+end
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 5918f8857a9bccbfa9ec69ed38613f3959cdd702..c9fda4285529294fa002ed43ef80af4d0f86f0b2 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -50,6 +50,8 @@
 #import <Foundation/Foundation.h>
 #import <RxLibrary/GRXWriter.h>
 
+#include <AvailabilityMacros.h>
+
 #pragma mark gRPC errors
 
 /** Domain of NSError objects produced by gRPC. */
@@ -161,6 +163,9 @@ extern id const kGRPCTrailersKey;
 
 #pragma mark GRPCCall
 
+/** Represents a single gRPC remote call. */
+@interface GRPCCall : GRXWriter
+
 /**
  * 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.
@@ -170,21 +175,6 @@ extern id const kGRPCTrailersKey;
  * 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 <NSObject>
-
-@property(nonatomic, readonly) NSUInteger count;
-
-- (id)objectForKeyedSubscript:(NSString *)key;
-- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
-
-- (void)removeAllObjects;
-- (void)removeObjectForKey:(NSString *)key;
-
-@end
-
-/** 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.
@@ -200,7 +190,7 @@ extern id const kGRPCTrailersKey;
  *
  * The property is initialized to an empty NSMutableDictionary.
  */
-@property(atomic, readonly) id<GRPCRequestHeaders> requestHeaders;
+@property(atomic, readonly) NSMutableDictionary *requestHeaders;
 
 /**
  * This dictionary is populated with the HTTP headers received from the server. This happens before
@@ -243,3 +233,24 @@ extern id const kGRPCTrailersKey;
 
 // TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?
 @end
+
+#pragma mark Backwards compatibiity
+
+/** This protocol is kept for backwards compatibility with existing code. */
+DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.")
+@protocol GRPCRequestHeaders <NSObject>
+@property(nonatomic, readonly) NSUInteger count;
+
+- (id)objectForKeyedSubscript:(NSString *)key;
+- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
+
+- (void)removeAllObjects;
+- (void)removeObjectForKey:(NSString *)key;
+@end
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+/** This is only needed for backwards-compatibility. */
+@interface NSMutableDictionary (GRPCRequestHeaders) <GRPCRequestHeaders>
+@end
+#pragma clang diagnostic pop
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index b6986bf59c03dd27f6a603a46c8ae6105867dca9..f79b7d0bc0cf08920c78619eca04c41de2d9112c 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -221,7 +221,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 
 #pragma mark Send headers
 
-- (void)sendHeaders:(id<GRPCRequestHeaders>)headers {
+- (void)sendHeaders:(NSDictionary *)headers {
   // TODO(jcanizales): Add error handlers for async failures
   [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc] initWithMetadata:headers
                                                                                 handler:nil]]];
diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
index cf5a1be9d6a8edfbcccf7521bda47911afc2e4ba..b580f194061db5fca76f6705c5f18f4a4b66ba16 100644
--- a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
+++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
@@ -32,21 +32,14 @@
  */
 
 #import <Foundation/Foundation.h>
-#include <grpc/grpc.h>
 
 #import "../GRPCCall.h"
 
-@interface GRPCRequestHeaders : NSObject<GRPCRequestHeaders>
-
-@property(nonatomic, readonly) NSUInteger count;
-@property(nonatomic, readonly) grpc_metadata *grpc_metadataArray;
+@interface GRPCRequestHeaders : NSMutableDictionary
 
 - (instancetype)initWithCall:(GRPCCall *)call;
 
-- (id)objectForKeyedSubscript:(NSString *)key;
-- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
-
-- (void)removeAllObjects;
-- (void)removeObjectForKey:(NSString *)key;
+- (instancetype)initWithCall:(GRPCCall *)call
+                     storage:(NSMutableDictionary *)storage NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
index d23f21c0f9c0847228ebcad487c998379255e60d..c6a03c145ea209566b9d8c69db41f835ec78b9a2 100644
--- a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
+++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
@@ -68,17 +68,44 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
 
 @implementation GRPCRequestHeaders {
   __weak GRPCCall *_call;
+  // The NSMutableDictionary superclass doesn't hold any storage (so that people can implement their
+  // own in subclasses). As that's not the reason we're subclassing, we just delegate storage to the
+  // default NSMutableDictionary subclass returned by the cluster (e.g. __NSDictionaryM on iOS 9).
   NSMutableDictionary *_delegate;
 }
 
+- (instancetype)init {
+  return [self initWithCall:nil];
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  return [self init];
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+  return [self init];
+}
+
 - (instancetype)initWithCall:(GRPCCall *)call {
+  return [self initWithCall:call storage:[NSMutableDictionary dictionary]];
+}
+
+// Designated initializer
+- (instancetype)initWithCall:(GRPCCall *)call storage:(NSMutableDictionary *)storage {
+  // TODO(jcanizales): Throw if call or storage are nil.
   if ((self = [super init])) {
     _call = call;
-    _delegate = [NSMutableDictionary dictionary];
+    _delegate = storage;
   }
   return self;
 }
 
+- (instancetype)initWithObjects:(const id  _Nonnull __unsafe_unretained *)objects
+                        forKeys:(const id<NSCopying>  _Nonnull __unsafe_unretained *)keys
+                          count:(NSUInteger)cnt {
+  return [self init];
+}
+
 - (void)checkCallIsNotStarted {
   if (_call.state != GRXWriterStateNotStarted) {
     [NSException raise:@"Invalid modification"
@@ -86,11 +113,11 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
   }
 }
 
-- (id)objectForKeyedSubscript:(NSString *)key {
+- (id)objectForKey:(NSString *)key {
   return _delegate[key.lowercaseString];
 }
 
-- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key {
+- (void)setObject:(id)obj forKey:(NSString *)key {
   [self checkCallIsNotStarted];
   CheckIsNonNilASCII(@"Header name", key);
   key = key.lowercaseString;
@@ -103,16 +130,12 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
   [_delegate removeObjectForKey:key.lowercaseString];
 }
 
-- (void)removeAllObjects {
-  [self checkCallIsNotStarted];
-  [_delegate removeAllObjects];
-}
-
 - (NSUInteger)count {
   return _delegate.count;
 }
 
-- (grpc_metadata *)grpc_metadataArray {
-  return _delegate.grpc_metadataArray;
+- (NSEnumerator * _Nonnull)keyEnumerator {
+  return [_delegate keyEnumerator];
 }
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index 7747aa53ef07fdf25fb605e05984d116db659c14..71e7e0e54eeb87f8b451b56d1040b6a0678f1009 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -45,7 +45,7 @@
 
 @interface GRPCOpSendMetadata : GRPCOperation
 
-- (instancetype)initWithMetadata:(GRPCRequestHeaders *)metadata
+- (instancetype)initWithMetadata:(NSDictionary *)metadata
                          handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index cea7c479e0f6f20b6c6051d53e9645ef9d776815..fe3d51da53a58a409621433744fdd028872e64a3 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -65,7 +65,7 @@
   return [self initWithMetadata:nil handler:nil];
 }
 
-- (instancetype)initWithMetadata:(GRPCRequestHeaders *)metadata handler:(void (^)())handler {
+- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)())handler {
   if (self = [super init]) {
     _op.op = GRPC_OP_SEND_INITIAL_METADATA;
     _op.data.send_initial_metadata.count = metadata.count;
diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile
index 3b2f41256940c4931638bf5b422d03e08adf72f2..93859fb73403e624b5c78874a1d5c8154d579fab 100644
--- a/src/objective-c/examples/Sample/Podfile
+++ b/src/objective-c/examples/Sample/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
 pod 'Protobuf', :path => "../../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => "../.."
 pod 'gRPC', :path => "../../../.."
 pod 'RemoteTest', :path => "../RemoteTestClient"
 
diff --git a/src/objective-c/examples/SwiftSample/Podfile b/src/objective-c/examples/SwiftSample/Podfile
index 3611b00863c174ab17ab6c7748e01637fbd04330..f2df4a34a34f8adb39fce609146328f2ccc91d5b 100644
--- a/src/objective-c/examples/SwiftSample/Podfile
+++ b/src/objective-c/examples/SwiftSample/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
 pod 'Protobuf', :path => "../../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => "../.."
 pod 'gRPC', :path => "../../../.."
 pod 'RemoteTest', :path => "../RemoteTestClient"
 
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index cab608d37fee7df15ad461ffe08a6501f9ea3b3c..7ec7a258982bff2fa1af5573ce51e309d918ff27 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
 pod 'Protobuf', :path => "../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => ".."
 pod 'gRPC', :path => "../../.."
 pod 'RemoteTest', :path => "RemoteTestClient"
 
diff --git a/src/php/tests/generated_code/math.proto b/src/php/tests/generated_code/math.proto
index 1de7d0b8debe52aa0b09a7d541fa58f6a505ea3c..c872ee6e0b2a2f499f7994d206f4eb7f10a10267 100644
--- a/src/php/tests/generated_code/math.proto
+++ b/src/php/tests/generated_code/math.proto
@@ -28,6 +28,9 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// TODO: start using src/proto/math/math.proto and remove this file once
+// PHP supports proto3.
+
 syntax = "proto2";
 
 package math;
diff --git a/src/ruby/pb/grpc/health/v1alpha/health.proto b/src/proto/grpc/health/v1alpha/health.proto
similarity index 97%
rename from src/ruby/pb/grpc/health/v1alpha/health.proto
rename to src/proto/grpc/health/v1alpha/health.proto
index d31df1e0a7c018837d2ede9fed8e0084d552c4a3..28786c4427da1fd2958eb8010d15f94db14ba1b5 100644
--- a/src/ruby/pb/grpc/health/v1alpha/health.proto
+++ b/src/proto/grpc/health/v1alpha/health.proto
@@ -30,6 +30,7 @@
 syntax = "proto3";
 
 package grpc.health.v1alpha;
+option csharp_namespace = "Grpc.Health.V1Alpha";
 
 message HealthCheckRequest {
   string host = 1;
diff --git a/src/csharp/Grpc.Examples/proto/math.proto b/src/proto/math/math.proto
similarity index 100%
rename from src/csharp/Grpc.Examples/proto/math.proto
rename to src/proto/math/math.proto
diff --git a/src/python/grpcio/.gitignore b/src/python/grpcio/.gitignore
index 4c02b8d14dcbbeb3e029f98633aed9de5bb1dcc8..95b96f7c1e9f7c368801e14f6848639f2b13485b 100644
--- a/src/python/grpcio/.gitignore
+++ b/src/python/grpcio/.gitignore
@@ -5,5 +5,12 @@ dist/
 *.egg
 *.egg/
 *.eggs/
+*_pb2.py
+.coverage
+.coverage.*
+.cache/
+.tox/
+nosetests.xml
 doc/
 _grpcio_metadata.py
+htmlcov/
diff --git a/src/python/grpcio/MANIFEST.in b/src/python/grpcio/MANIFEST.in
index 9583dc7768dab9f9da2dad02036ec4d415d51112..407eeabc1792555014d5ca27bdbf2281eccc90d9 100644
--- a/src/python/grpcio/MANIFEST.in
+++ b/src/python/grpcio/MANIFEST.in
@@ -1,3 +1,4 @@
 graft grpc
+graft tests
 include commands.py
 include requirements.txt
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 8a2f2d6283edcb13806aec5f0d94ff5c2c9a1f4c..d9fd023b214923f5bbb442104c69d3bca87f8a18 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -29,14 +29,18 @@
 
 """Provides distutils command classes for the GRPC Python setup process."""
 
+import distutils
 import os
 import os.path
+import re
+import subprocess
 import sys
 
 import setuptools
 from setuptools.command import build_py
+from setuptools.command import test
 
-_CONF_PY_ADDENDUM = """
+CONF_PY_ADDENDUM = """
 extensions.append('sphinx.ext.napoleon')
 napoleon_google_docstring = True
 napoleon_numpy_docstring = True
@@ -48,7 +52,7 @@ html_theme = 'sphinx_rtd_theme'
 class SphinxDocumentation(setuptools.Command):
   """Command to generate documentation via sphinx."""
 
-  description = ''
+  description = 'generate sphinx documentation'
   user_options = []
 
   def initialize_options(self):
@@ -72,14 +76,61 @@ class SphinxDocumentation(setuptools.Command):
         '-o', os.path.join('doc', 'src'), src_dir])
     conf_filepath = os.path.join('doc', 'src', 'conf.py')
     with open(conf_filepath, 'a') as conf_file:
-      conf_file.write(_CONF_PY_ADDENDUM)
+      conf_file.write(CONF_PY_ADDENDUM)
     sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')])
 
 
+class BuildProtoModules(setuptools.Command):
+  """Command to generate project *_pb2.py modules from proto files."""
+
+  description = 'build protobuf modules'
+  user_options = [
+    ('include=', None, 'path patterns to include in protobuf generation'),
+    ('exclude=', None, 'path patterns to exclude from protobuf generation')
+  ]
+
+  def initialize_options(self):
+    self.exclude = None
+    self.include = r'.*\.proto$'
+    self.protoc_command = None
+    self.grpc_python_plugin_command = None
+
+  def finalize_options(self):
+    self.protoc_command = distutils.spawn.find_executable('protoc')
+    self.grpc_python_plugin_command = distutils.spawn.find_executable(
+        'grpc_python_plugin')
+
+  def run(self):
+    include_regex = re.compile(self.include)
+    exclude_regex = re.compile(self.exclude) if self.exclude else None
+    paths = []
+    root_directory = os.getcwd()
+    for walk_root, directories, filenames in os.walk(root_directory):
+      for filename in filenames:
+        path = os.path.join(walk_root, filename)
+        if include_regex.match(path) and not (
+            exclude_regex and exclude_regex.match(path)):
+          paths.append(path)
+    command = [
+        self.protoc_command,
+        '--plugin=protoc-gen-python-grpc={}'.format(
+            self.grpc_python_plugin_command),
+        '-I {}'.format(root_directory),
+        '--python_out={}'.format(root_directory),
+        '--python-grpc_out={}'.format(root_directory),
+    ] + paths
+    try:
+      subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
+                              stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+      raise Exception('Command:\n{}\nMessage:\n{}\nOutput:\n{}'.format(
+          command, e.message, e.output))
+
+
 class BuildProjectMetadata(setuptools.Command):
   """Command to generate project metadata in a module."""
 
-  description = ''
+  description = 'build grpcio project metadata files'
   user_options = []
 
   def initialize_options(self):
@@ -98,5 +149,73 @@ class BuildPy(build_py.build_py):
   """Custom project build command."""
 
   def run(self):
+    self.run_command('build_proto_modules')
     self.run_command('build_project_metadata')
     build_py.build_py.run(self)
+
+
+class Gather(setuptools.Command):
+  """Command to gather project dependencies."""
+
+  description = 'gather dependencies for grpcio'
+  user_options = [
+    ('test', 't', 'flag indicating to gather test dependencies'),
+    ('install', 'i', 'flag indicating to gather install dependencies')
+  ]
+
+  def initialize_options(self):
+    self.test = False
+    self.install = False
+
+  def finalize_options(self):
+    # distutils requires this override.
+    pass
+
+  def run(self):
+    if self.install and self.distribution.install_requires:
+      self.distribution.fetch_build_eggs(self.distribution.install_requires)
+    if self.test and self.distribution.tests_require:
+      self.distribution.fetch_build_eggs(self.distribution.tests_require)
+
+
+class RunInterop(test.test):
+
+  description = 'run interop test client/server'
+  user_options = [
+    ('args=', 'a', 'pass-thru arguments for the client/server'),
+    ('client', 'c', 'flag indicating to run the client'),
+    ('server', 's', 'flag indicating to run the server')
+  ]
+
+  def initialize_options(self):
+    self.args = ''
+    self.client = False
+    self.server = False
+
+  def finalize_options(self):
+    if self.client and self.server:
+      raise DistutilsOptionError('you may only specify one of client or server')
+
+  def run(self):
+    if self.distribution.install_requires:
+      self.distribution.fetch_build_eggs(self.distribution.install_requires)
+    if self.distribution.tests_require:
+      self.distribution.fetch_build_eggs(self.distribution.tests_require)
+    if self.client:
+      self.run_client()
+    elif self.server:
+      self.run_server()
+
+  def run_server(self):
+    # We import here to ensure that our setuptools parent has had a chance to
+    # edit the Python system path.
+    from tests.interop import server
+    sys.argv[1:] = self.args.split()
+    server.serve()
+
+  def run_client(self):
+    # We import here to ensure that our setuptools parent has had a chance to
+    # edit the Python system path.
+    from tests.interop import client
+    sys.argv[1:] = self.args.split()
+    client.test_interoperability()
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h
deleted file mode 100644
index 9ab415d216b41497a5e54ab0c851b6aadfde8b5b..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC__ADAPTER__C_TYPES_H_
-#define GRPC__ADAPTER__C_TYPES_H_
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-
-/*=========================*/
-/* Client-side credentials */
-/*=========================*/
-
-typedef struct ChannelCredentials {
-  PyObject_HEAD
-  grpc_channel_credentials *c_creds;
-} ChannelCredentials;
-void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self);
-ChannelCredentials *pygrpc_ChannelCredentials_google_default(
-    PyTypeObject *type, PyObject *ignored);
-ChannelCredentials *pygrpc_ChannelCredentials_ssl(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ChannelCredentials *pygrpc_ChannelCredentials_composite(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_ChannelCredentials_type;
-
-typedef struct CallCredentials {
-  PyObject_HEAD
-  grpc_call_credentials *c_creds;
-} CallCredentials;
-void pygrpc_CallCredentials_dealloc(CallCredentials *self);
-CallCredentials *pygrpc_CallCredentials_composite(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-CallCredentials *pygrpc_CallCredentials_compute_engine(
-    PyTypeObject *type, PyObject *ignored);
-CallCredentials *pygrpc_CallCredentials_jwt(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-CallCredentials *pygrpc_CallCredentials_refresh_token(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-CallCredentials *pygrpc_CallCredentials_iam(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_CallCredentials_type;
-
-/*=========================*/
-/* Server-side credentials */
-/*=========================*/
-
-typedef struct ServerCredentials {
-  PyObject_HEAD
-  grpc_server_credentials *c_creds;
-} ServerCredentials;
-void pygrpc_ServerCredentials_dealloc(ServerCredentials *self);
-ServerCredentials *pygrpc_ServerCredentials_ssl(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_ServerCredentials_type;
-
-
-/*==================*/
-/* Completion queue */
-/*==================*/
-
-typedef struct CompletionQueue {
-  PyObject_HEAD
-  grpc_completion_queue *c_cq;
-} CompletionQueue;
-CompletionQueue *pygrpc_CompletionQueue_new(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-void pygrpc_CompletionQueue_dealloc(CompletionQueue *self);
-PyObject *pygrpc_CompletionQueue_next(
-    CompletionQueue *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_CompletionQueue_shutdown(
-    CompletionQueue *self, PyObject *ignored);
-extern PyTypeObject pygrpc_CompletionQueue_type;
-
-
-/*======*/
-/* Call */
-/*======*/
-
-typedef struct Call {
-  PyObject_HEAD
-  grpc_call *c_call;
-  CompletionQueue *cq;
-} Call;
-Call *pygrpc_Call_new_empty(CompletionQueue *cq);
-void pygrpc_Call_dealloc(Call *self);
-PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Call_peer(Call *self);
-PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
-                                      PyObject *kwargs);
-extern PyTypeObject pygrpc_Call_type;
-
-
-/*=========*/
-/* Channel */
-/*=========*/
-
-typedef struct Channel {
-  PyObject_HEAD
-  grpc_channel *c_chan;
-} Channel;
-Channel *pygrpc_Channel_new(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-void pygrpc_Channel_dealloc(Channel *self);
-Call *pygrpc_Channel_create_call(
-    Channel *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Channel_check_connectivity_state(Channel *self, PyObject *args,
-                                                  PyObject *kwargs);
-PyObject *pygrpc_Channel_watch_connectivity_state(Channel *self, PyObject *args,
-                                                  PyObject *kwargs);
-PyObject *pygrpc_Channel_target(Channel *self);
-extern PyTypeObject pygrpc_Channel_type;
-
-
-/*========*/
-/* Server */
-/*========*/
-
-typedef struct Server {
-  PyObject_HEAD
-  grpc_server *c_serv;
-  CompletionQueue *cq;
-  int shutdown_called;
-} Server;
-Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
-void pygrpc_Server_dealloc(Server *self);
-PyObject *pygrpc_Server_request_call(
-    Server *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Server_add_http2_port(
-    Server *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Server_start(Server *self, PyObject *ignored);
-PyObject *pygrpc_Server_shutdown(
-    Server *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused);
-extern PyTypeObject pygrpc_Server_type;
-
-/*=========*/
-/* Utility */
-/*=========*/
-
-/* Every tag that passes from Python GRPC to GRPC core is of this type. */
-typedef struct pygrpc_tag {
-  PyObject *user_tag;
-  Call *call;
-  grpc_call_details request_call_details;
-  grpc_metadata_array request_metadata;
-  grpc_op *ops;
-  size_t nops;
-  int is_new_call;
-} pygrpc_tag;
-
-/* Construct a tag associated with a batch call. Does not take ownership of the
-   resources in the elements of ops. */
-pygrpc_tag *pygrpc_produce_batch_tag(PyObject *user_tag, Call *call,
-                                     grpc_op *ops, size_t nops);
-
-
-/* Construct a tag associated with a server request. The calling code should
-   use the appropriate fields of the produced tag in the invocation of
-   grpc_server_request_call. */
-pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call);
-
-/* Construct a tag associated with a server shutdown. */
-pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag);
-
-/* Construct a tag associated with a channel state change. */
-pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag);
-
-/* Frees all resources owned by the tag and the tag itself. */
-void pygrpc_discard_tag(pygrpc_tag *tag);
-
-/* Consumes an event and its associated tag, providing a Python tuple of the
-   form `(type, tag, call, call_details, results)` (where type is an integer
-   corresponding to a grpc_completion_type, tag is an arbitrary PyObject, call
-   is the call object associated with the event [if any], call_details is a
-   tuple of form `(method, host, deadline)` [if such details are available],
-   and resultd is a list of tuples of form `(type, metadata, message, status,
-   cancelled)` [where type corresponds to a grpc_op_type, metadata is a
-   sequence of 2-sequences of strings, message is a byte string, and status is
-   a 2-tuple of an integer corresponding to grpc_status_code and a string of
-   status details]).
-
-   Frees all resources associated with the event tag. */
-PyObject *pygrpc_consume_event(grpc_event event);
-
-/* Transliterate the Python tuple of form `(type, metadata, message,
-   status)` (where type is an integer corresponding to a grpc_op_type, metadata
-   is a sequence of 2-sequences of strings, message is a byte string, and
-   status is 2-tuple of an integer corresponding to grpc_status_code and a
-   string of status details) to a grpc_op suitable for use in a
-   grpc_call_start_batch invocation. The grpc_op is a 'directory' of resources
-   that must be freed after GRPC core is done with them.
-
-   Calls gpr_malloc (or the appropriate type-specific grpc_*_create function)
-   to populate the appropriate union-discriminated members of the op.
-
-   Returns true on success, false on failure. */
-int pygrpc_produce_op(PyObject *op, grpc_op *result);
-
-/* Discards all resources associated with the passed in op that was produced by
-   pygrpc_produce_op. */
-void pygrpc_discard_op(grpc_op op);
-
-/* Transliterate the grpc_ops (which have been sent through a
-   grpc_call_start_batch invocation and whose corresponding event has appeared
-   on a completion queue) to a Python tuple of form `(type, metadata, message,
-   status, cancelled)` (where type is an integer corresponding to a
-   grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a
-   byte string, and status is 2-tuple of an integer corresponding to
-   grpc_status_code and a string of status details).
-
-   Calls gpr_free (or the appropriate type-specific grpc_*_destroy function) on
-   the appropriate union-discriminated populated members of the ops. */
-PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops);
-
-/* Transliterate from a gpr_timespec to a double (in units of seconds, either
-   from the epoch if interpreted absolutely or as a delta otherwise). */
-double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec);
-
-/* Transliterate from a double (in units of seconds from the epoch if
-   interpreted absolutely or as a delta otherwise) to a gpr_timespec. */
-gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds);
-
-/* Returns true on success, false on failure. */
-int pygrpc_cast_pyseq_to_send_metadata(
-    PyObject *pyseq, grpc_metadata **metadata, size_t *count);
-/* Returns a metadata array as a Python object on success, else NULL. */
-PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata);
-
-/* Transliterate from a list of python channel arguments (2-tuples of string
-   and string|integer|None) to a grpc_channel_args object. The strings placed
-   in the grpc_channel_args object's grpc_arg elements are views of the Python
-   object. The Python object must live long enough for the grpc_channel_args
-   to be used. Arguments set to None are silently ignored. Returns true on
-   success, false on failure. */
-int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args);
-void pygrpc_discard_channel_args(grpc_channel_args args);
-
-/* Read the bytes from grpc_byte_buffer to a gpr_malloc'd array of bytes;
-   output to result and result_size. */
-void pygrpc_byte_buffer_to_bytes(
-    grpc_byte_buffer *buffer, char **result, size_t *result_size);
-
-
-/*========*/
-/* Module */
-/*========*/
-
-/* Returns 0 on success, -1 on failure. */
-int pygrpc_module_add_types(PyObject *module);
-
-#endif  /* GRPC__ADAPTER__C_TYPES_H_ */
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c
deleted file mode 100644
index 04ec871880086a8a87a9d161c7af98ea99a83d06..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/call.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-
-
-PyMethodDef pygrpc_Call_methods[] = {
-    {"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""},
-    {"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""},
-    {"peer", (PyCFunction)pygrpc_Call_peer, METH_NOARGS, ""},
-    {"set_credentials", (PyCFunction)pygrpc_Call_set_credentials, METH_KEYWORDS,
-     ""},
-    {NULL}
-};
-const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call.";
-PyTypeObject pygrpc_Call_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "Call",                                   /* tp_name */
-    sizeof(Call),                             /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_Call_dealloc,          /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_Call_doc,                          /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_Call_methods,                      /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    0                                         /* tp_new */
-};
-
-Call *pygrpc_Call_new_empty(CompletionQueue *cq) {
-  Call *call = (Call *)pygrpc_Call_type.tp_alloc(&pygrpc_Call_type, 0);
-  call->c_call = NULL;
-  call->cq = cq;
-  Py_XINCREF(call->cq);
-  return call;
-}
-void pygrpc_Call_dealloc(Call *self) {
-  if (self->c_call) {
-    grpc_call_destroy(self->c_call);
-  }
-  Py_XDECREF(self->cq);
-  self->ob_type->tp_free((PyObject *)self);
-}
-PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs) {
-  PyObject *op_list;
-  PyObject *user_tag;
-  grpc_op *ops;
-  size_t nops;
-  size_t i;
-  size_t j;
-  pygrpc_tag *tag;
-  grpc_call_error errcode;
-  static char *keywords[] = {"ops", "tag", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:start_batch", keywords,
-                                   &op_list, &user_tag)) {
-    return NULL;
-  }
-  if (!PyList_Check(op_list)) {
-    PyErr_SetString(PyExc_TypeError, "expected a list of OpArgs");
-    return NULL;
-  }
-  nops = PyList_Size(op_list);
-  ops = gpr_malloc(sizeof(grpc_op) * nops);
-  for (i = 0; i < nops; ++i) {
-    PyObject *item = PyList_GET_ITEM(op_list, i);
-    if (!pygrpc_produce_op(item, &ops[i])) {
-      for (j = 0; j < i; ++j) {
-        pygrpc_discard_op(ops[j]);
-      }
-      return NULL;
-    }
-  }
-  tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops);
-  errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag, NULL);
-  gpr_free(ops);
-  return PyInt_FromLong(errcode);
-}
-PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) {
-  PyObject *py_code = NULL;
-  grpc_call_error errcode;
-  int code;
-  char *details = NULL;
-  static char *keywords[] = {"code", "details", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:start_batch", keywords,
-                                   &py_code, &details)) {
-    return NULL;
-  }
-  if (py_code != NULL && details != NULL) {
-    if (!PyInt_Check(py_code)) {
-      PyErr_SetString(PyExc_TypeError, "expected integer code");
-      return NULL;
-    }
-    code = PyInt_AsLong(py_code);
-    errcode = grpc_call_cancel_with_status(self->c_call, code, details, NULL);
-  } else if (py_code != NULL || details != NULL) {
-    PyErr_SetString(PyExc_ValueError,
-                    "if `code` is specified, so must `details`");
-    return NULL;
-  } else {
-    errcode = grpc_call_cancel(self->c_call, NULL);
-  }
-  return PyInt_FromLong(errcode);
-}
-
-PyObject *pygrpc_Call_peer(Call *self) {
-  char *peer = grpc_call_get_peer(self->c_call);
-  PyObject *py_peer = PyString_FromString(peer);
-  gpr_free(peer);
-  return py_peer;
-}
-PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
-                                      PyObject *kwargs) {
-  CallCredentials *creds;
-  grpc_call_error errcode;
-  static char *keywords[] = {"creds", NULL};
-  if (!PyArg_ParseTupleAndKeywords(
-      args, kwargs, "O!:set_credentials", keywords,
-      &pygrpc_CallCredentials_type, &creds)) {
-    return NULL;
-  }
-  errcode = grpc_call_set_credentials(self->c_call, creds->c_creds);
-  return PyInt_FromLong(errcode);
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
deleted file mode 100644
index 5a15a6e17dc37105bfe3adf93c145be5b8df507a..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-
-PyMethodDef pygrpc_CallCredentials_methods[] = {
-    {"composite", (PyCFunction)pygrpc_CallCredentials_composite,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine,
-     METH_CLASS|METH_NOARGS, ""},
-    {"jwt", (PyCFunction)pygrpc_CallCredentials_jwt,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {"iam", (PyCFunction)pygrpc_CallCredentials_iam,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {NULL}
-};
-
-const char pygrpc_CallCredentials_doc[] = "";
-PyTypeObject pygrpc_CallCredentials_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "CallCredentials",                        /* tp_name */
-    sizeof(CallCredentials),                  /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_CallCredentials_dealloc, /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_CallCredentials_doc,             /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_CallCredentials_methods,         /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    0                                         /* tp_new */
-};
-
-void pygrpc_CallCredentials_dealloc(CallCredentials *self) {
-  grpc_call_credentials_release(self->c_creds);
-  self->ob_type->tp_free((PyObject *)self);
-}
-
-CallCredentials *pygrpc_CallCredentials_composite(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  CallCredentials *self;
-  CallCredentials *creds1;
-  CallCredentials *creds2;
-  static char *keywords[] = {"creds1", "creds2", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
-        &pygrpc_CallCredentials_type, &creds1,
-        &pygrpc_CallCredentials_type, &creds2)) {
-    return NULL;
-  }
-  self = (CallCredentials *)type->tp_alloc(type, 0);
-  self->c_creds =
-      grpc_composite_call_credentials_create(
-          creds1->c_creds, creds2->c_creds, NULL);
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials");
-    return NULL;
-  }
-  return self;
-}
-
-CallCredentials *pygrpc_CallCredentials_compute_engine(
-    PyTypeObject *type, PyObject *ignored) {
-  CallCredentials *self = (CallCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_google_compute_engine_credentials_create(NULL);
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError,
-                    "couldn't create compute engine credentials");
-    return NULL;
-  }
-  return self;
-}
-
-/* TODO: Rename this credentials to something like service_account_jwt_access */
-CallCredentials *pygrpc_CallCredentials_jwt(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  CallCredentials *self;
-  const char *json_key;
-  double lifetime;
-  static char *keywords[] = {"json_key", "token_lifetime", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd:jwt", keywords,
-        &json_key, &lifetime)) {
-    return NULL;
-  }
-  self = (CallCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_service_account_jwt_access_credentials_create(
-      json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL);
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials");
-    return NULL;
-  }
-  return self;
-}
-
-CallCredentials *pygrpc_CallCredentials_refresh_token(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  CallCredentials *self;
-  const char *json_refresh_token;
-  static char *keywords[] = {"json_refresh_token", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords,
-        &json_refresh_token)) {
-    return NULL;
-  }
-  self = (CallCredentials *)type->tp_alloc(type, 0);
-  self->c_creds =
-      grpc_google_refresh_token_credentials_create(json_refresh_token, NULL);
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError,
-                    "couldn't create credentials from refresh token");
-    return NULL;
-  }
-  return self;
-}
-
-CallCredentials *pygrpc_CallCredentials_iam(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  CallCredentials *self;
-  const char *authorization_token;
-  const char *authority_selector;
-  static char *keywords[] = {"authorization_token", "authority_selector", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:iam", keywords,
-        &authorization_token, &authority_selector)) {
-    return NULL;
-  }
-  self = (CallCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_google_iam_credentials_create(authorization_token,
-                                                     authority_selector, NULL);
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials");
-    return NULL;
-  }
-  return self;
-}
-
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
deleted file mode 100644
index c4db2a0dfde3e9b53fe1332946716390d2676ac5..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-
-
-PyMethodDef pygrpc_Channel_methods[] = {
-    {"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""},
-    {"check_connectivity_state", (PyCFunction)pygrpc_Channel_check_connectivity_state, METH_KEYWORDS, ""},
-    {"watch_connectivity_state", (PyCFunction)pygrpc_Channel_watch_connectivity_state, METH_KEYWORDS, ""},
-    {"target", (PyCFunction)pygrpc_Channel_target, METH_NOARGS, ""},
-    {NULL}
-};
-const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel.";
-PyTypeObject pygrpc_Channel_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "Channel",                                /* tp_name */
-    sizeof(Channel),                          /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_Channel_dealloc,       /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_Channel_doc,                       /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_Channel_methods,                   /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    (newfunc)pygrpc_Channel_new               /* tp_new */
-};
-
-Channel *pygrpc_Channel_new(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  Channel *self;
-  const char *target;
-  PyObject *py_args;
-  ChannelCredentials *creds = NULL;
-  grpc_channel_args c_args;
-  char *keywords[] = {"target", "args", "creds", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords,
-        &target, &py_args, &pygrpc_ChannelCredentials_type, &creds)) {
-    return NULL;
-  }
-  if (!pygrpc_produce_channel_args(py_args, &c_args)) {
-    return NULL;
-  }
-  self = (Channel *)type->tp_alloc(type, 0);
-  if (creds) {
-    self->c_chan =
-        grpc_secure_channel_create(creds->c_creds, target, &c_args, NULL);
-  } else {
-    self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL);
-  }
-  pygrpc_discard_channel_args(c_args);
-  return self;
-}
-void pygrpc_Channel_dealloc(Channel *self) {
-  grpc_channel_destroy(self->c_chan);
-  self->ob_type->tp_free((PyObject *)self);
-}
-
-Call *pygrpc_Channel_create_call(
-    Channel *self, PyObject *args, PyObject *kwargs) {
-  Call *call;
-  CompletionQueue *cq;
-  const char *method;
-  const char *host;
-  double deadline;
-  char *keywords[] = {"cq", "method", "host", "deadline", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!szd:create_call", keywords,
-        &pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) {
-    return NULL;
-  }
-  call = pygrpc_Call_new_empty(cq);
-  call->c_call = grpc_channel_create_call(
-      self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host,
-      pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
-  return call;
-}
-
-PyObject *pygrpc_Channel_check_connectivity_state(
-    Channel *self, PyObject *args, PyObject *kwargs) {
-  PyObject *py_try_to_connect;
-  int try_to_connect;
-  char *keywords[] = {"try_to_connect", NULL};
-  grpc_connectivity_state state;
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:connectivity_state", keywords,
-                                   &py_try_to_connect)) {
-    return NULL;
-  }
-  if (!PyBool_Check(py_try_to_connect)) {
-    Py_XDECREF(py_try_to_connect);
-    return NULL;
-  }
-  try_to_connect = Py_True == py_try_to_connect;
-  Py_DECREF(py_try_to_connect);
-  state = grpc_channel_check_connectivity_state(self->c_chan, try_to_connect);
-  return PyInt_FromLong(state);
-}
-
-PyObject *pygrpc_Channel_watch_connectivity_state(
-    Channel *self, PyObject *args, PyObject *kwargs) {
-  PyObject *tag;
-  double deadline;
-  int last_observed_state;
-  CompletionQueue *completion_queue;
-  char *keywords[] = {"last_observed_state", "deadline",
-                      "completion_queue", "tag", NULL};
-  if (!PyArg_ParseTupleAndKeywords(
-      args, kwargs, "idO!O:watch_connectivity_state", keywords,
-      &last_observed_state, &deadline, &pygrpc_CompletionQueue_type,
-      &completion_queue, &tag)) {
-    return NULL;
-  }
-  grpc_channel_watch_connectivity_state(
-      self->c_chan, (grpc_connectivity_state)last_observed_state,
-      pygrpc_cast_double_to_gpr_timespec(deadline), completion_queue->c_cq,
-      pygrpc_produce_channel_state_change_tag(tag));
-  Py_RETURN_NONE;
-}
-
-PyObject *pygrpc_Channel_target(Channel *self) {
-  char *target = grpc_channel_get_target(self->c_chan);
-  PyObject *py_target = PyString_FromString(target);
-  gpr_free(target);
-  return py_target;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
deleted file mode 100644
index 83b1fc0406af9f4f9c9240bff4790ac972b94982..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-
-PyMethodDef pygrpc_ChannelCredentials_methods[] = {
-    {"google_default", (PyCFunction)pygrpc_ChannelCredentials_google_default,
-     METH_CLASS|METH_NOARGS, ""},
-    {"ssl", (PyCFunction)pygrpc_ChannelCredentials_ssl,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {"composite", (PyCFunction)pygrpc_ChannelCredentials_composite,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {NULL}
-};
-
-const char pygrpc_ChannelCredentials_doc[] = "";
-PyTypeObject pygrpc_ChannelCredentials_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "ChannelCredentials",                     /* tp_name */
-    sizeof(ChannelCredentials),               /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_ChannelCredentials_dealloc, /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_ChannelCredentials_doc,             /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_ChannelCredentials_methods,         /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    0                                         /* tp_new */
-};
-
-void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self) {
-  grpc_channel_credentials_release(self->c_creds);
-  self->ob_type->tp_free((PyObject *)self);
-}
-
-ChannelCredentials *pygrpc_ChannelCredentials_google_default(
-    PyTypeObject *type, PyObject *ignored) {
-  ChannelCredentials *self = (ChannelCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_google_default_credentials_create();
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError,
-                    "couldn't create Google default credentials");
-    return NULL;
-  }
-  return self;
-}
-
-ChannelCredentials *pygrpc_ChannelCredentials_ssl(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ChannelCredentials *self;
-  const char *root_certs;
-  const char *private_key = NULL;
-  const char *cert_chain = NULL;
-  grpc_ssl_pem_key_cert_pair key_cert_pair;
-  static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords,
-        &root_certs, &private_key, &cert_chain)) {
-    return NULL;
-  }
-  self = (ChannelCredentials *)type->tp_alloc(type, 0);
-  if (private_key && cert_chain) {
-    key_cert_pair.private_key = private_key;
-    key_cert_pair.cert_chain = cert_chain;
-    self->c_creds =
-        grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL);
-  } else {
-    self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL);
-  }
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials");
-    return NULL;
-  }
-  return self;
-}
-
-ChannelCredentials *pygrpc_ChannelCredentials_composite(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ChannelCredentials *self;
-  ChannelCredentials *creds1;
-  CallCredentials *creds2;
-  static char *keywords[] = {"creds1", "creds2", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
-        &pygrpc_ChannelCredentials_type, &creds1,
-        &pygrpc_CallCredentials_type, &creds2)) {
-    return NULL;
-  }
-  self = (ChannelCredentials *)type->tp_alloc(type, 0);
-  self->c_creds =
-      grpc_composite_channel_credentials_create(
-          creds1->c_creds, creds2->c_creds, NULL);
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(
-        PyExc_RuntimeError, "couldn't create composite credentials");
-    return NULL;
-  }
-  return self;
-}
-
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
deleted file mode 100644
index d8bb89ca4bc60c6bbb0eefa8f94dc36a846e78ea..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-
-
-PyMethodDef pygrpc_CompletionQueue_methods[] = {
-    {"next", (PyCFunction)pygrpc_CompletionQueue_next, METH_KEYWORDS, ""},
-    {"shutdown", (PyCFunction)pygrpc_CompletionQueue_shutdown, METH_NOARGS, ""},
-    {NULL}
-};
-const char pygrpc_CompletionQueue_doc[] =
-    "See grpc._adapter._types.CompletionQueue.";
-PyTypeObject pygrpc_CompletionQueue_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "CompletionQueue",                        /* tp_name */
-    sizeof(CompletionQueue),                  /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_CompletionQueue_dealloc, /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_CompletionQueue_doc,               /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_CompletionQueue_methods,           /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    (newfunc)pygrpc_CompletionQueue_new       /* tp_new */
-};
-
-CompletionQueue *pygrpc_CompletionQueue_new(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0);
-  self->c_cq = grpc_completion_queue_create(NULL);
-  return self;
-}
-
-void pygrpc_CompletionQueue_dealloc(CompletionQueue *self) {
-  grpc_completion_queue_destroy(self->c_cq);
-  self->ob_type->tp_free((PyObject *)self);
-}
-
-PyObject *pygrpc_CompletionQueue_next(
-    CompletionQueue *self, PyObject *args, PyObject *kwargs) {
-  double deadline;
-  grpc_event event;
-  PyObject *transliterated_event;
-  static char *keywords[] = {"deadline", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:next", keywords,
-                                   &deadline)) {
-    return NULL;
-  }
-  Py_BEGIN_ALLOW_THREADS;
-  event = grpc_completion_queue_next(
-      self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
-  Py_END_ALLOW_THREADS;
-  transliterated_event = pygrpc_consume_event(event);
-  return transliterated_event;
-}
-
-PyObject *pygrpc_CompletionQueue_shutdown(
-    CompletionQueue *self, PyObject *ignored) {
-  grpc_completion_queue_shutdown(self->c_cq);
-  Py_RETURN_NONE;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server.c b/src/python/grpcio/grpc/_adapter/_c/types/server.c
deleted file mode 100644
index 8feab8aab15d0b969f8abdbf5d26993dea41244f..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/server.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-
-
-PyMethodDef pygrpc_Server_methods[] = {
-    {"request_call", (PyCFunction)pygrpc_Server_request_call,
-     METH_KEYWORDS, ""},
-    {"add_http2_port", (PyCFunction)pygrpc_Server_add_http2_port,
-     METH_KEYWORDS, ""},
-    {"start", (PyCFunction)pygrpc_Server_start, METH_NOARGS, ""},
-    {"shutdown", (PyCFunction)pygrpc_Server_shutdown, METH_KEYWORDS, ""},
-    {"cancel_all_calls", (PyCFunction)pygrpc_Server_cancel_all_calls,
-     METH_NOARGS, ""},
-    {NULL}
-};
-const char pygrpc_Server_doc[] = "See grpc._adapter._types.Server.";
-PyTypeObject pygrpc_Server_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "Server",                                 /* tp_name */
-    sizeof(Server),                           /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_Server_dealloc,        /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_Server_doc,                        /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_Server_methods,                    /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    (newfunc)pygrpc_Server_new                /* tp_new */
-};
-
-Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  Server *self;
-  CompletionQueue *cq;
-  PyObject *py_args;
-  grpc_channel_args c_args;
-  char *keywords[] = {"cq", "args", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Server", keywords,
-        &pygrpc_CompletionQueue_type, &cq, &py_args)) {
-    return NULL;
-  }
-  if (!pygrpc_produce_channel_args(py_args, &c_args)) {
-    return NULL;
-  }
-  self = (Server *)type->tp_alloc(type, 0);
-  self->c_serv = grpc_server_create(&c_args, NULL);
-  grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL);
-  pygrpc_discard_channel_args(c_args);
-  self->cq = cq;
-  Py_INCREF(self->cq);
-  self->shutdown_called = 0;
-  return self;
-}
-
-void pygrpc_Server_dealloc(Server *self) {
-  grpc_server_destroy(self->c_serv);
-  Py_XDECREF(self->cq);
-  self->ob_type->tp_free((PyObject *)self);
-}
-
-PyObject *pygrpc_Server_request_call(
-    Server *self, PyObject *args, PyObject *kwargs) {
-  CompletionQueue *cq;
-  PyObject *user_tag;
-  pygrpc_tag *tag;
-  Call *empty_call;
-  grpc_call_error errcode;
-  static char *keywords[] = {"cq", "tag", NULL};
-  if (!PyArg_ParseTupleAndKeywords(
-      args, kwargs, "O!O", keywords,
-      &pygrpc_CompletionQueue_type, &cq, &user_tag)) {
-    return NULL;
-  }
-  empty_call = pygrpc_Call_new_empty(cq);
-  tag = pygrpc_produce_request_tag(user_tag, empty_call);
-  errcode = grpc_server_request_call(
-      self->c_serv, &tag->call->c_call, &tag->request_call_details,
-      &tag->request_metadata, tag->call->cq->c_cq, self->cq->c_cq, tag);
-  Py_DECREF(empty_call);
-  return PyInt_FromLong(errcode);
-}
-
-PyObject *pygrpc_Server_add_http2_port(
-    Server *self, PyObject *args, PyObject *kwargs) {
-  const char *addr;
-  ServerCredentials *creds = NULL;
-  int port;
-  static char *keywords[] = {"addr", "creds", NULL};
-  if (!PyArg_ParseTupleAndKeywords(
-      args, kwargs, "s|O!:add_http2_port", keywords,
-      &addr, &pygrpc_ServerCredentials_type, &creds)) {
-    return NULL;
-  }
-  if (creds) {
-    port = grpc_server_add_secure_http2_port(
-        self->c_serv, addr, creds->c_creds);
-  } else {
-    port = grpc_server_add_insecure_http2_port(self->c_serv, addr);
-  }
-  return PyInt_FromLong(port);
-
-}
-
-PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) {
-  grpc_server_start(self->c_serv);
-  self->shutdown_called = 0;
-  Py_RETURN_NONE;
-}
-
-PyObject *pygrpc_Server_shutdown(
-    Server *self, PyObject *args, PyObject *kwargs) {
-  PyObject *user_tag;
-  pygrpc_tag *tag;
-  static char *keywords[] = {"tag", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &user_tag)) {
-    return NULL;
-  }
-  tag = pygrpc_produce_server_shutdown_tag(user_tag);
-  grpc_server_shutdown_and_notify(self->c_serv, self->cq->c_cq, tag);
-  self->shutdown_called = 1;
-  Py_RETURN_NONE;
-}
-
-PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused) {
-  if (!self->shutdown_called) {
-    PyErr_SetString(
-        PyExc_RuntimeError,
-        "shutdown must have been called prior to calling cancel_all_calls!");
-    return NULL;
-  }
-  grpc_server_cancel_all_calls(self->c_serv);
-  Py_RETURN_NONE;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
deleted file mode 100644
index df51a99b6a9ce56116d63a926a569fa16544ff8d..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-#include <grpc/support/alloc.h>
-
-
-PyMethodDef pygrpc_ServerCredentials_methods[] = {
-    {"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {NULL}
-};
-const char pygrpc_ServerCredentials_doc[] = "";
-PyTypeObject pygrpc_ServerCredentials_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                        /* ob_size */
-    "ServerCredentials",                      /* tp_name */
-    sizeof(ServerCredentials),                /* tp_basicsize */
-    0,                                        /* tp_itemsize */
-    (destructor)pygrpc_ServerCredentials_dealloc, /* tp_dealloc */
-    0,                                        /* tp_print */
-    0,                                        /* tp_getattr */
-    0,                                        /* tp_setattr */
-    0,                                        /* tp_compare */
-    0,                                        /* tp_repr */
-    0,                                        /* tp_as_number */
-    0,                                        /* tp_as_sequence */
-    0,                                        /* tp_as_mapping */
-    0,                                        /* tp_hash */
-    0,                                        /* tp_call */
-    0,                                        /* tp_str */
-    0,                                        /* tp_getattro */
-    0,                                        /* tp_setattro */
-    0,                                        /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_ServerCredentials_doc,             /* tp_doc */
-    0,                                        /* tp_traverse */
-    0,                                        /* tp_clear */
-    0,                                        /* tp_richcompare */
-    0,                                        /* tp_weaklistoffset */
-    0,                                        /* tp_iter */
-    0,                                        /* tp_iternext */
-    pygrpc_ServerCredentials_methods,         /* tp_methods */
-    0,                                        /* tp_members */
-    0,                                        /* tp_getset */
-    0,                                        /* tp_base */
-    0,                                        /* tp_dict */
-    0,                                        /* tp_descr_get */
-    0,                                        /* tp_descr_set */
-    0,                                        /* tp_dictoffset */
-    0,                                        /* tp_init */
-    0,                                        /* tp_alloc */
-    0                                         /* tp_new */
-};
-
-void pygrpc_ServerCredentials_dealloc(ServerCredentials *self) {
-  grpc_server_credentials_release(self->c_creds);
-  self->ob_type->tp_free((PyObject *)self);
-}
-
-ServerCredentials *pygrpc_ServerCredentials_ssl(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ServerCredentials *self;
-  const char *root_certs;
-  PyObject *py_key_cert_pairs;
-  grpc_ssl_pem_key_cert_pair *key_cert_pairs;
-  int force_client_auth;
-  size_t num_key_cert_pairs;
-  size_t i;
-  static char *keywords[] = {
-      "root_certs", "key_cert_pairs", "force_client_auth", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zOi:ssl", keywords,
-	&root_certs, &py_key_cert_pairs, &force_client_auth)) {
-    return NULL;
-  }
-  if (!PyList_Check(py_key_cert_pairs)) {
-    PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings");
-    return NULL;
-  }
-  num_key_cert_pairs = PyList_Size(py_key_cert_pairs);
-  key_cert_pairs =
-      gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
-  for (i = 0; i < num_key_cert_pairs; ++i) {
-    PyObject *item = PyList_GET_ITEM(py_key_cert_pairs, i);
-    const char *key;
-    const char *cert;
-    if (!PyArg_ParseTuple(item, "zz", &key, &cert)) {
-      gpr_free(key_cert_pairs);
-      PyErr_SetString(PyExc_TypeError,
-                      "expected a list of 2-tuples of strings");
-      return NULL;
-    }
-    key_cert_pairs[i].private_key = key;
-    key_cert_pairs[i].cert_chain = cert;
-  }
-
-  self = (ServerCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_ssl_server_credentials_create(
-      root_certs, key_cert_pairs, num_key_cert_pairs, force_client_auth, NULL);
-  gpr_free(key_cert_pairs);
-  return self;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c
deleted file mode 100644
index 590f7e013a20207b0b8b9319239c09d2c7dc97a7..0000000000000000000000000000000000000000
--- a/src/python/grpcio/grpc/_adapter/_c/utility.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <math.h>
-#include <string.h>
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/byte_buffer_reader.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/time.h>
-#include <grpc/support/string_util.h>
-
-#include "grpc/_adapter/_c/types.h"
-
-pygrpc_tag *pygrpc_produce_batch_tag(
-    PyObject *user_tag, Call *call, grpc_op *ops, size_t nops) {
-  pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
-  tag->user_tag = user_tag;
-  Py_XINCREF(tag->user_tag);
-  tag->call = call;
-  Py_XINCREF(tag->call);
-  tag->ops = gpr_malloc(sizeof(grpc_op)*nops);
-  memcpy(tag->ops, ops, sizeof(grpc_op)*nops);
-  tag->nops = nops;
-  grpc_call_details_init(&tag->request_call_details);
-  grpc_metadata_array_init(&tag->request_metadata);
-  tag->is_new_call = 0;
-  return tag;
-}
-
-pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call) {
-  pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
-  tag->user_tag = user_tag;
-  Py_XINCREF(tag->user_tag);
-  tag->call = empty_call;
-  Py_XINCREF(tag->call);
-  tag->ops = NULL;
-  tag->nops = 0;
-  grpc_call_details_init(&tag->request_call_details);
-  grpc_metadata_array_init(&tag->request_metadata);
-  tag->is_new_call = 1;
-  return tag;
-}
-
-pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag) {
-  pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
-  tag->user_tag = user_tag;
-  Py_XINCREF(tag->user_tag);
-  tag->call = NULL;
-  tag->ops = NULL;
-  tag->nops = 0;
-  grpc_call_details_init(&tag->request_call_details);
-  grpc_metadata_array_init(&tag->request_metadata);
-  tag->is_new_call = 0;
-  return tag;
-}
-
-pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag) {
-  pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
-  tag->user_tag = user_tag;
-  Py_XINCREF(tag->user_tag);
-  tag->call = NULL;
-  tag->ops = NULL;
-  tag->nops = 0;
-  grpc_call_details_init(&tag->request_call_details);
-  grpc_metadata_array_init(&tag->request_metadata);
-  tag->is_new_call = 0;
-  return tag;
-}
-
-void pygrpc_discard_tag(pygrpc_tag *tag) {
-  if (!tag) {
-    return;
-  }
-  Py_XDECREF(tag->user_tag);
-  Py_XDECREF(tag->call);
-  gpr_free(tag->ops);
-  grpc_call_details_destroy(&tag->request_call_details);
-  grpc_metadata_array_destroy(&tag->request_metadata);
-  gpr_free(tag);
-}
-
-PyObject *pygrpc_consume_event(grpc_event event) {
-  pygrpc_tag *tag;
-  PyObject *result;
-  if (event.type == GRPC_QUEUE_TIMEOUT) {
-    Py_RETURN_NONE;
-  }
-  tag = event.tag;
-  switch (event.type) {
-  case GRPC_QUEUE_SHUTDOWN:
-    result = Py_BuildValue("iOOOOO", GRPC_QUEUE_SHUTDOWN,
-                           Py_None, Py_None, Py_None, Py_None, Py_True);
-    break;
-  case GRPC_OP_COMPLETE:
-    if (tag->is_new_call) {
-      result = Py_BuildValue(
-          "iOO(ssd)[(iNOOOO)]O", GRPC_OP_COMPLETE, tag->user_tag, tag->call,
-          tag->request_call_details.method, tag->request_call_details.host,
-          pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline),
-          GRPC_OP_RECV_INITIAL_METADATA,
-          pygrpc_cast_metadata_array_to_pyseq(tag->request_metadata), Py_None,
-          Py_None, Py_None, Py_None,
-          event.success ? Py_True : Py_False);
-    } else {
-      result = Py_BuildValue("iOOONO", GRPC_OP_COMPLETE, tag->user_tag,
-          tag->call ? (PyObject*)tag->call : Py_None, Py_None,
-          pygrpc_consume_ops(tag->ops, tag->nops),
-          event.success ? Py_True : Py_False);
-    }
-    break;
-  default:
-    PyErr_SetString(PyExc_ValueError,
-                    "unknown completion type; could not translate event");
-    return NULL;
-  }
-  pygrpc_discard_tag(tag);
-  return result;
-}
-
-int pygrpc_produce_op(PyObject *op, grpc_op *result) {
-  static const int OP_TUPLE_SIZE = 6;
-  static const int STATUS_TUPLE_SIZE = 2;
-  static const int TYPE_INDEX = 0;
-  static const int INITIAL_METADATA_INDEX = 1;
-  static const int TRAILING_METADATA_INDEX = 2;
-  static const int MESSAGE_INDEX = 3;
-  static const int STATUS_INDEX = 4;
-  static const int STATUS_CODE_INDEX = 0;
-  static const int STATUS_DETAILS_INDEX = 1;
-  static const int WRITE_FLAGS_INDEX = 5;
-  int type;
-  Py_ssize_t message_size;
-  char *message;
-  char *status_details;
-  gpr_slice message_slice;
-  grpc_op c_op;
-  if (!PyTuple_Check(op)) {
-    PyErr_SetString(PyExc_TypeError, "expected tuple op");
-    return 0;
-  }
-  if (PyTuple_Size(op) != OP_TUPLE_SIZE) {
-    char *buf;
-    gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE);
-    PyErr_SetString(PyExc_ValueError, buf);
-    gpr_free(buf);
-    return 0;
-  }
-  type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX));
-  if (PyErr_Occurred()) {
-    return 0;
-  }
-  c_op.op = type;
-  c_op.reserved = NULL;
-  c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX));
-  if (PyErr_Occurred()) {
-    return 0;
-  }
-  switch (type) {
-  case GRPC_OP_SEND_INITIAL_METADATA:
-    if (!pygrpc_cast_pyseq_to_send_metadata(
-            PyTuple_GetItem(op, INITIAL_METADATA_INDEX),
-            &c_op.data.send_initial_metadata.metadata,
-            &c_op.data.send_initial_metadata.count)) {
-      return 0;
-    }
-    break;
-  case GRPC_OP_SEND_MESSAGE:
-    PyString_AsStringAndSize(
-        PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size);
-    message_slice = gpr_slice_from_copied_buffer(message, message_size);
-    c_op.data.send_message = grpc_raw_byte_buffer_create(&message_slice, 1);
-    gpr_slice_unref(message_slice);
-    break;
-  case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-    /* Don't need to fill in any other fields. */
-    break;
-  case GRPC_OP_SEND_STATUS_FROM_SERVER:
-    if (!pygrpc_cast_pyseq_to_send_metadata(
-            PyTuple_GetItem(op, TRAILING_METADATA_INDEX),
-            &c_op.data.send_status_from_server.trailing_metadata,
-            &c_op.data.send_status_from_server.trailing_metadata_count)) {
-      return 0;
-    }
-    if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) {
-      char *buf;
-      gpr_asprintf(&buf, "expected tuple status in op of length %d",
-                   STATUS_TUPLE_SIZE);
-      PyErr_SetString(PyExc_ValueError, buf);
-      gpr_free(buf);
-      return 0;
-    }
-    c_op.data.send_status_from_server.status = PyInt_AsLong(
-        PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX));
-    status_details = PyString_AsString(
-        PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX));
-    if (PyErr_Occurred()) {
-      return 0;
-    }
-    c_op.data.send_status_from_server.status_details =
-        gpr_malloc(strlen(status_details) + 1);
-    strcpy((char *)c_op.data.send_status_from_server.status_details,
-           status_details);
-    break;
-  case GRPC_OP_RECV_INITIAL_METADATA:
-    c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array));
-    grpc_metadata_array_init(c_op.data.recv_initial_metadata);
-    break;
-  case GRPC_OP_RECV_MESSAGE:
-    c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *));
-    break;
-  case GRPC_OP_RECV_STATUS_ON_CLIENT:
-    c_op.data.recv_status_on_client.trailing_metadata =
-        gpr_malloc(sizeof(grpc_metadata_array));
-    grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata);
-    c_op.data.recv_status_on_client.status =
-        gpr_malloc(sizeof(grpc_status_code *));
-    c_op.data.recv_status_on_client.status_details =
-        gpr_malloc(sizeof(char *));
-    *c_op.data.recv_status_on_client.status_details = NULL;
-    c_op.data.recv_status_on_client.status_details_capacity =
-        gpr_malloc(sizeof(size_t));
-    *c_op.data.recv_status_on_client.status_details_capacity = 0;
-    break;
-  case GRPC_OP_RECV_CLOSE_ON_SERVER:
-    c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int));
-    break;
-  default:
-    return 0;
-  }
-  *result = c_op;
-  return 1;
-}
-
-void pygrpc_discard_op(grpc_op op) {
-  size_t i;
-  switch(op.op) {
-  case GRPC_OP_SEND_INITIAL_METADATA:
-    /* Whenever we produce send-metadata, we allocate new strings (to handle
-       arbitrary sequence input as opposed to just lists or just tuples). We
-       thus must free those elements. */
-    for (i = 0; i < op.data.send_initial_metadata.count; ++i) {
-      gpr_free((void *)op.data.send_initial_metadata.metadata[i].key);
-      gpr_free((void *)op.data.send_initial_metadata.metadata[i].value);
-    }
-    gpr_free(op.data.send_initial_metadata.metadata);
-    break;
-  case GRPC_OP_SEND_MESSAGE:
-    grpc_byte_buffer_destroy(op.data.send_message);
-    break;
-  case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-    /* Don't need to free any fields. */
-    break;
-  case GRPC_OP_SEND_STATUS_FROM_SERVER:
-    /* Whenever we produce send-metadata, we allocate new strings (to handle
-       arbitrary sequence input as opposed to just lists or just tuples). We
-       thus must free those elements. */
-    for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count;
-         ++i) {
-      gpr_free(
-          (void *)op.data.send_status_from_server.trailing_metadata[i].key);
-      gpr_free(
-          (void *)op.data.send_status_from_server.trailing_metadata[i].value);
-    }
-    gpr_free(op.data.send_status_from_server.trailing_metadata);
-    gpr_free((char *)op.data.send_status_from_server.status_details);
-    break;
-  case GRPC_OP_RECV_INITIAL_METADATA:
-    grpc_metadata_array_destroy(op.data.recv_initial_metadata);
-    gpr_free(op.data.recv_initial_metadata);
-    break;
-  case GRPC_OP_RECV_MESSAGE:
-    grpc_byte_buffer_destroy(*op.data.recv_message);
-    gpr_free(op.data.recv_message);
-    break;
-  case GRPC_OP_RECV_STATUS_ON_CLIENT:
-    grpc_metadata_array_destroy(op.data.recv_status_on_client.trailing_metadata);
-    gpr_free(op.data.recv_status_on_client.trailing_metadata);
-    gpr_free(op.data.recv_status_on_client.status);
-    gpr_free(*op.data.recv_status_on_client.status_details);
-    gpr_free(op.data.recv_status_on_client.status_details);
-    gpr_free(op.data.recv_status_on_client.status_details_capacity);
-    break;
-  case GRPC_OP_RECV_CLOSE_ON_SERVER:
-    gpr_free(op.data.recv_close_on_server.cancelled);
-    break;
-  }
-}
-
-PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) {
-  static const int TYPE_INDEX = 0;
-  static const int INITIAL_METADATA_INDEX = 1;
-  static const int TRAILING_METADATA_INDEX = 2;
-  static const int MESSAGE_INDEX = 3;
-  static const int STATUS_INDEX = 4;
-  static const int CANCELLED_INDEX = 5;
-  static const int OPRESULT_LENGTH = 6;
-  PyObject *list;
-  size_t i;
-  size_t j;
-  char *bytes;
-  size_t bytes_size;
-  PyObject *results = PyList_New(nops);
-  if (!results) {
-    return NULL;
-  }
-  for (i = 0; i < nops; ++i) {
-    PyObject *result = PyTuple_Pack(OPRESULT_LENGTH, Py_None, Py_None, Py_None,
-                                    Py_None, Py_None, Py_None);
-    PyTuple_SetItem(result, TYPE_INDEX, PyInt_FromLong(op[i].op));
-    switch(op[i].op) {
-    case GRPC_OP_RECV_INITIAL_METADATA:
-      PyTuple_SetItem(result, INITIAL_METADATA_INDEX,
-                      list=PyList_New(op[i].data.recv_initial_metadata->count));
-      for (j = 0; j < op[i].data.recv_initial_metadata->count; ++j) {
-        grpc_metadata md = op[i].data.recv_initial_metadata->metadata[j];
-        PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value,
-                                              (Py_ssize_t)md.value_length));
-      }
-      break;
-    case GRPC_OP_RECV_MESSAGE:
-      if (*op[i].data.recv_message) {
-        pygrpc_byte_buffer_to_bytes(
-            *op[i].data.recv_message, &bytes, &bytes_size);
-        PyTuple_SetItem(result, MESSAGE_INDEX,
-                        PyString_FromStringAndSize(bytes, bytes_size));
-        gpr_free(bytes);
-      } else {
-        PyTuple_SetItem(result, MESSAGE_INDEX, Py_BuildValue(""));
-      }
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      PyTuple_SetItem(
-          result, TRAILING_METADATA_INDEX,
-          list = PyList_New(op[i].data.recv_status_on_client.trailing_metadata->count));
-      for (j = 0; j < op[i].data.recv_status_on_client.trailing_metadata->count; ++j) {
-        grpc_metadata md =
-            op[i].data.recv_status_on_client.trailing_metadata->metadata[j];
-        PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value,
-                                              (Py_ssize_t)md.value_length));
-      }
-      PyTuple_SetItem(
-          result, STATUS_INDEX, Py_BuildValue(
-              "is", *op[i].data.recv_status_on_client.status,
-              *op[i].data.recv_status_on_client.status_details));
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      PyTuple_SetItem(
-          result, CANCELLED_INDEX,
-          PyBool_FromLong(*op[i].data.recv_close_on_server.cancelled));
-      break;
-    default:
-      break;
-    }
-    pygrpc_discard_op(op[i]);
-    PyList_SetItem(results, i, result);
-  }
-  return results;
-}
-
-double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) {
-  timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME);
-  return timespec.tv_sec + 1e-9*timespec.tv_nsec;
-}
-
-/* Because C89 doesn't have a way to check for infinity... */
-static int pygrpc_isinf(double x) {
-  return x * 0 != 0;
-}
-
-gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) {
-  gpr_timespec result;
-  if (pygrpc_isinf(seconds)) {
-    result = seconds > 0.0 ? gpr_inf_future(GPR_CLOCK_REALTIME)
-                           : gpr_inf_past(GPR_CLOCK_REALTIME);
-  } else {
-    result.tv_sec = (time_t)seconds;
-    result.tv_nsec = ((seconds - result.tv_sec) * 1e9);
-    result.clock_type = GPR_CLOCK_REALTIME;
-  }
-  return result;
-}
-
-int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args) {
-  size_t num_args = PyList_Size(py_args);
-  size_t i;
-  grpc_channel_args args;
-  args.num_args = num_args;
-  args.args = gpr_malloc(sizeof(grpc_arg) * num_args);
-  for (i = 0; i < args.num_args; ++i) {
-    char *key;
-    PyObject *value;
-    if (!PyArg_ParseTuple(PyList_GetItem(py_args, i), "zO", &key, &value)) {
-      gpr_free(args.args);
-      args.num_args = 0;
-      args.args = NULL;
-      PyErr_SetString(PyExc_TypeError,
-                      "expected a list of 2-tuple of str and str|int|None");
-      return 0;
-    }
-    args.args[i].key = key;
-    if (PyInt_Check(value)) {
-      args.args[i].type = GRPC_ARG_INTEGER;
-      args.args[i].value.integer = PyInt_AsLong(value);
-    } else if (PyString_Check(value)) {
-      args.args[i].type = GRPC_ARG_STRING;
-      args.args[i].value.string = PyString_AsString(value);
-    } else if (value == Py_None) {
-      --args.num_args;
-      --i;
-      continue;
-    } else {
-      gpr_free(args.args);
-      args.num_args = 0;
-      args.args = NULL;
-      PyErr_SetString(PyExc_TypeError,
-                      "expected a list of 2-tuple of str and str|int|None");
-      return 0;
-    }
-  }
-  *c_args = args;
-  return 1;
-}
-
-void pygrpc_discard_channel_args(grpc_channel_args args) {
-  gpr_free(args.args);
-}
-
-int pygrpc_cast_pyseq_to_send_metadata(
-    PyObject *pyseq, grpc_metadata **metadata, size_t *count) {
-  size_t i;
-  Py_ssize_t value_length;
-  char *key;
-  char *value;
-  if (!PySequence_Check(pyseq)) {
-    return 0;
-  }
-  *count = PySequence_Size(pyseq);
-  *metadata = gpr_malloc(sizeof(grpc_metadata) * *count);
-  for (i = 0; i < *count; ++i) {
-    PyObject *item = PySequence_GetItem(pyseq, i);
-    if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) {
-      Py_DECREF(item);
-      gpr_free(*metadata);
-      *count = 0;
-      *metadata = NULL;
-      return 0;
-    } else {
-      (*metadata)[i].key = gpr_strdup(key);
-      (*metadata)[i].value = gpr_malloc(value_length);
-      memcpy((void *)(*metadata)[i].value, value, value_length);
-      Py_DECREF(item);
-    }
-    (*metadata)[i].value_length = value_length;
-  }
-  return 1;
-}
-
-PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) {
-  PyObject *result = PyTuple_New(metadata.count);
-  size_t i;
-  for (i = 0; i < metadata.count; ++i) {
-    PyTuple_SetItem(
-        result, i, Py_BuildValue(
-            "ss#", metadata.metadata[i].key, metadata.metadata[i].value,
-            (Py_ssize_t)metadata.metadata[i].value_length));
-    if (PyErr_Occurred()) {
-      Py_DECREF(result);
-      return NULL;
-    }
-  }
-  return result;
-}
-
-void pygrpc_byte_buffer_to_bytes(
-    grpc_byte_buffer *buffer, char **result, size_t *result_size) {
-  grpc_byte_buffer_reader reader;
-  gpr_slice slice;
-  char *read_result = NULL;
-  size_t size = 0;
-  grpc_byte_buffer_reader_init(&reader, buffer);
-  while (grpc_byte_buffer_reader_next(&reader, &slice)) {
-    read_result = gpr_realloc(read_result, size + GPR_SLICE_LENGTH(slice));
-    memcpy(read_result + size, GPR_SLICE_START_PTR(slice),
-           GPR_SLICE_LENGTH(slice));
-    size = size + GPR_SLICE_LENGTH(slice);
-    gpr_slice_unref(slice);
-  }
-  *result_size = size;
-  *result = read_result;
-}
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_c_test.py b/src/python/grpcio/grpc/_adapter/_implementations.py
similarity index 74%
rename from src/python/grpcio_test/grpc_test/_adapter/_c_test.py
rename to src/python/grpcio/grpc/_adapter/_implementations.py
index fe020e2a9cfe915faa30859dc942634fa8c46ec8..b85f228bf69ee37c7524b73d551c88f6f98953fb 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_c_test.py
+++ b/src/python/grpcio/grpc/_adapter/_implementations.py
@@ -27,29 +27,22 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import time
-import unittest
+import collections
 
-from grpc._adapter import _c
-from grpc._adapter import _types
+from grpc.beta import interfaces
 
+class AuthMetadataContext(collections.namedtuple(
+    'AuthMetadataContext', [
+        'service_url',
+        'method_name'
+    ]), interfaces.GRPCAuthMetadataContext):
+  pass
 
-class CTypeSmokeTest(unittest.TestCase):
 
-  def testCompletionQueueUpDown(self):
-    completion_queue = _c.CompletionQueue()
-    del completion_queue
+class AuthMetadataPluginCallback(interfaces.GRPCAuthMetadataContext):
 
-  def testServerUpDown(self):
-    completion_queue = _c.CompletionQueue()
-    serv = _c.Server(completion_queue, [])
-    del serv
-    del completion_queue
+  def __init__(self, callback):
+    self._callback = callback
 
-  def testChannelUpDown(self):
-    channel = _c.Channel('[::]:0', [])
-    del channel
-
-
-if __name__ == '__main__':
-  unittest.main(verbosity=2)
+  def __call__(self, metadata, error):
+    self._callback(metadata, error)
diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
index 5634c2024d350f6d19d5f28ead406a2746f540e9..9698ffeabf1f967f8c4c86f147f22c488251d5cc 100644
--- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py
+++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
@@ -115,16 +115,20 @@ class Call(object):
     return call
 
   def invoke(self, completion_queue, metadata_tag, finish_tag):
-    err0 = self._internal.start_batch([
+    err = self._internal.start_batch([
           _types.OpArgs.send_initial_metadata(self._metadata)
       ], _IGNORE_ME_TAG)
-    err1 = self._internal.start_batch([
+    if err != _types.CallError.OK:
+      return err
+    err = self._internal.start_batch([
           _types.OpArgs.recv_initial_metadata()
       ], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED))
-    err2 = self._internal.start_batch([
+    if err != _types.CallError.OK:
+      return err
+    err = self._internal.start_batch([
           _types.OpArgs.recv_status_on_client()
       ], _TagAdapter(finish_tag, Event.Kind.FINISH))
-    return err0 if err0 != _types.CallError.OK else err1 if err1 != _types.CallError.OK else err2 if err2 != _types.CallError.OK else _types.CallError.OK
+    return err
 
   def write(self, message, tag, flags):
     return self._internal.start_batch([
@@ -158,7 +162,8 @@ class Call(object):
 
   def status(self, status, tag):
     return self._internal.start_batch([
-          _types.OpArgs.send_status_from_server(self._metadata, status.code, status.details)
+          _types.OpArgs.send_status_from_server(
+              self._metadata, status.code, status.details)
       ], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED))
 
   def cancel(self):
@@ -168,20 +173,17 @@ class Call(object):
     return self._internal.peer()
 
   def set_credentials(self, creds):
-    return self._internal.set_credentials(creds._internal)
+    return self._internal.set_credentials(creds)
 
 
 class Channel(object):
   """Adapter from old _low.Channel interface to new _low.Channel."""
 
-  def __init__(self, hostport, client_credentials, server_host_override=None):
+  def __init__(self, hostport, channel_credentials, server_host_override=None):
     args = []
     if server_host_override:
       args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override))
-    creds = None
-    if client_credentials:
-      creds = client_credentials._internal
-    self._internal = _low.Channel(hostport, args, creds)
+    self._internal = _low.Channel(hostport, args, channel_credentials)
 
 
 class CompletionQueue(object):
@@ -192,7 +194,7 @@ class CompletionQueue(object):
 
   def get(self, deadline=None):
     if deadline is None:
-      ev = self._internal.next()
+      ev = self._internal.next(float('+inf'))
     else:
       ev = self._internal.next(deadline)
     if ev is None:
@@ -240,7 +242,7 @@ class Server(object):
     if server_credentials is None:
       return self._internal.add_http2_port(addr, None)
     else:
-      return self._internal.add_http2_port(addr, server_credentials._internal)
+      return self._internal.add_http2_port(addr, server_credentials)
 
   def start(self):
     return self._internal.start()
@@ -248,20 +250,9 @@ class Server(object):
   def service(self, tag):
     return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED))
 
+  def cancel_all_calls(self):
+    self._internal.cancel_all_calls()
+
   def stop(self):
     return self._internal.shutdown(_TagAdapter(None, Event.Kind.STOP))
 
-
-class ClientCredentials(object):
-  """Adapter from old _low.ClientCredentials interface to new _low.ChannelCredentials."""
-
-  def __init__(self, root_certificates, private_key, certificate_chain):
-    self._internal = _low.ChannelCredentials.ssl(root_certificates, private_key, certificate_chain)
-
-
-class ServerCredentials(object):
-  """Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials."""
-
-  def __init__(self, root_credentials, pair_sequence, force_client_auth):
-    self._internal = _low.ServerCredentials.ssl(
-        root_credentials, list(pair_sequence), force_client_auth)
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index 57146aaefe8020933548c6803cbefa37f60510f2..b13d8dd9dda1f8e92e45d3fc5c18be1e7be2896f 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -27,36 +27,157 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+import threading
+
 from grpc import _grpcio_metadata
-from grpc._adapter import _c
+from grpc._cython import cygrpc
+from grpc._adapter import _implementations
 from grpc._adapter import _types
 
 _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
 
-ChannelCredentials = _c.ChannelCredentials
-CallCredentials = _c.CallCredentials
-ServerCredentials = _c.ServerCredentials
+ChannelCredentials = cygrpc.ChannelCredentials
+CallCredentials = cygrpc.CallCredentials
+ServerCredentials = cygrpc.ServerCredentials
+
+channel_credentials_composite = cygrpc.channel_credentials_composite
+call_credentials_composite = cygrpc.call_credentials_composite
+
+def server_credentials_ssl(root_credentials, pair_sequence, force_client_auth):
+  return cygrpc.server_credentials_ssl(
+      root_credentials,
+      [cygrpc.SslPemKeyCertPair(key, pem) for key, pem in pair_sequence],
+      force_client_auth)
+
+def channel_credentials_ssl(
+    root_certificates, private_key, certificate_chain):
+  pair = None
+  if private_key is not None or certificate_chain is not None:
+    pair = cygrpc.SslPemKeyCertPair(private_key, certificate_chain)
+  return cygrpc.channel_credentials_ssl(root_certificates, pair)
+
+
+class _WrappedCygrpcCallback(object):
+
+  def __init__(self, cygrpc_callback):
+    self.is_called = False
+    self.error = None
+    self.is_called_lock = threading.Lock()
+    self.cygrpc_callback = cygrpc_callback
+
+  def _invoke_failure(self, error):
+    # TODO(atash) translate different Exception superclasses into different
+    # status codes.
+    self.cygrpc_callback(
+        cygrpc.Metadata([]), cygrpc.StatusCode.internal, error.message)
+
+  def _invoke_success(self, metadata):
+    try:
+      cygrpc_metadata = cygrpc.Metadata(
+          cygrpc.Metadatum(key, value)
+          for key, value in metadata)
+    except Exception as error:
+      self._invoke_failure(error)
+      return
+    self.cygrpc_callback(cygrpc_metadata, cygrpc.StatusCode.ok, '')
+
+  def __call__(self, metadata, error):
+    with self.is_called_lock:
+      if self.is_called:
+        raise RuntimeError('callback should only ever be invoked once')
+      if self.error:
+        self._invoke_failure(self.error)
+        return
+      self.is_called = True
+    if error is None:
+      self._invoke_success(metadata)
+    else:
+      self._invoke_failure(error)
+
+  def notify_failure(self, error):
+    with self.is_called_lock:
+      if not self.is_called:
+        self.error = error
+
+
+class _WrappedPlugin(object):
+
+  def __init__(self, plugin):
+    self.plugin = plugin
+
+  def __call__(self, context, cygrpc_callback):
+    wrapped_cygrpc_callback = _WrappedCygrpcCallback(cygrpc_callback)
+    wrapped_context = _implementations.AuthMetadataContext(context.service_url,
+                                                           context.method_name)
+    try:
+      self.plugin(
+          wrapped_context,
+          _implementations.AuthMetadataPluginCallback(wrapped_cygrpc_callback))
+    except Exception as error:
+      wrapped_cygrpc_callback.notify_failure(error)
+      raise
+
+
+def call_credentials_metadata_plugin(plugin, name):
+  """
+  Args:
+    plugin: A callable accepting a _types.AuthMetadataContext
+      object and a callback (itself accepting a list of metadata key/value
+      2-tuples and a None-able exception value). The callback must be eventually
+      called, but need not be called in plugin's invocation.
+      plugin's invocation must be non-blocking.
+  """
+  return cygrpc.call_credentials_metadata_plugin(
+      cygrpc.CredentialsMetadataPlugin(_WrappedPlugin(plugin), name))
 
 
 class CompletionQueue(_types.CompletionQueue):
 
   def __init__(self):
-    self.completion_queue = _c.CompletionQueue()
+    self.completion_queue = cygrpc.CompletionQueue()
 
   def next(self, deadline=float('+inf')):
-    raw_event = self.completion_queue.next(deadline)
-    if raw_event is None:
+    raw_event = self.completion_queue.poll(cygrpc.Timespec(deadline))
+    if raw_event.type == cygrpc.CompletionType.queue_timeout:
       return None
-    event = _types.Event(*raw_event)
-    if event.call is not None:
-      event = event._replace(call=Call(event.call))
-    if event.call_details is not None:
-      event = event._replace(call_details=_types.CallDetails(*event.call_details))
-    if event.results is not None:
-      new_results = [_types.OpResult(*r) for r in event.results]
-      new_results = [r if r.status is None else r._replace(status=_types.Status(_types.StatusCode(r.status[0]), r.status[1])) for r in new_results]
-      event = event._replace(results=new_results)
-    return event
+    event_type = raw_event.type
+    event_tag = raw_event.tag
+    event_call = Call(raw_event.operation_call)
+    if raw_event.request_call_details:
+      event_call_details = _types.CallDetails(
+          raw_event.request_call_details.method,
+          raw_event.request_call_details.host,
+          float(raw_event.request_call_details.deadline))
+    else:
+      event_call_details = None
+    event_success = raw_event.success
+    event_results = []
+    if raw_event.is_new_request:
+      event_results.append(_types.OpResult(
+          _types.OpType.RECV_INITIAL_METADATA, raw_event.request_metadata,
+          None, None, None, None))
+    else:
+      if raw_event.batch_operations:
+        for operation in raw_event.batch_operations:
+          result_type = operation.type
+          result_initial_metadata = operation.received_metadata_or_none
+          result_trailing_metadata = operation.received_metadata_or_none
+          result_message = operation.received_message_or_none
+          if result_message is not None:
+            result_message = result_message.bytes()
+          result_cancelled = operation.received_cancelled_or_none
+          if operation.has_status:
+            result_status = _types.Status(
+                operation.received_status_code_or_none,
+                operation.received_status_details_or_none)
+          else:
+            result_status = None
+          event_results.append(
+              _types.OpResult(result_type, result_initial_metadata,
+                              result_trailing_metadata, result_message,
+                              result_status, result_cancelled))
+    return _types.Event(event_type, event_tag, event_call, event_call_details,
+                        event_results, event_success)
 
   def shutdown(self):
     self.completion_queue.shutdown()
@@ -68,7 +189,36 @@ class Call(_types.Call):
     self.call = call
 
   def start_batch(self, ops, tag):
-    return self.call.start_batch(ops, tag)
+    translated_ops = []
+    for op in ops:
+      if op.type == _types.OpType.SEND_INITIAL_METADATA:
+        translated_op = cygrpc.operation_send_initial_metadata(
+            cygrpc.Metadata(
+                cygrpc.Metadatum(key, value)
+                for key, value in op.initial_metadata))
+      elif op.type == _types.OpType.SEND_MESSAGE:
+        translated_op = cygrpc.operation_send_message(op.message)
+      elif op.type == _types.OpType.SEND_CLOSE_FROM_CLIENT:
+        translated_op = cygrpc.operation_send_close_from_client()
+      elif op.type == _types.OpType.SEND_STATUS_FROM_SERVER:
+        translated_op = cygrpc.operation_send_status_from_server(
+            cygrpc.Metadata(
+                cygrpc.Metadatum(key, value)
+                for key, value in op.trailing_metadata),
+            op.status.code,
+            op.status.details)
+      elif op.type == _types.OpType.RECV_INITIAL_METADATA:
+        translated_op = cygrpc.operation_receive_initial_metadata()
+      elif op.type == _types.OpType.RECV_MESSAGE:
+        translated_op = cygrpc.operation_receive_message()
+      elif op.type == _types.OpType.RECV_STATUS_ON_CLIENT:
+        translated_op = cygrpc.operation_receive_status_on_client()
+      elif op.type == _types.OpType.RECV_CLOSE_ON_SERVER:
+        translated_op = cygrpc.operation_receive_close_on_server()
+      else:
+        raise ValueError('unexpected operation type {}'.format(op.type))
+      translated_ops.append(translated_op)
+    return self.call.start_batch(cygrpc.Operations(translated_ops), tag)
 
   def cancel(self, code=None, details=None):
     if code is None and details is None:
@@ -86,14 +236,20 @@ class Call(_types.Call):
 class Channel(_types.Channel):
 
   def __init__(self, target, args, creds=None):
-    args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)]
+    args = list(args) + [
+        (cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT)]
+    args = cygrpc.ChannelArgs(
+        cygrpc.ChannelArg(key, value) for key, value in args)
     if creds is None:
-      self.channel = _c.Channel(target, args)
+      self.channel = cygrpc.Channel(target, args)
     else:
-      self.channel = _c.Channel(target, args, creds)
+      self.channel = cygrpc.Channel(target, args, creds)
 
   def create_call(self, completion_queue, method, host, deadline=None):
-    return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline))
+    internal_call = self.channel.create_call(
+        None, 0, completion_queue.completion_queue, method, host,
+        cygrpc.Timespec(deadline))
+    return Call(internal_call)
 
   def check_connectivity_state(self, try_to_connect):
     return self.channel.check_connectivity_state(try_to_connect)
@@ -101,7 +257,8 @@ class Channel(_types.Channel):
   def watch_connectivity_state(self, last_observed_state, deadline,
                                completion_queue, tag):
     self.channel.watch_connectivity_state(
-        last_observed_state, deadline, completion_queue.completion_queue, tag)
+        last_observed_state, cygrpc.Timespec(deadline),
+        completion_queue.completion_queue, tag)
 
   def target(self):
     return self.channel.target()
@@ -112,7 +269,11 @@ _NO_TAG = object()
 class Server(_types.Server):
 
   def __init__(self, completion_queue, args):
-    self.server = _c.Server(completion_queue.completion_queue, args)
+    args = cygrpc.ChannelArgs(
+        cygrpc.ChannelArg(key, value) for key, value in args)
+    self.server = cygrpc.Server(args)
+    self.server.register_completion_queue(completion_queue.completion_queue)
+    self.server_queue = completion_queue
 
   def add_http2_port(self, addr, creds=None):
     if creds is None:
@@ -124,10 +285,11 @@ class Server(_types.Server):
     return self.server.start()
 
   def shutdown(self, tag=None):
-    return self.server.shutdown(tag)
+    return self.server.shutdown(self.server_queue.completion_queue, tag)
 
   def request_call(self, completion_queue, tag):
-    return self.server.request_call(completion_queue.completion_queue, tag)
+    return self.server.request_call(completion_queue.completion_queue,
+                                    self.server_queue.completion_queue, tag)
 
   def cancel_all_calls(self):
     return self.server.cancel_all_calls()
diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py
index ca0fa066bc8e7d6bf005acde6898c4d6304276a8..3d5ab33d0084aef6d457dd63f4e153125fcc544d 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -31,6 +31,8 @@ import abc
 import collections
 import enum
 
+from grpc._cython import cygrpc
+
 
 class GrpcChannelArgumentKeys(enum.Enum):
   """Mirrors keys used in grpc_channel_args for GRPC-specific arguments."""
@@ -40,77 +42,77 @@ class GrpcChannelArgumentKeys(enum.Enum):
 @enum.unique
 class CallError(enum.IntEnum):
   """Mirrors grpc_call_error in the C core."""
-  OK                        = 0
-  ERROR                     = 1
-  ERROR_NOT_ON_SERVER       = 2
-  ERROR_NOT_ON_CLIENT       = 3
-  ERROR_ALREADY_ACCEPTED    = 4
-  ERROR_ALREADY_INVOKED     = 5
-  ERROR_NOT_INVOKED         = 6
-  ERROR_ALREADY_FINISHED    = 7
-  ERROR_TOO_MANY_OPERATIONS = 8
-  ERROR_INVALID_FLAGS       = 9
-  ERROR_INVALID_METADATA    = 10
+  OK                        = cygrpc.CallError.ok
+  ERROR                     = cygrpc.CallError.error
+  ERROR_NOT_ON_SERVER       = cygrpc.CallError.not_on_server
+  ERROR_NOT_ON_CLIENT       = cygrpc.CallError.not_on_client
+  ERROR_ALREADY_ACCEPTED    = cygrpc.CallError.already_accepted
+  ERROR_ALREADY_INVOKED     = cygrpc.CallError.already_invoked
+  ERROR_NOT_INVOKED         = cygrpc.CallError.not_invoked
+  ERROR_ALREADY_FINISHED    = cygrpc.CallError.already_finished
+  ERROR_TOO_MANY_OPERATIONS = cygrpc.CallError.too_many_operations
+  ERROR_INVALID_FLAGS       = cygrpc.CallError.invalid_flags
+  ERROR_INVALID_METADATA    = cygrpc.CallError.invalid_metadata
 
 
 @enum.unique
 class StatusCode(enum.IntEnum):
   """Mirrors grpc_status_code in the C core."""
-  OK                  = 0
-  CANCELLED           = 1
-  UNKNOWN             = 2
-  INVALID_ARGUMENT    = 3
-  DEADLINE_EXCEEDED   = 4
-  NOT_FOUND           = 5
-  ALREADY_EXISTS      = 6
-  PERMISSION_DENIED   = 7
-  RESOURCE_EXHAUSTED  = 8
-  FAILED_PRECONDITION = 9
-  ABORTED             = 10
-  OUT_OF_RANGE        = 11
-  UNIMPLEMENTED       = 12
-  INTERNAL            = 13
-  UNAVAILABLE         = 14
-  DATA_LOSS           = 15
-  UNAUTHENTICATED     = 16
+  OK                  = cygrpc.StatusCode.ok
+  CANCELLED           = cygrpc.StatusCode.cancelled
+  UNKNOWN             = cygrpc.StatusCode.unknown
+  INVALID_ARGUMENT    = cygrpc.StatusCode.invalid_argument
+  DEADLINE_EXCEEDED   = cygrpc.StatusCode.deadline_exceeded
+  NOT_FOUND           = cygrpc.StatusCode.not_found
+  ALREADY_EXISTS      = cygrpc.StatusCode.already_exists
+  PERMISSION_DENIED   = cygrpc.StatusCode.permission_denied
+  RESOURCE_EXHAUSTED  = cygrpc.StatusCode.resource_exhausted
+  FAILED_PRECONDITION = cygrpc.StatusCode.failed_precondition
+  ABORTED             = cygrpc.StatusCode.aborted
+  OUT_OF_RANGE        = cygrpc.StatusCode.out_of_range
+  UNIMPLEMENTED       = cygrpc.StatusCode.unimplemented
+  INTERNAL            = cygrpc.StatusCode.internal
+  UNAVAILABLE         = cygrpc.StatusCode.unavailable
+  DATA_LOSS           = cygrpc.StatusCode.data_loss
+  UNAUTHENTICATED     = cygrpc.StatusCode.unauthenticated
 
 
 @enum.unique
 class OpWriteFlags(enum.IntEnum):
   """Mirrors defined write-flag constants in the C core."""
-  WRITE_BUFFER_HINT = 1
-  WRITE_NO_COMPRESS = 2
+  WRITE_BUFFER_HINT = cygrpc.WriteFlag.buffer_hint
+  WRITE_NO_COMPRESS = cygrpc.WriteFlag.no_compress
 
 
 @enum.unique
 class OpType(enum.IntEnum):
   """Mirrors grpc_op_type in the C core."""
-  SEND_INITIAL_METADATA   = 0
-  SEND_MESSAGE            = 1
-  SEND_CLOSE_FROM_CLIENT  = 2
-  SEND_STATUS_FROM_SERVER = 3
-  RECV_INITIAL_METADATA   = 4
-  RECV_MESSAGE            = 5
-  RECV_STATUS_ON_CLIENT   = 6
-  RECV_CLOSE_ON_SERVER    = 7
+  SEND_INITIAL_METADATA   = cygrpc.OperationType.send_initial_metadata
+  SEND_MESSAGE            = cygrpc.OperationType.send_message
+  SEND_CLOSE_FROM_CLIENT  = cygrpc.OperationType.send_close_from_client
+  SEND_STATUS_FROM_SERVER = cygrpc.OperationType.send_status_from_server
+  RECV_INITIAL_METADATA   = cygrpc.OperationType.receive_initial_metadata
+  RECV_MESSAGE            = cygrpc.OperationType.receive_message
+  RECV_STATUS_ON_CLIENT   = cygrpc.OperationType.receive_status_on_client
+  RECV_CLOSE_ON_SERVER    = cygrpc.OperationType.receive_close_on_server
 
 
 @enum.unique
 class EventType(enum.IntEnum):
   """Mirrors grpc_completion_type in the C core."""
-  QUEUE_SHUTDOWN = 0
-  QUEUE_TIMEOUT  = 1  # if seen on the Python side, something went horridly wrong
-  OP_COMPLETE    = 2
+  QUEUE_SHUTDOWN = cygrpc.CompletionType.queue_shutdown
+  QUEUE_TIMEOUT  = cygrpc.CompletionType.queue_timeout
+  OP_COMPLETE    = cygrpc.CompletionType.operation_complete
 
 
 @enum.unique
 class ConnectivityState(enum.IntEnum):
   """Mirrors grpc_connectivity_state in the C core."""
-  IDLE              = 0
-  CONNECTING        = 1
-  READY             = 2
-  TRANSIENT_FAILURE = 3
-  FATAL_FAILURE     = 4
+  IDLE              = cygrpc.ConnectivityState.idle
+  CONNECTING        = cygrpc.ConnectivityState.connecting
+  READY             = cygrpc.ConnectivityState.ready
+  TRANSIENT_FAILURE = cygrpc.ConnectivityState.transient_failure
+  FATAL_FAILURE     = cygrpc.ConnectivityState.fatal_failure
 
 
 class Status(collections.namedtuple(
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
index 51c46681388f43e6ed720d2da557fce7f8101167..1c07f9f4f4c6870dd3451844a188eee58d998e0b 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
@@ -53,24 +53,24 @@ cdef class Call:
         self.c_call, cy_operations.c_ops, cy_operations.c_nops,
         <cpython.PyObject *>operation_tag, NULL)
 
-  def cancel(self,
-             grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
-             details=None):
+  def cancel(
+      self, grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
+      details=None):
     if not self.is_valid:
       raise ValueError("invalid call object cannot be used from Python")
     if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE):
       raise ValueError("if error_code is specified, so must details "
                        "(and vice-versa)")
-    if isinstance(details, bytes):
-      pass
-    elif isinstance(details, basestring):
-      details = details.encode()
-    else:
-      raise TypeError("expected details to be str or bytes")
     if error_code != grpc.GRPC_STATUS__DO_NOT_USE:
+      if isinstance(details, bytes):
+        pass
+      elif isinstance(details, basestring):
+        details = details.encode()
+      else:
+        raise TypeError("expected details to be str or bytes")
       self.references.append(details)
-      return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details,
-                                               NULL)
+      return grpc.grpc_call_cancel_with_status(
+          self.c_call, error_code, details, NULL)
     else:
       return grpc.grpc_call_cancel(self.c_call, NULL)
 
@@ -79,6 +79,12 @@ cdef class Call:
     return grpc.grpc_call_set_credentials(
         self.c_call, call_credentials.c_credentials)
 
+  def peer(self):
+    cdef char *peer = grpc.grpc_call_get_peer(self.c_call)
+    result = <bytes>peer
+    grpc.gpr_free(peer)
+    return result
+
   def __dealloc__(self):
     if self.c_call != NULL:
       grpc.grpc_call_destroy(self.c_call)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
index e25db3e2a442095aec7c367afcc6b262e6a0474d..a944a83576c5dfe393124af74df9573e74ba5295 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
@@ -27,6 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+cimport cpython
+
 from grpc._cython._cygrpc cimport call
 from grpc._cython._cygrpc cimport completion_queue
 from grpc._cython._cygrpc cimport credentials
@@ -70,12 +72,16 @@ cdef class Channel:
       method = method.encode()
     else:
       raise TypeError("expected method to be str or bytes")
-    if isinstance(host, bytes):
+    cdef char *host_c_string = NULL
+    if host is None:
       pass
+    elif isinstance(host, bytes):
+      host_c_string = host
     elif isinstance(host, basestring):
       host = host.encode()
+      host_c_string = host
     else:
-      raise TypeError("expected host to be str or bytes")
+      raise TypeError("expected host to be str, bytes, or None")
     cdef call.Call operation_call = call.Call()
     operation_call.references = [self, method, host, queue]
     cdef grpc.grpc_call *parent_call = NULL
@@ -83,10 +89,29 @@ cdef class Channel:
       parent_call = parent.c_call
     operation_call.c_call = grpc.grpc_channel_create_call(
         self.c_channel, parent_call, flags,
-        queue.c_completion_queue, method, host, deadline.c_time,
+        queue.c_completion_queue, method, host_c_string, deadline.c_time,
         NULL)
     return operation_call
 
+  def check_connectivity_state(self, bint try_to_connect):
+    return grpc.grpc_channel_check_connectivity_state(self.c_channel,
+                                                      try_to_connect)
+
+  def watch_connectivity_state(
+      self, last_observed_state, records.Timespec deadline not None,
+      completion_queue.CompletionQueue queue not None, tag):
+    cdef records.OperationTag operation_tag = records.OperationTag(tag)
+    cpython.Py_INCREF(operation_tag)
+    grpc.grpc_channel_watch_connectivity_state(
+        self.c_channel, last_observed_state, deadline.c_time,
+        queue.c_completion_queue, <cpython.PyObject *>operation_tag)
+
+  def target(self):
+    cdef char * target = grpc.grpc_channel_get_target(self.c_channel)
+    result = <bytes>target
+    grpc.gpr_free(target)
+    return result
+
   def __dealloc__(self):
     if self.c_channel != NULL:
       grpc.grpc_channel_destroy(self.c_channel)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
index a7a265eab7d34d66a9126f9a917f75702376f093..2cf49707b48dbb83eb69da6194e331c1879f6af9 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
@@ -62,6 +62,8 @@ cdef class CompletionQueue:
     cdef grpc.grpc_event event
 
     # Poll within a critical section
+    # TODO consider making queue polling contention a hard error to enable
+    # easier bug discovery
     with self.poll_condition:
       while self.is_polling:
         self.poll_condition.wait(float(deadline) - time.time())
@@ -74,10 +76,12 @@ cdef class CompletionQueue:
       self.poll_condition.notify()
 
     if event.type == grpc.GRPC_QUEUE_TIMEOUT:
-      return records.Event(event.type, False, None, None, None, None, None)
+      return records.Event(
+          event.type, False, None, None, None, None, False, None)
     elif event.type == grpc.GRPC_QUEUE_SHUTDOWN:
       self.is_shutdown = True
-      return records.Event(event.type, True, None, None, None, None, None)
+      return records.Event(
+          event.type, True, None, None, None, None, False, None)
     else:
       if event.tag != NULL:
         tag = <records.OperationTag>event.tag
@@ -97,7 +101,8 @@ cdef class CompletionQueue:
           operation_call.references.extend(tag.references)
       return records.Event(
           event.type, event.success, user_tag, operation_call,
-          request_call_details, request_metadata, batch_operations)
+          request_call_details, request_metadata, tag.is_new_request,
+          batch_operations)
 
   def shutdown(self):
     grpc.grpc_completion_queue_shutdown(self.c_completion_queue)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
index 7a9fa7b76d01b3b3596be369fe77ac3481818a6b..db9f8ddec9936ab6ecdf9a0464f05cebac49a2d6 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
@@ -27,7 +27,10 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+cimport cpython
+
 from grpc._cython._cygrpc cimport grpc
+from grpc._cython._cygrpc cimport records
 
 
 cdef class ChannelCredentials:
@@ -49,3 +52,23 @@ cdef class ServerCredentials:
   cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
   cdef size_t c_ssl_pem_key_cert_pairs_count
   cdef list references
+
+
+cdef class CredentialsMetadataPlugin:
+
+  cdef object plugin_callback
+  cdef str plugin_name
+
+  cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self)
+
+
+cdef class AuthMetadataContext:
+
+  cdef grpc.grpc_auth_metadata_context context
+
+
+cdef void plugin_get_metadata(
+    void *state, grpc.grpc_auth_metadata_context context,
+    grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil
+
+cdef void plugin_destroy_c_plugin_state(void *state)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
index e9836fec2cf7ed08446373d67634a56d4e57dafd..a968894967a542ec059f98bbfd4fd12c6f0d3f18 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
@@ -27,6 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+cimport cpython
+
 from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
@@ -71,19 +73,80 @@ cdef class ServerCredentials:
 
   def __cinit__(self):
     self.c_credentials = NULL
+    self.references = []
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
       grpc.grpc_server_credentials_release(self.c_credentials)
 
 
+cdef class CredentialsMetadataPlugin:
+
+  def __cinit__(self, object plugin_callback, str name):
+    """
+    Args:
+      plugin_callback (callable): Callback accepting a service URL (str/bytes)
+        and callback object (accepting a records.Metadata,
+        grpc.grpc_status_code, and a str/bytes error message). This argument
+        when called should be non-blocking and eventually call the callback
+        object with the appropriate status code/details and metadata (if
+        successful).
+      name (str): Plugin name.
+    """
+    if not callable(plugin_callback):
+      raise ValueError('expected callable plugin_callback')
+    self.plugin_callback = plugin_callback
+    self.plugin_name = name
+
+  @staticmethod
+  cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self):
+    cdef grpc.grpc_metadata_credentials_plugin result
+    result.get_metadata = plugin_get_metadata
+    result.destroy = plugin_destroy_c_plugin_state
+    result.state = <void *>self
+    result.type = self.plugin_name
+    cpython.Py_INCREF(self)
+    return result
+
+
+cdef class AuthMetadataContext:
+
+  def __cinit__(self):
+    self.context.service_url = NULL
+    self.context.method_name = NULL
+
+  @property
+  def service_url(self):
+    return self.context.service_url
+
+  @property
+  def method_name(self):
+    return self.context.method_name
+
+
+cdef void plugin_get_metadata(
+    void *state, grpc.grpc_auth_metadata_context context,
+    grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
+  def python_callback(
+      records.Metadata metadata, grpc.grpc_status_code status,
+      const char *error_details):
+    cb(user_data, metadata.c_metadata_array.metadata,
+       metadata.c_metadata_array.count, status, error_details)
+  cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state
+  cdef AuthMetadataContext cy_context = AuthMetadataContext()
+  cy_context.context = context
+  self.plugin_callback(cy_context, python_callback)
+
+cdef void plugin_destroy_c_plugin_state(void *state):
+  cpython.Py_DECREF(<CredentialsMetadataPlugin>state)
+
 def channel_credentials_google_default():
   cdef ChannelCredentials credentials = ChannelCredentials();
   credentials.c_credentials = grpc.grpc_google_default_credentials_create()
   return credentials
 
 def channel_credentials_ssl(pem_root_certificates,
-                           records.SslPemKeyCertPair ssl_pem_key_cert_pair):
+                            records.SslPemKeyCertPair ssl_pem_key_cert_pair):
   if pem_root_certificates is None:
     pass
   elif isinstance(pem_root_certificates, bytes):
@@ -104,6 +167,7 @@ def channel_credentials_ssl(pem_root_certificates,
   else:
     credentials.c_credentials = grpc.grpc_ssl_credentials_create(
       c_pem_root_certificates, NULL, NULL)
+  return credentials
 
 def channel_credentials_composite(
     ChannelCredentials credentials_1 not None,
@@ -135,7 +199,6 @@ def call_credentials_google_compute_engine():
       grpc.grpc_google_compute_engine_credentials_create(NULL))
   return credentials
 
-#TODO rename to something like client_credentials_service_account_jwt_access.
 def call_credentials_service_account_jwt_access(
     json_key, records.Timespec token_lifetime not None):
   if isinstance(json_key, bytes):
@@ -184,14 +247,25 @@ def call_credentials_google_iam(authorization_token, authority_selector):
   credentials.references.append(authority_selector)
   return credentials
 
+def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
+  cdef CallCredentials credentials = CallCredentials()
+  credentials.c_credentials = (
+      grpc.grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(),
+                                                        NULL))
+  # TODO(atash): the following held reference is *probably* never necessary
+  credentials.references.append(plugin)
+  return credentials
+
 def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
                            bint force_client_auth):
+  cdef char *c_pem_root_certs = NULL
   if pem_root_certs is None:
     pass
   elif isinstance(pem_root_certs, bytes):
-    pass
+    c_pem_root_certs = pem_root_certs
   elif isinstance(pem_root_certs, basestring):
     pem_root_certs = pem_root_certs.encode()
+    c_pem_root_certs = pem_root_certs
   else:
     raise TypeError("expected pem_root_certs to be str or bytes")
   pem_key_cert_pairs = list(pem_key_cert_pairs)
@@ -212,7 +286,7 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
     credentials.c_ssl_pem_key_cert_pairs[i] = (
         (<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
   credentials.c_credentials = grpc.grpc_ssl_server_credentials_create(
-      pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
+      c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
       credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL)
   return credentials
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
index 36aea81a6c0d8de77d6a187426d9b096c76f7638..10c948cd0ac8e32c20080ac2ff168ea93f38ebe4 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -132,6 +132,20 @@ cdef extern from "grpc/byte_buffer.h":
 
 cdef extern from "grpc/grpc.h":
 
+  const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
+  const char *GRPC_ARG_ENABLE_CENSUS
+  const char *GRPC_ARG_MAX_CONCURRENT_STREAMS
+  const char *GRPC_ARG_MAX_MESSAGE_LENGTH
+  const char *GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
+  const char *GRPC_ARG_DEFAULT_AUTHORITY
+  const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
+  const char *GRPC_ARG_SECONDARY_USER_AGENT_STRING
+  const char *GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+
+  const int GRPC_WRITE_BUFFER_HINT
+  const int GRPC_WRITE_NO_COMPRESS
+  const int GRPC_WRITE_USED_MASK
+
   ctypedef struct grpc_completion_queue:
     # We don't care about the internals (and in fact don't know them)
     pass
@@ -149,9 +163,9 @@ cdef extern from "grpc/grpc.h":
     pass
 
   ctypedef enum grpc_arg_type:
-    grpc_arg_string "GRPC_ARG_STRING"
-    grpc_arg_integer "GRPC_ARG_INTEGER"
-    grpc_arg_pointer "GRPC_ARG_POINTER"
+    GRPC_ARG_STRING
+    GRPC_ARG_INTEGER
+    GRPC_ARG_POINTER
 
   ctypedef struct grpc_arg_value_pointer:
     void *address "p"
@@ -185,6 +199,13 @@ cdef extern from "grpc/grpc.h":
     GRPC_CALL_ERROR_INVALID_FLAGS
     GRPC_CALL_ERROR_INVALID_METADATA
 
+  ctypedef enum grpc_connectivity_state:
+    GRPC_CHANNEL_IDLE
+    GRPC_CHANNEL_CONNECTING
+    GRPC_CHANNEL_READY
+    GRPC_CHANNEL_TRANSIENT_FAILURE
+    GRPC_CHANNEL_FATAL_FAILURE
+
   ctypedef struct grpc_metadata:
     const char *key
     const char *value
@@ -279,9 +300,9 @@ cdef extern from "grpc/grpc.h":
                                                grpc_status_code status,
                                                const char *description,
                                                void *reserved)
+  char *grpc_call_get_peer(grpc_call *call)
   void grpc_call_destroy(grpc_call *call)
 
-
   grpc_channel *grpc_insecure_channel_create(const char *target,
                                              const grpc_channel_args *args,
                                              void *reserved)
@@ -291,6 +312,12 @@ cdef extern from "grpc/grpc.h":
                                       grpc_completion_queue *completion_queue,
                                       const char *method, const char *host,
                                       gpr_timespec deadline, void *reserved)
+  grpc_connectivity_state grpc_channel_check_connectivity_state(
+      grpc_channel *channel, int try_to_connect)
+  void grpc_channel_watch_connectivity_state(
+      grpc_channel *channel, grpc_connectivity_state last_observed_state,
+      gpr_timespec deadline, grpc_completion_queue *cq, void *tag)
+  char *grpc_channel_get_target(grpc_channel *channel)
   void grpc_channel_destroy(grpc_channel *channel)
 
   grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved)
@@ -367,3 +394,27 @@ cdef extern from "grpc/grpc_security.h":
 
   grpc_call_error grpc_call_set_credentials(grpc_call *call,
                                             grpc_call_credentials *creds)
+
+  ctypedef struct grpc_auth_context:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  ctypedef struct grpc_auth_metadata_context:
+    const char *service_url
+    const char *method_name
+    const grpc_auth_context *channel_auth_context
+
+  ctypedef void (*grpc_credentials_plugin_metadata_cb)(
+      void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
+      grpc_status_code status, const char *error_details)
+
+  ctypedef struct grpc_metadata_credentials_plugin:
+    void (*get_metadata)(
+        void *state, grpc_auth_metadata_context context,
+        grpc_credentials_plugin_metadata_cb cb, void *user_data)
+    void (*destroy)(void *state)
+    void *state
+    const char *type
+
+  grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
+      grpc_metadata_credentials_plugin plugin, void *reserved)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
index 9ee487882aa062a063183a8d050bc93e488f0797..4c844e4cb6cd8be385a1ff82f168ff63fdb93464 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
@@ -66,6 +66,7 @@ cdef class Event:
   cdef readonly call.Call operation_call
 
   # For Server.request_call
+  cdef readonly bint is_new_request
   cdef readonly CallDetails request_call_details
   cdef readonly Metadata request_metadata
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
index 8edee09c2d43ed1ab16c672a7203abd7bc3ef097..79a7f8f563b8812c0f886c63689f21a328563c40 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
@@ -32,6 +32,30 @@ from grpc._cython._cygrpc cimport call
 from grpc._cython._cygrpc cimport server
 
 
+class ConnectivityState:
+  idle = grpc.GRPC_CHANNEL_IDLE
+  connecting = grpc.GRPC_CHANNEL_CONNECTING
+  ready = grpc.GRPC_CHANNEL_READY
+  transient_failure = grpc.GRPC_CHANNEL_TRANSIENT_FAILURE
+  fatal_failure = grpc.GRPC_CHANNEL_FATAL_FAILURE
+
+
+class ChannelArgKey:
+  enable_census = grpc.GRPC_ARG_ENABLE_CENSUS
+  max_concurrent_streams = grpc.GRPC_ARG_MAX_CONCURRENT_STREAMS
+  max_message_length = grpc.GRPC_ARG_MAX_MESSAGE_LENGTH
+  http2_initial_sequence_number = grpc.GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
+  default_authority = grpc.GRPC_ARG_DEFAULT_AUTHORITY
+  primary_user_agent_string = grpc.GRPC_ARG_PRIMARY_USER_AGENT_STRING
+  secondary_user_agent_string = grpc.GRPC_ARG_SECONDARY_USER_AGENT_STRING
+  ssl_target_name_override = grpc.GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+
+
+class WriteFlag:
+  buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT
+  no_compress = grpc.GRPC_WRITE_NO_COMPRESS
+
+
 class StatusCode:
   ok = grpc.GRPC_STATUS_OK
   cancelled = grpc.GRPC_STATUS_CANCELLED
@@ -88,7 +112,10 @@ cdef class Timespec:
   def __cinit__(self, time):
     if time is None:
       self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
-    elif isinstance(time, float):
+      return
+    if isinstance(time, int):
+      time = float(time)
+    if isinstance(time, float):
       if time == float("+inf"):
         self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME)
       elif time == float("-inf"):
@@ -97,8 +124,11 @@ cdef class Timespec:
         self.c_time.seconds = time
         self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
         self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME
+    elif isinstance(time, Timespec):
+      self.c_time = (<Timespec>time).c_time
     else:
-      raise TypeError("expected time to be float")
+      raise TypeError("expected time to be float, int, or Timespec, not {}"
+                          .format(type(time)))
 
   @property
   def seconds(self):
@@ -166,6 +196,7 @@ cdef class Event:
                 object tag, call.Call operation_call,
                 CallDetails request_call_details,
                 Metadata request_metadata,
+                bint is_new_request,
                 Operations batch_operations):
     self.type = type
     self.success = success
@@ -174,6 +205,7 @@ cdef class Event:
     self.request_call_details = request_call_details
     self.request_metadata = request_metadata
     self.batch_operations = batch_operations
+    self.is_new_request = is_new_request
 
 
 cdef class ByteBuffer:
@@ -186,8 +218,14 @@ cdef class ByteBuffer:
       pass
     elif isinstance(data, basestring):
       data = data.encode()
+    elif isinstance(data, ByteBuffer):
+      data = (<ByteBuffer>data).bytes()
+      if data is None:
+        self.c_byte_buffer = NULL
+        return
     else:
-      raise TypeError("expected value to be of type str or bytes")
+      raise TypeError("expected value to be of type str, bytes, or "
+                      "ByteBuffer, not {}".format(type(data)))
 
     cdef char *c_data = data
     data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
@@ -409,12 +447,22 @@ cdef class Operation:
   def type(self):
     return self.c_op.type
 
+  @property
+  def has_status(self):
+    return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+
   @property
   def received_message(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
       raise TypeError("self must be an operation receiving a message")
     return self._received_message
 
+  @property
+  def received_message_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
+      return None
+    return self._received_message
+
   @property
   def received_metadata(self):
     if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
@@ -422,12 +470,25 @@ cdef class Operation:
       raise TypeError("self must be an operation receiving metadata")
     return self._received_metadata
 
+  @property
+  def received_metadata_or_none(self):
+    if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
+        self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
+      return None
+    return self._received_metadata
+
   @property
   def received_status_code(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
       raise TypeError("self must be an operation receiving a status code")
     return self._received_status_code
 
+  @property
+  def received_status_code_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      return None
+    return self._received_status_code
+
   @property
   def received_status_details(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
@@ -437,6 +498,15 @@ cdef class Operation:
     else:
       return None
 
+  @property
+  def received_status_details_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      return None
+    if self._received_status_details:
+      return self._received_status_details
+    else:
+      return None
+
   @property
   def received_cancelled(self):
     if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
@@ -444,6 +514,12 @@ cdef class Operation:
                       "information")
     return False if self._received_cancelled == 0 else True
 
+  @property
+  def received_cancelled_or_none(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
+      return None
+    return False if self._received_cancelled == 0 else True
+
   def __dealloc__(self):
     # We *almost* don't need to do anything; most of the objects are handled by
     # Python. The remaining one(s) are primitive fields filled in by GRPC core.
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
index 6d20d2910c73bef8c2be77fe3991781523426a03..46df8bf77f8d1228f842b67fdbe68d8fbd12ab4c 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
@@ -132,7 +132,7 @@ cdef class Server:
 
   def cancel_all_calls(self):
     if not self.is_shutting_down:
-      raise ValueError("the server must be shutting down to cancel all calls")
+      raise RuntimeError("the server must be shutting down to cancel all calls")
     elif self.is_shutdown:
       return
     else:
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index b20dda8a95875dcfdf66687ae52a00967f7037fb..16ec12dac0d9510f50f22aac8242a88206acf93b 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -44,6 +44,9 @@ from grpc._cython._cygrpc import completion_queue
 from grpc._cython._cygrpc import records
 from grpc._cython._cygrpc import server
 
+ConnectivityState = records.ConnectivityState
+ChannelArgKey = records.ChannelArgKey
+WriteFlag = records.WriteFlag
 StatusCode = records.StatusCode
 CallError = records.CallError
 CompletionType = records.CompletionType
@@ -73,6 +76,8 @@ Operations = records.Operations
 CallCredentials = credentials.CallCredentials
 ChannelCredentials = credentials.ChannelCredentials
 ServerCredentials = credentials.ServerCredentials
+CredentialsMetadataPlugin = credentials.CredentialsMetadataPlugin
+AuthMetadataContext = credentials.AuthMetadataContext
 
 channel_credentials_google_default = (
     credentials.channel_credentials_google_default)
@@ -88,6 +93,7 @@ call_credentials_jwt_access = (
 call_credentials_refresh_token = (
     credentials.call_credentials_google_refresh_token)
 call_credentials_google_iam = credentials.call_credentials_google_iam
+call_credentials_metadata_plugin = credentials.call_credentials_metadata_plugin
 server_credentials_ssl = credentials.server_credentials_ssl
 
 CompletionQueue = completion_queue.CompletionQueue
diff --git a/src/python/grpcio/grpc/_links/invocation.py b/src/python/grpcio/grpc/_links/invocation.py
index 67ef86a1769cfcac2a02cd52ac6520eb81ac4554..5ca0a0ee606810dd3ec3070e323a989f61ff022b 100644
--- a/src/python/grpcio/grpc/_links/invocation.py
+++ b/src/python/grpcio/grpc/_links/invocation.py
@@ -182,15 +182,15 @@ class _Kernel(object):
 
   def _on_finish_event(self, operation_id, event, rpc_state):
     _no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states)
-    if event.status.code is _intermediary_low.Code.OK:
+    if event.status.code == _intermediary_low.Code.OK:
       termination = links.Ticket.Termination.COMPLETION
-    elif event.status.code is _intermediary_low.Code.CANCELLED:
+    elif event.status.code == _intermediary_low.Code.CANCELLED:
       termination = links.Ticket.Termination.CANCELLATION
-    elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+    elif event.status.code == _intermediary_low.Code.DEADLINE_EXCEEDED:
       termination = links.Ticket.Termination.EXPIRATION
-    elif event.status.code is _intermediary_low.Code.UNIMPLEMENTED:
+    elif event.status.code == _intermediary_low.Code.UNIMPLEMENTED:
       termination = links.Ticket.Termination.REMOTE_FAILURE
-    elif event.status.code is _intermediary_low.Code.UNKNOWN:
+    elif event.status.code == _intermediary_low.Code.UNKNOWN:
       termination = links.Ticket.Termination.LOCAL_FAILURE
     else:
       termination = links.Ticket.Termination.TRANSMISSION_FAILURE
@@ -262,7 +262,7 @@ class _Kernel(object):
         self._channel, self._completion_queue, '/%s/%s' % (group, method),
         self._host, time.time() + timeout)
     if options is not None and options.credentials is not None:
-      call.set_credentials(options.credentials._intermediary_low_credentials)
+      call.set_credentials(options.credentials._low_credentials)
     if transformed_initial_metadata is not None:
       for metadata_key, metadata_value in transformed_initial_metadata:
         call.add_metadata(metadata_key, metadata_value)
diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index f56df84007d899beaaf20a80218bd6e2d7af3a6e..01edee6896186defca95aa10918dd5d1b5cfa293 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -254,12 +254,12 @@ class _Kernel(object):
     rpc_state = self._rpc_states[call]
     _no_longer_due(_FINISH, rpc_state, call, self._rpc_states)
     code = event.status.code
-    if code is _intermediary_low.Code.OK:
+    if code == _intermediary_low.Code.OK:
       return
 
-    if code is _intermediary_low.Code.CANCELLED:
+    if code == _intermediary_low.Code.CANCELLED:
       termination = links.Ticket.Termination.CANCELLATION
-    elif code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+    elif code == _intermediary_low.Code.DEADLINE_EXCEEDED:
       termination = links.Ticket.Termination.EXPIRATION
     else:
       termination = links.Ticket.Termination.TRANSMISSION_FAILURE
diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py
index 05b954d1860030557ccffe3f0c5a562c76f87534..2b520cc7e5f0c9d46d2ad59b476b3b8fa40f0108 100644
--- a/src/python/grpcio/grpc/beta/_server.py
+++ b/src/python/grpcio/grpc/beta/_server.py
@@ -44,6 +44,12 @@ _DEFAULT_TIMEOUT = 300
 _MAXIMUM_TIMEOUT = 24 * 60 * 60
 
 
+def _set_event():
+  event = threading.Event()
+  event.set()
+  return event
+
+
 class _GRPCServicer(base.Servicer):
 
   def __init__(self, delegate):
@@ -61,86 +67,143 @@ class _GRPCServicer(base.Servicer):
         raise
 
 
-def _disassemble(grpc_link, end_link, pool, event, grace):
-  grpc_link.begin_stop()
-  end_link.stop(grace).wait()
-  grpc_link.end_stop()
-  grpc_link.join_link(utilities.NULL_LINK)
-  end_link.join_link(utilities.NULL_LINK)
-  if pool is not None:
-    pool.shutdown(wait=True)
-  event.set()
+class _Server(interfaces.Server):
 
+  def __init__(
+      self, implementations, multi_implementation, pool, pool_size,
+      default_timeout, maximum_timeout, grpc_link):
+    self._lock = threading.Lock()
+    self._implementations = implementations
+    self._multi_implementation = multi_implementation
+    self._customer_pool = pool
+    self._pool_size = pool_size
+    self._default_timeout = default_timeout
+    self._maximum_timeout = maximum_timeout
+    self._grpc_link = grpc_link
 
-class Server(interfaces.Server):
+    self._end_link = None
+    self._stop_events = None
+    self._pool = None
 
-  def __init__(self, grpc_link, end_link, pool):
-    self._grpc_link = grpc_link
-    self._end_link = end_link
-    self._pool = pool
+  def _start(self):
+    with self._lock:
+      if self._end_link is not None:
+        raise ValueError('Cannot start already-started server!')
+
+      if self._customer_pool is None:
+        self._pool = logging_pool.pool(self._pool_size)
+        assembly_pool = self._pool
+      else:
+        assembly_pool = self._customer_pool
+
+      servicer = _GRPCServicer(
+          _crust_implementations.servicer(
+              self._implementations, self._multi_implementation, assembly_pool))
+
+      self._end_link = _core_implementations.service_end_link(
+          servicer, self._default_timeout, self._maximum_timeout)
+
+      self._grpc_link.join_link(self._end_link)
+      self._end_link.join_link(self._grpc_link)
+      self._grpc_link.start()
+      self._end_link.start()
+
+  def _dissociate_links_and_shut_down_pool(self):
+    self._grpc_link.end_stop()
+    self._grpc_link.join_link(utilities.NULL_LINK)
+    self._end_link.join_link(utilities.NULL_LINK)
+    self._end_link = None
+    if self._pool is not None:
+      self._pool.shutdown(wait=True)
+    self._pool = None
+
+  def _stop_stopping(self):
+    self._dissociate_links_and_shut_down_pool()
+    for stop_event in self._stop_events:
+      stop_event.set()
+    self._stop_events = None
+
+  def _stop_started(self):
+    self._grpc_link.begin_stop()
+    self._end_link.stop(0).wait()
+    self._dissociate_links_and_shut_down_pool()
+
+  def _foreign_thread_stop(self, end_stop_event, stop_events):
+    end_stop_event.wait()
+    with self._lock:
+      if self._stop_events is stop_events:
+        self._stop_stopping()
+
+  def _schedule_stop(self, grace):
+    with self._lock:
+      if self._end_link is None:
+        return _set_event()
+      server_stop_event = threading.Event()
+      if self._stop_events is None:
+        self._stop_events = [server_stop_event]
+        self._grpc_link.begin_stop()
+      else:
+        self._stop_events.append(server_stop_event)
+      end_stop_event = self._end_link.stop(grace)
+      end_stop_thread = threading.Thread(
+          target=self._foreign_thread_stop,
+          args=(end_stop_event, self._stop_events))
+      end_stop_thread.start()
+      return server_stop_event
+
+  def _stop_now(self):
+    with self._lock:
+      if self._end_link is not None:
+        if self._stop_events is None:
+          self._stop_started()
+        else:
+          self._stop_stopping()
 
   def add_insecure_port(self, address):
-    return self._grpc_link.add_port(address, None)
+    with self._lock:
+      if self._end_link is None:
+        return self._grpc_link.add_port(address, None)
+      else:
+        raise ValueError('Can\'t add port to serving server!')
 
   def add_secure_port(self, address, server_credentials):
-    return self._grpc_link.add_port(
-        address, server_credentials._intermediary_low_credentials)  # pylint: disable=protected-access
-
-  def _start(self):
-    self._grpc_link.join_link(self._end_link)
-    self._end_link.join_link(self._grpc_link)
-    self._grpc_link.start()
-    self._end_link.start()
-
-  def _stop(self, grace):
-    stop_event = threading.Event()
-    if 0 < grace:
-      disassembly_thread = threading.Thread(
-          target=_disassemble,
-          args=(
-              self._grpc_link, self._end_link, self._pool, stop_event, grace,))
-      disassembly_thread.start()
-      return stop_event
-    else:
-      _disassemble(self._grpc_link, self._end_link, self._pool, stop_event, 0)
-      return stop_event
+    with self._lock:
+      if self._end_link is None:
+        return self._grpc_link.add_port(
+            address, server_credentials._low_credentials)  # pylint: disable=protected-access
+      else:
+        raise ValueError('Can\'t add port to serving server!')
 
   def start(self):
     self._start()
 
   def stop(self, grace):
-    return self._stop(grace)
+    if 0 < grace:
+      return self._schedule_stop(grace)
+    else:
+      self._stop_now()
+      return _set_event()
 
   def __enter__(self):
     self._start()
     return self
 
   def __exit__(self, exc_type, exc_val, exc_tb):
-    self._stop(0).wait()
+    self._stop_now()
     return False
 
+  def __del__(self):
+    self._stop_now()
+
 
 def server(
     implementations, multi_implementation, request_deserializers,
     response_serializers, thread_pool, thread_pool_size, default_timeout,
     maximum_timeout):
-  if thread_pool is None:
-    service_thread_pool = logging_pool.pool(
-        _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
-    assembly_thread_pool = service_thread_pool
-  else:
-    service_thread_pool = thread_pool
-    assembly_thread_pool = None
-
-  servicer = _GRPCServicer(
-      _crust_implementations.servicer(
-          implementations, multi_implementation, service_thread_pool))
-
   grpc_link = service.service_link(request_deserializers, response_serializers)
-
-  end_link = _core_implementations.service_end_link(
-      servicer,
+  return _Server(
+      implementations, multi_implementation, thread_pool,
+      _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size,
       _DEFAULT_TIMEOUT if default_timeout is None else default_timeout,
-      _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout)
-
-  return Server(grpc_link, end_link, assembly_thread_pool)
+      _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout,
+      grpc_link)
diff --git a/src/python/grpcio/grpc/beta/_stub.py b/src/python/grpcio/grpc/beta/_stub.py
index 11dab889cd0f34e8196a885374c4aa1d94f0130f..2af019309afc412077089c21986f3397e690218c 100644
--- a/src/python/grpcio/grpc/beta/_stub.py
+++ b/src/python/grpcio/grpc/beta/_stub.py
@@ -42,76 +42,114 @@ _DEFAULT_POOL_SIZE = 6
 
 class _AutoIntermediary(object):
 
-  def __init__(self, delegate, on_deletion):
+  def __init__(self, up, down, delegate):
+    self._lock = threading.Lock()
+    self._up = up
+    self._down = down
+    self._in_context = False
     self._delegate = delegate
-    self._on_deletion = on_deletion
 
   def __getattr__(self, attr):
-    return getattr(self._delegate, attr)
+    with self._lock:
+      if self._delegate is None:
+        raise AttributeError('No useful attributes out of context!')
+      else:
+        return getattr(self._delegate, attr)
 
   def __enter__(self):
-    return self
+    with self._lock:
+      if self._in_context:
+        raise ValueError('Already in context!')
+      elif self._delegate is None:
+        self._delegate = self._up()
+      self._in_context = True
+      return self
 
   def __exit__(self, exc_type, exc_val, exc_tb):
-    return False
+    with self._lock:
+      if not self._in_context:
+        raise ValueError('Not in context!')
+      self._down()
+      self._in_context = False
+      self._delegate = None
+      return False
 
   def __del__(self):
-    self._on_deletion()
+    with self._lock:
+      if self._delegate is not None:
+        self._down()
+        self._delegate = None
+
+
+class _StubAssemblyManager(object):
+
+  def __init__(
+      self, thread_pool, thread_pool_size, end_link, grpc_link, stub_creator):
+    self._thread_pool = thread_pool
+    self._pool_size = thread_pool_size
+    self._end_link = end_link
+    self._grpc_link = grpc_link
+    self._stub_creator = stub_creator
+    self._own_pool = None
+
+  def up(self):
+    if self._thread_pool is None:
+      self._own_pool = logging_pool.pool(
+          _DEFAULT_POOL_SIZE if self._pool_size is None else self._pool_size)
+      assembly_pool = self._own_pool
+    else:
+      assembly_pool = self._thread_pool
+    self._end_link.join_link(self._grpc_link)
+    self._grpc_link.join_link(self._end_link)
+    self._end_link.start()
+    self._grpc_link.start()
+    return self._stub_creator(self._end_link, assembly_pool)
+
+  def down(self):
+    self._end_link.stop(0).wait()
+    self._grpc_link.stop()
+    self._end_link.join_link(utilities.NULL_LINK)
+    self._grpc_link.join_link(utilities.NULL_LINK)
+    if self._own_pool is not None:
+      self._own_pool.shutdown(wait=True)
+      self._own_pool = None
 
 
 def _assemble(
     channel, host, metadata_transformer, request_serializers,
-    response_deserializers, thread_pool, thread_pool_size):
+    response_deserializers, thread_pool, thread_pool_size, stub_creator):
   end_link = _core_implementations.invocation_end_link()
   grpc_link = invocation.invocation_link(
       channel, host, metadata_transformer, request_serializers,
       response_deserializers)
-  if thread_pool is None:
-    invocation_pool = logging_pool.pool(
-        _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
-    assembly_pool = invocation_pool
-  else:
-    invocation_pool = thread_pool
-    assembly_pool = None
-  end_link.join_link(grpc_link)
-  grpc_link.join_link(end_link)
-  end_link.start()
-  grpc_link.start()
-  return end_link, grpc_link, invocation_pool, assembly_pool
-
-
-def _disassemble(end_link, grpc_link, pool):
-  end_link.stop(24 * 60 * 60).wait()
-  grpc_link.stop()
-  end_link.join_link(utilities.NULL_LINK)
-  grpc_link.join_link(utilities.NULL_LINK)
-  if pool is not None:
-    pool.shutdown(wait=True)
-
-
-def _wrap_assembly(stub, end_link, grpc_link, assembly_pool):
-  disassembly_thread = threading.Thread(
-      target=_disassemble, args=(end_link, grpc_link, assembly_pool))
-  return _AutoIntermediary(stub, disassembly_thread.start)
+  stub_assembly_manager = _StubAssemblyManager(
+      thread_pool, thread_pool_size, end_link, grpc_link, stub_creator)
+  stub = stub_assembly_manager.up()
+  return _AutoIntermediary(
+      stub_assembly_manager.up, stub_assembly_manager.down, stub)
+
+
+def _dynamic_stub_creator(service, cardinalities):
+  def create_dynamic_stub(end_link, invocation_pool):
+    return _crust_implementations.dynamic_stub(
+        end_link, service, cardinalities, invocation_pool)
+  return create_dynamic_stub
 
 
 def generic_stub(
     channel, host, metadata_transformer, request_serializers,
     response_deserializers, thread_pool, thread_pool_size):
-  end_link, grpc_link, invocation_pool, assembly_pool = _assemble(
+  return _assemble(
       channel, host, metadata_transformer, request_serializers,
-      response_deserializers, thread_pool, thread_pool_size)
-  stub = _crust_implementations.generic_stub(end_link, invocation_pool)
-  return _wrap_assembly(stub, end_link, grpc_link, assembly_pool)
+      response_deserializers, thread_pool, thread_pool_size,
+      _crust_implementations.generic_stub)
 
 
 def dynamic_stub(
     channel, host, service, cardinalities, metadata_transformer,
     request_serializers, response_deserializers, thread_pool,
     thread_pool_size):
-  end_link, grpc_link, invocation_pool, assembly_pool = _assemble(
+  return _assemble(
       channel, host, metadata_transformer, request_serializers,
-      response_deserializers, thread_pool, thread_pool_size)
-  stub = _crust_implementations.dynamic_stub(
-      end_link, service, cardinalities, invocation_pool)
-  return _wrap_assembly(stub, end_link, grpc_link, assembly_pool)
+      response_deserializers, thread_pool, thread_pool_size,
+      _dynamic_stub_creator(service, cardinalities))
diff --git a/src/python/grpcio/grpc/beta/implementations.py b/src/python/grpcio/grpc/beta/implementations.py
index c9d64ad35a06561a8df50b03c7fbfda3419a54d0..a0ca330d2c02bda4883a5643daaf08b1c0edf53d 100644
--- a/src/python/grpcio/grpc/beta/implementations.py
+++ b/src/python/grpcio/grpc/beta/implementations.py
@@ -36,6 +36,7 @@ import threading  # pylint: disable=unused-import
 
 # cardinality and face are referenced from specification in this module.
 from grpc._adapter import _intermediary_low
+from grpc._adapter import _low
 from grpc._adapter import _types
 from grpc.beta import _connectivity_channel
 from grpc.beta import _server
@@ -48,7 +49,7 @@ _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
     'Exception calling channel subscription callback!')
 
 
-class ClientCredentials(object):
+class ChannelCredentials(object):
   """A value encapsulating the data required to create a secure Channel.
 
   This class and its instances have no supported interface - it exists to define
@@ -56,13 +57,12 @@ class ClientCredentials(object):
   functions.
   """
 
-  def __init__(self, low_credentials, intermediary_low_credentials):
+  def __init__(self, low_credentials):
     self._low_credentials = low_credentials
-    self._intermediary_low_credentials = intermediary_low_credentials
 
 
-def ssl_client_credentials(root_certificates, private_key, certificate_chain):
-  """Creates a ClientCredentials for use with an SSL-enabled Channel.
+def ssl_channel_credentials(root_certificates, private_key, certificate_chain):
+  """Creates a ChannelCredentials for use with an SSL-enabled Channel.
 
   Args:
     root_certificates: The PEM-encoded root certificates or None to ask for
@@ -73,12 +73,73 @@ def ssl_client_credentials(root_certificates, private_key, certificate_chain):
       certificate chain should be used.
 
   Returns:
-    A ClientCredentials for use with an SSL-enabled Channel.
+    A ChannelCredentials for use with an SSL-enabled Channel.
   """
-  intermediary_low_credentials = _intermediary_low.ClientCredentials(
-      root_certificates, private_key, certificate_chain)
-  return ClientCredentials(
-      intermediary_low_credentials._internal, intermediary_low_credentials)  # pylint: disable=protected-access
+  return ChannelCredentials(_low.channel_credentials_ssl(
+      root_certificates, private_key, certificate_chain))
+
+
+class CallCredentials(object):
+  """A value encapsulating data asserting an identity over an *established*
+  channel. May be composed with ChannelCredentials to always assert identity for
+  every call over that channel.
+
+  This class and its instances have no supported interface - it exists to define
+  the type of its instances and its instances exist to be passed to other
+  functions.
+  """
+
+  def __init__(self, low_credentials):
+    self._low_credentials = low_credentials
+
+
+def metadata_call_credentials(metadata_plugin, name=None):
+  """Construct CallCredentials from an interfaces.GRPCAuthMetadataPlugin.
+
+  Args:
+    metadata_plugin: An interfaces.GRPCAuthMetadataPlugin to use in constructing
+      the CallCredentials object.
+
+  Returns:
+    A CallCredentials object for use in a GRPCCallOptions object.
+  """
+  if name is None:
+    name = metadata_plugin.__name__
+  return CallCredentials(
+      _low.call_credentials_metadata_plugin(metadata_plugin, name))
+
+def composite_call_credentials(call_credentials, additional_call_credentials):
+  """Compose two CallCredentials to make a new one.
+
+  Args:
+    call_credentials: A CallCredentials object.
+    additional_call_credentials: Another CallCredentials object to compose on
+      top of call_credentials.
+
+  Returns:
+    A CallCredentials object for use in a GRPCCallOptions object.
+  """
+  return CallCredentials(
+      _low.call_credentials_composite(
+          call_credentials._low_credentials,
+          additional_call_credentials._low_credentials))
+
+def composite_channel_credentials(channel_credentials,
+                                 additional_call_credentials):
+  """Compose ChannelCredentials on top of client credentials to make a new one.
+
+  Args:
+    channel_credentials: A ChannelCredentials object.
+    additional_call_credentials: A CallCredentials object to compose on
+      top of channel_credentials.
+
+  Returns:
+    A ChannelCredentials object for use in a GRPCCallOptions object.
+  """
+  return ChannelCredentials(
+      _low.channel_credentials_composite(
+          channel_credentials._low_credentials,
+          additional_call_credentials._low_credentials))
 
 
 class Channel(object):
@@ -135,19 +196,19 @@ def insecure_channel(host, port):
   return Channel(intermediary_low_channel._internal, intermediary_low_channel)  # pylint: disable=protected-access
 
 
-def secure_channel(host, port, client_credentials):
+def secure_channel(host, port, channel_credentials):
   """Creates a secure Channel to a remote host.
 
   Args:
     host: The name of the remote host to which to connect.
     port: The port of the remote host to which to connect.
-    client_credentials: A ClientCredentials.
+    channel_credentials: A ChannelCredentials.
 
   Returns:
     A secure Channel to the remote host through which RPCs may be conducted.
   """
   intermediary_low_channel = _intermediary_low.Channel(
-      '%s:%d' % (host, port), client_credentials._intermediary_low_credentials)
+      '%s:%d' % (host, port), channel_credentials._low_credentials)
   return Channel(intermediary_low_channel._internal, intermediary_low_channel)  # pylint: disable=protected-access
 
 
@@ -251,9 +312,8 @@ class ServerCredentials(object):
   functions.
   """
 
-  def __init__(self, low_credentials, intermediary_low_credentials):
+  def __init__(self, low_credentials):
     self._low_credentials = low_credentials
-    self._intermediary_low_credentials = intermediary_low_credentials
 
 
 def ssl_server_credentials(
@@ -282,11 +342,9 @@ def ssl_server_credentials(
     raise ValueError(
         'Illegal to require client auth without providing root certificates!')
   else:
-    intermediary_low_credentials = _intermediary_low.ServerCredentials(
+    return ServerCredentials(_low.server_credentials_ssl(
         root_certificates, private_key_certificate_chain_pairs,
-        require_client_auth)
-    return ServerCredentials(
-        intermediary_low_credentials._internal, intermediary_low_credentials)  # pylint: disable=protected-access
+        require_client_auth))
 
 
 class ServerOptions(object):
diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py
index d4ca56500ffd488c4856afe59e29096d7f479757..0663119163f2eadea3e2d34319da0ae2ce3b1ed5 100644
--- a/src/python/grpcio/grpc/beta/interfaces.py
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -100,14 +100,55 @@ def grpc_call_options(disable_compression=False, credentials=None):
     disable_compression: A boolean indicating whether or not compression should
       be disabled for the request object of the RPC. Only valid for
       request-unary RPCs.
-    credentials: Reserved for gRPC per-call credentials. The type for this does
-      not exist yet at the Python level.
+    credentials: A CallCredentials object to use for the invoked RPC.
   """
-  if credentials is not None:
-    raise ValueError('`credentials` is a reserved argument')
   return GRPCCallOptions(disable_compression, None, credentials)
 
 
+class GRPCAuthMetadataContext(object):
+  """Provides information to call credentials metadata plugins.
+
+  Attributes:
+    service_url: A string URL of the service being called into.
+    method_name: A string of the fully qualified method name being called.
+  """
+  __metaclass__ = abc.ABCMeta
+
+
+class GRPCAuthMetadataPluginCallback(object):
+  """Callback object received by a metadata plugin."""
+  __metaclass__ = abc.ABCMeta
+
+  def __call__(self, metadata, error):
+    """Inform the gRPC runtime of the metadata to construct a CallCredentials.
+
+    Args:
+      metadata: An iterable of 2-sequences (e.g. tuples) of metadata key/value
+        pairs.
+      error: An Exception to indicate error or None to indicate success.
+    """
+    raise NotImplementedError()
+
+
+class GRPCAuthMetadataPlugin(object):
+  """
+  """
+  __metaclass__ = abc.ABCMeta
+
+  def __call__(self, context, callback):
+    """Invoke the plugin.
+
+    Must not block. Need only be called by the gRPC runtime.
+
+    Args:
+      context: A GRPCAuthMetadataContext providing information on what the
+        plugin is being used for.
+      callback: A GRPCAuthMetadataPluginCallback to be invoked either
+        synchronously or asynchronously.
+    """
+    raise NotImplementedError()
+
+
 class GRPCServicerContext(object):
   """Exposes gRPC-specific options and behaviors to code servicing RPCs."""
   __metaclass__ = abc.ABCMeta
diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py
index 8e07d9061e017a1d6dab8f85d833c4be9cde89a6..9c615672aa71ee843f976cce15b97f68012bb6e1 100644
--- a/src/python/grpcio/grpc/framework/core/_end.py
+++ b/src/python/grpcio/grpc/framework/core/_end.py
@@ -85,35 +85,6 @@ def _future_shutdown(lock, cycle, event):
   return in_future
 
 
-def _termination_action(lock, stats, operation_id, cycle):
-  """Constructs the termination action for a single operation.
-
-  Args:
-    lock: A lock to hold during the termination action.
-    stats: A mapping from base.Outcome.Kind values to integers to increment
-      with the outcome kind given to the termination action.
-    operation_id: The operation ID for the termination action.
-    cycle: A _Cycle value to be updated during the termination action.
-
-  Returns:
-    A callable that takes an operation outcome kind as its sole parameter and
-      that should be used as the termination action for the operation
-      associated with the given operation ID.
-  """
-  def termination_action(outcome_kind):
-    with lock:
-      stats[outcome_kind] += 1
-      cycle.operations.pop(operation_id, None)
-      if not cycle.operations:
-        for action in cycle.idle_actions:
-          cycle.pool.submit(action)
-        cycle.idle_actions = []
-        if cycle.grace:
-          _cancel_futures(cycle.futures)
-          cycle.pool.shutdown(wait=False)
-  return termination_action
-
-
 class _End(End):
   """An End implementation."""
 
@@ -133,6 +104,31 @@ class _End(End):
 
     self._cycle = None
 
+  def _termination_action(self, operation_id):
+    """Constructs the termination action for a single operation.
+
+    Args:
+      operation_id: The operation ID for the termination action.
+
+    Returns:
+      A callable that takes an operation outcome kind as its sole parameter and
+        that should be used as the termination action for the operation
+        associated with the given operation ID.
+    """
+    def termination_action(outcome_kind):
+      with self._lock:
+        self._stats[outcome_kind] += 1
+        self._cycle.operations.pop(operation_id, None)
+        if not self._cycle.operations:
+          for action in self._cycle.idle_actions:
+            self._cycle.pool.submit(action)
+          self._cycle.idle_actions = []
+          if self._cycle.grace:
+            _cancel_futures(self._cycle.futures)
+            self._cycle.pool.shutdown(wait=False)
+            self._cycle = None
+    return termination_action
+
   def start(self):
     """See base.End.start for specification."""
     with self._lock:
@@ -174,8 +170,7 @@ class _End(End):
     with self._lock:
       if self._cycle is None or self._cycle.grace:
         raise ValueError('Can\'t operate on stopped or stopping End!')
-      termination_action = _termination_action(
-          self._lock, self._stats, operation_id, self._cycle)
+      termination_action = self._termination_action(operation_id)
       operation = _operation.invocation_operate(
           operation_id, group, method, subscription, timeout, protocol_options,
           initial_metadata, payload, completion, self._mate.accept_ticket,
@@ -208,8 +203,7 @@ class _End(End):
         if operation is not None:
           operation.handle_ticket(ticket)
         elif self._servicer_package is not None and not self._cycle.grace:
-          termination_action = _termination_action(
-              self._lock, self._stats, ticket.operation_id, self._cycle)
+          termination_action = self._termination_action(ticket.operation_id)
           operation = _operation.service_operate(
               self._servicer_package, ticket, self._mate.accept_ticket,
               termination_action, self._cycle.pool)
diff --git a/src/python/grpcio/requirements.txt b/src/python/grpcio/requirements.txt
index ee8568120b76dd6fe7ea1eae2349aeed3a6667aa..06516ee0d7bda76b504058d5cc7756ef48c42aa1 100644
--- a/src/python/grpcio/requirements.txt
+++ b/src/python/grpcio/requirements.txt
@@ -1,3 +1,4 @@
 enum34>=1.0.4
 futures>=2.2.0
 cython>=0.23
+coverage>=4.0
diff --git a/src/python/grpcio/setup.cfg b/src/python/grpcio/setup.cfg
index 8f6961363204a5e6d56afae5c1ff67cb8f5a3077..52b6b50900716c3c29ab17d5ef5c54befcba4c4c 100644
--- a/src/python/grpcio/setup.cfg
+++ b/src/python/grpcio/setup.cfg
@@ -1,2 +1,8 @@
+[coverage:run]
+plugins = Cython.Coverage
+
 [build_ext]
 inplace=1
+
+[build_proto_modules]
+exclude=.*protoc_plugin/protoc_plugin_test\.proto$
diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py
index ec68eb67555c5c9b530f9d0f0a9e7476e17b6f92..a948ca1fac6d819cb7ebc5d38ff0bb3f2aa7a63f 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -43,27 +43,23 @@ os.chdir(os.path.dirname(os.path.abspath(__file__)))
 # Break import-style to ensure we can actually find our commands module.
 import commands
 
-# Use environment variables to determine whether or not the Cython extension
-# should *use* Cython or use the generated C files. Note that this requires the
-# C files to have been generated by building first *with* Cython support.
-_BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
-
-_C_EXTENSION_SOURCES = (
-    'grpc/_adapter/_c/module.c',
-    'grpc/_adapter/_c/types.c',
-    'grpc/_adapter/_c/utility.c',
-    'grpc/_adapter/_c/types/call_credentials.c',
-    'grpc/_adapter/_c/types/channel_credentials.c',
-    'grpc/_adapter/_c/types/server_credentials.c',
-    'grpc/_adapter/_c/types/completion_queue.c',
-    'grpc/_adapter/_c/types/call.c',
-    'grpc/_adapter/_c/types/channel.c',
-    'grpc/_adapter/_c/types/server.c',
-)
+# Environment variable to determine whether or not the Cython extension should
+# *use* Cython or use the generated C files. Note that this requires the C files
+# to have been generated by building first *with* Cython support.
+BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+
+# Environment variable to determine whether or not to enable coverage analysis
+# in Cython modules.
+ENABLE_CYTHON_TRACING = os.environ.get(
+    'GRPC_PYTHON_ENABLE_CYTHON_TRACING', False)
+
+# Environment variable to determine whether or not to include the test files in
+# the installation.
+INSTALL_TESTS = os.environ.get('GRPC_PYTHON_INSTALL_TESTS', False)
 
-_CYTHON_EXTENSION_PACKAGE_NAMES = ()
+CYTHON_EXTENSION_PACKAGE_NAMES = ()
 
-_CYTHON_EXTENSION_MODULE_NAMES = (
+CYTHON_EXTENSION_MODULE_NAMES = (
     'grpc._cython.cygrpc',
     'grpc._cython._cygrpc.call',
     'grpc._cython._cygrpc.channel',
@@ -73,24 +69,16 @@ _CYTHON_EXTENSION_MODULE_NAMES = (
     'grpc._cython._cygrpc.server',
 )
 
-_EXTENSION_INCLUDE_DIRECTORIES = (
+EXTENSION_INCLUDE_DIRECTORIES = (
     '.',
 )
 
-_EXTENSION_LIBRARIES = (
+EXTENSION_LIBRARIES = (
     'grpc',
     'gpr',
 )
 if not "darwin" in sys.platform:
-    _EXTENSION_LIBRARIES += ('rt',)
-
-
-_C_EXTENSION_MODULE = _core.Extension(
-    'grpc._adapter._c', sources=list(_C_EXTENSION_SOURCES),
-    include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES),
-    libraries=list(_EXTENSION_LIBRARIES),
-)
-_EXTENSION_MODULES = [_C_EXTENSION_MODULE]
+    EXTENSION_LIBRARIES += ('rt',)
 
 
 def cython_extensions(package_names, module_names, include_dirs, libraries,
@@ -101,48 +89,89 @@ def cython_extensions(package_names, module_names, include_dirs, libraries,
   extensions = [
       _extension.Extension(
           name=module_name, sources=[module_file],
-          include_dirs=include_dirs, libraries=libraries
+          include_dirs=include_dirs, libraries=libraries,
+          define_macros=[('CYTHON_TRACE_NOGIL', 1)] if ENABLE_CYTHON_TRACING else []
       ) for (module_name, module_file) in zip(module_names, module_files)
   ]
   if build_with_cython:
     import Cython.Build
-    return Cython.Build.cythonize(extensions)
+    return Cython.Build.cythonize(
+        extensions,
+        compiler_directives={'linetrace': bool(ENABLE_CYTHON_TRACING)})
   else:
     return extensions
 
-_CYTHON_EXTENSION_MODULES = cython_extensions(
-    list(_CYTHON_EXTENSION_PACKAGE_NAMES), list(_CYTHON_EXTENSION_MODULE_NAMES),
-    list(_EXTENSION_INCLUDE_DIRECTORIES), list(_EXTENSION_LIBRARIES),
-    bool(_BUILD_WITH_CYTHON))
+CYTHON_EXTENSION_MODULES = cython_extensions(
+    list(CYTHON_EXTENSION_PACKAGE_NAMES), list(CYTHON_EXTENSION_MODULE_NAMES),
+    list(EXTENSION_INCLUDE_DIRECTORIES), list(EXTENSION_LIBRARIES),
+    bool(BUILD_WITH_CYTHON))
 
-_PACKAGES = setuptools.find_packages('.')
-
-_PACKAGE_DIRECTORIES = {
+PACKAGE_DIRECTORIES = {
     '': '.',
 }
 
-_INSTALL_REQUIRES = (
+INSTALL_REQUIRES = (
     'enum34>=1.0.4',
     'futures>=2.2.0',
 )
 
-_SETUP_REQUIRES = (
+SETUP_REQUIRES = (
     'sphinx>=1.3',
-) + _INSTALL_REQUIRES
+) + INSTALL_REQUIRES
 
-_COMMAND_CLASS = {
+COMMAND_CLASS = {
     'doc': commands.SphinxDocumentation,
+    'build_proto_modules': commands.BuildProtoModules,
     'build_project_metadata': commands.BuildProjectMetadata,
     'build_py': commands.BuildPy,
+    'gather': commands.Gather,
+    'run_interop': commands.RunInterop,
+}
+
+TEST_PACKAGE_DATA = {
+    'tests.interop': [
+        'credentials/ca.pem',
+        'credentials/server1.key',
+        'credentials/server1.pem',
+    ],
+    'tests.protoc_plugin': [
+        'protoc_plugin_test.proto',
+    ],
+    'tests.unit': [
+        'credentials/ca.pem',
+        'credentials/server1.key',
+        'credentials/server1.pem',
+    ],
 }
 
+TESTS_REQUIRE = (
+    'oauth2client>=1.4.7',
+    'protobuf==3.0.0a3',
+    'coverage>=4.0',
+) + INSTALL_REQUIRES
+
+TEST_SUITE = 'tests'
+TEST_LOADER = 'tests:Loader'
+TEST_RUNNER = 'tests:Runner'
+
+PACKAGE_DATA = {}
+if INSTALL_TESTS:
+  PACKAGE_DATA = dict(PACKAGE_DATA, **TEST_PACKAGE_DATA)
+  PACKAGES = setuptools.find_packages('.')
+else:
+  PACKAGES = setuptools.find_packages('.', exclude=['tests', 'tests.*'])
+
 setuptools.setup(
     name='grpcio',
-    version='0.11.0b1',
-    ext_modules=_EXTENSION_MODULES + _CYTHON_EXTENSION_MODULES,
-    packages=list(_PACKAGES),
-    package_dir=_PACKAGE_DIRECTORIES,
-    install_requires=_INSTALL_REQUIRES,
-    setup_requires=_SETUP_REQUIRES,
-    cmdclass=_COMMAND_CLASS
+    version='0.11.0b2',
+    ext_modules=CYTHON_EXTENSION_MODULES,
+    packages=list(PACKAGES),
+    package_dir=PACKAGE_DIRECTORIES,
+    install_requires=INSTALL_REQUIRES,
+    setup_requires=SETUP_REQUIRES,
+    cmdclass=COMMAND_CLASS,
+    tests_require=TESTS_REQUIRE,
+    test_suite=TEST_SUITE,
+    test_loader=TEST_LOADER,
+    test_runner=TEST_RUNNER,
 )
diff --git a/src/python/grpcio/grpc/_cython/adapter_low.py b/src/python/grpcio/tests/__init__.py
similarity index 50%
rename from src/python/grpcio/grpc/_cython/adapter_low.py
rename to src/python/grpcio/tests/__init__.py
index 4f24da330f5e2141cd324cd614f7d22f821169c4..b76b3985a192d275f2e2a99811d81fc1da6b3704 100644
--- a/src/python/grpcio/grpc/_cython/adapter_low.py
+++ b/src/python/grpcio/tests/__init__.py
@@ -27,76 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+from tests import _loader
+from tests import _runner
 
-# Adapter from grpc._cython.types to the surface expected by
-# grpc._adapter._intermediary_low.
-#
-# TODO(atash): Once this is plugged into grpc._adapter._intermediary_low, remove
-# both grpc._adapter._intermediary_low and this file. The fore and rear links in
-# grpc._adapter should be able to use grpc._cython.types directly.
-
-from grpc._adapter import _types as type_interfaces
-from grpc._cython import cygrpc
-
-
-class ClientCredentials(object):
-  def __init__(self):
-    raise NotImplementedError()
-
-  @staticmethod
-  def google_default():
-    raise NotImplementedError()
-
-  @staticmethod
-  def ssl():
-    raise NotImplementedError()
-
-  @staticmethod
-  def composite():
-    raise NotImplementedError()
-
-  @staticmethod
-  def compute_engine():
-    raise NotImplementedError()
-
-  @staticmethod
-  def jwt():
-    raise NotImplementedError()
-
-  @staticmethod
-  def refresh_token():
-    raise NotImplementedError()
-
-  @staticmethod
-  def iam():
-    raise NotImplementedError()
-
-
-class ServerCredentials(object):
-  def __init__(self):
-    raise NotImplementedError()
-
-  @staticmethod
-  def ssl():
-    raise NotImplementedError()
-
-
-class CompletionQueue(type_interfaces.CompletionQueue):
-  def __init__(self):
-    raise NotImplementedError()
-
-
-class Call(type_interfaces.Call):
-  def __init__(self):
-    raise NotImplementedError()
-
-
-class Channel(type_interfaces.Channel):
-  def __init__(self):
-    raise NotImplementedError()
-
-
-class Server(type_interfaces.Server):
-  def __init__(self):
-    raise NotImplementedError()
-
+Loader = _loader.Loader
+Runner = _runner.Runner
diff --git a/src/python/grpcio/tests/_loader.py b/src/python/grpcio/tests/_loader.py
new file mode 100644
index 0000000000000000000000000000000000000000..6992029b5e801c0bedf17c89f30c7a6b7c56d054
--- /dev/null
+++ b/src/python/grpcio/tests/_loader.py
@@ -0,0 +1,119 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import importlib
+import pkgutil
+import re
+import unittest
+
+import coverage
+
+TEST_MODULE_REGEX = r'^.*_test$'
+
+
+class Loader(object):
+  """Test loader for setuptools test suite support.
+
+  Attributes:
+    suite (unittest.TestSuite): All tests collected by the loader.
+    loader (unittest.TestLoader): Standard Python unittest loader to be ran per
+      module discovered.
+    module_matcher (re.RegexObject): A regular expression object to match
+      against module names and determine whether or not the discovered module
+      contributes to the test suite.
+  """
+
+  def __init__(self):
+    self.suite = unittest.TestSuite()
+    self.loader = unittest.TestLoader()
+    self.module_matcher = re.compile(TEST_MODULE_REGEX)
+
+  def loadTestsFromNames(self, names, module=None):
+    """Function mirroring TestLoader::loadTestsFromNames, as expected by
+    setuptools.setup argument `test_loader`."""
+    # ensure that we capture decorators and definitions (else our coverage
+    # measure unnecessarily suffers)
+    coverage_context = coverage.Coverage(data_suffix=True)
+    coverage_context.start()
+    modules = [importlib.import_module(name) for name in names]
+    for module in modules:
+      self.visit_module(module)
+    for module in modules:
+      try:
+        package_paths = module.__path__
+      except:
+        continue
+      self.walk_packages(package_paths)
+    coverage_context.stop()
+    coverage_context.save()
+    return self.suite
+
+  def walk_packages(self, package_paths):
+    """Walks over the packages, dispatching `visit_module` calls.
+
+    Args:
+      package_paths (list): A list of paths over which to walk through modules
+        along.
+    """
+    for importer, module_name, is_package in (
+        pkgutil.iter_modules(package_paths)):
+      module = importer.find_module(module_name).load_module(module_name)
+      self.visit_module(module)
+      if is_package:
+        self.walk_packages(module.__path__)
+
+  def visit_module(self, module):
+    """Visits the module, adding discovered tests to the test suite.
+
+    Args:
+      module (module): Module to match against self.module_matcher; if matched
+        it has its tests loaded via self.loader into self.suite.
+    """
+    if self.module_matcher.match(module.__name__):
+      module_suite = self.loader.loadTestsFromModule(module)
+      self.suite.addTest(module_suite)
+
+
+def iterate_suite_cases(suite):
+  """Generator over all unittest.TestCases in a unittest.TestSuite.
+
+  Args:
+    suite (unittest.TestSuite): Suite to iterate over in the generator.
+
+  Returns:
+    generator: A generator over all unittest.TestCases in `suite`.
+  """
+  for item in suite:
+    if isinstance(item, unittest.TestSuite):
+      for child_item in iterate_suite_cases(item):
+        yield child_item
+    elif isinstance(item, unittest.TestCase):
+      yield item
+    else:
+      raise ValueError('unexpected suite item of type {}'.format(type(item)))
diff --git a/src/python/grpcio/tests/_result.py b/src/python/grpcio/tests/_result.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a570f42792a1cbbaa2a988ea993761b638c2a6c
--- /dev/null
+++ b/src/python/grpcio/tests/_result.py
@@ -0,0 +1,451 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import cStringIO as StringIO
+import collections
+import itertools
+import traceback
+import unittest
+from xml.etree import ElementTree
+
+import coverage
+
+from tests import _loader
+
+
+class CaseResult(collections.namedtuple('CaseResult', [
+    'id', 'name', 'kind', 'stdout', 'stderr', 'skip_reason', 'traceback'])):
+  """A serializable result of a single test case.
+
+  Attributes:
+    id (object): Any serializable object used to denote the identity of this
+      test case.
+    name (str or None): A human-readable name of the test case.
+    kind (CaseResult.Kind): The kind of test result.
+    stdout (object or None): Output on stdout, or None if nothing was captured.
+    stderr (object or None): Output on stderr, or None if nothing was captured.
+    skip_reason (object or None): The reason the test was skipped. Must be
+      something if self.kind is CaseResult.Kind.SKIP, else None.
+    traceback (object or None): The traceback of the test. Must be something if
+      self.kind is CaseResult.Kind.{ERROR, FAILURE, EXPECTED_FAILURE}, else
+      None.
+  """
+
+  class Kind:
+    UNTESTED = 'untested'
+    RUNNING = 'running'
+    ERROR = 'error'
+    FAILURE = 'failure'
+    SUCCESS = 'success'
+    SKIP = 'skip'
+    EXPECTED_FAILURE = 'expected failure'
+    UNEXPECTED_SUCCESS = 'unexpected success'
+
+  def __new__(cls, id=None, name=None, kind=None, stdout=None, stderr=None,
+              skip_reason=None, traceback=None):
+    """Helper keyword constructor for the namedtuple.
+
+    See this class' attributes for information on the arguments."""
+    assert id is not None
+    assert name is None or isinstance(name, str)
+    if kind is CaseResult.Kind.UNTESTED:
+      pass
+    elif kind is CaseResult.Kind.RUNNING:
+      pass
+    elif kind is CaseResult.Kind.ERROR:
+      assert traceback is not None
+    elif kind is CaseResult.Kind.FAILURE:
+      assert traceback is not None
+    elif kind is CaseResult.Kind.SUCCESS:
+      pass
+    elif kind is CaseResult.Kind.SKIP:
+      assert skip_reason is not None
+    elif kind is CaseResult.Kind.EXPECTED_FAILURE:
+      assert traceback is not None
+    elif kind is CaseResult.Kind.UNEXPECTED_SUCCESS:
+      pass
+    else:
+      assert False
+    return super(cls, CaseResult).__new__(
+        cls, id, name, kind, stdout, stderr, skip_reason, traceback)
+
+  def updated(self, name=None, kind=None, stdout=None, stderr=None,
+              skip_reason=None, traceback=None):
+    """Get a new validated CaseResult with the fields updated.
+
+    See this class' attributes for information on the arguments."""
+    name = self.name if name is None else name
+    kind = self.kind if kind is None else kind
+    stdout = self.stdout if stdout is None else stdout
+    stderr = self.stderr if stderr is None else stderr
+    skip_reason = self.skip_reason if skip_reason is None else skip_reason
+    traceback = self.traceback if traceback is None else traceback
+    return CaseResult(id=self.id, name=name, kind=kind, stdout=stdout,
+                      stderr=stderr, skip_reason=skip_reason,
+                      traceback=traceback)
+
+
+class AugmentedResult(unittest.TestResult):
+  """unittest.Result that keeps track of additional information.
+
+  Uses CaseResult objects to store test-case results, providing additional
+  information beyond that of the standard Python unittest library, such as
+  standard output.
+
+  Attributes:
+    id_map (callable): A unary callable mapping unittest.TestCase objects to
+      unique identifiers.
+    cases (dict): A dictionary mapping from the identifiers returned by id_map
+      to CaseResult objects corresponding to those IDs.
+  """
+
+  def __init__(self, id_map):
+    """Initialize the object with an identifier mapping.
+
+    Arguments:
+      id_map (callable): Corresponds to the attribute `id_map`."""
+    super(AugmentedResult, self).__init__()
+    self.id_map = id_map
+    self.cases = None
+
+  def startTestRun(self):
+    """See unittest.TestResult.startTestRun."""
+    super(AugmentedResult, self).startTestRun()
+    self.cases = dict()
+
+  def stopTestRun(self):
+    """See unittest.TestResult.stopTestRun."""
+    super(AugmentedResult, self).stopTestRun()
+
+  def startTest(self, test):
+    """See unittest.TestResult.startTest."""
+    super(AugmentedResult, self).startTest(test)
+    case_id = self.id_map(test)
+    self.cases[case_id] = CaseResult(
+        id=case_id, name=test.id(), kind=CaseResult.Kind.RUNNING)
+
+  def addError(self, test, error):
+    """See unittest.TestResult.addError."""
+    super(AugmentedResult, self).addError(test, error)
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        kind=CaseResult.Kind.ERROR, traceback=error)
+
+  def addFailure(self, test, error):
+    """See unittest.TestResult.addFailure."""
+    super(AugmentedResult, self).addFailure(test, error)
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        kind=CaseResult.Kind.FAILURE, traceback=error)
+
+  def addSuccess(self, test):
+    """See unittest.TestResult.addSuccess."""
+    super(AugmentedResult, self).addSuccess(test)
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        kind=CaseResult.Kind.SUCCESS)
+
+  def addSkip(self, test, reason):
+    """See unittest.TestResult.addSkip."""
+    super(AugmentedResult, self).addSkip(test, reason)
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        kind=CaseResult.Kind.SKIP, skip_reason=reason)
+
+  def addExpectedFailure(self, test, error):
+    """See unittest.TestResult.addExpectedFailure."""
+    super(AugmentedResult, self).addExpectedFailure(test, error)
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=error)
+
+  def addUnexpectedSuccess(self, test):
+    """See unittest.TestResult.addUnexpectedSuccess."""
+    super(AugmentedResult, self).addUnexpectedSuccess(test)
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        kind=CaseResult.Kind.UNEXPECTED_SUCCESS)
+
+  def set_output(self, test, stdout, stderr):
+    """Set the output attributes for the CaseResult corresponding to a test.
+
+    Args:
+      test (unittest.TestCase): The TestCase to set the outputs of.
+      stdout (str): Output from stdout to assign to self.id_map(test).
+      stderr (str): Output from stderr to assign to self.id_map(test).
+    """
+    case_id = self.id_map(test)
+    self.cases[case_id] = self.cases[case_id].updated(
+        stdout=stdout, stderr=stderr)
+
+  def augmented_results(self, filter):
+    """Convenience method to retrieve filtered case results.
+
+    Args:
+      filter (callable): A unary predicate to filter over CaseResult objects.
+    """
+    return (self.cases[case_id] for case_id in self.cases
+            if filter(self.cases[case_id]))
+
+
+class CoverageResult(AugmentedResult):
+  """Extension to AugmentedResult adding coverage.py support per test.\
+
+  Attributes:
+    coverage_context (coverage.Coverage): coverage.py management object.
+  """
+
+  def __init__(self, id_map):
+    """See AugmentedResult.__init__."""
+    super(CoverageResult, self).__init__(id_map=id_map)
+    self.coverage_context = None
+
+  def startTest(self, test):
+    """See unittest.TestResult.startTest.
+
+    Additionally initializes and begins code coverage tracking."""
+    super(CoverageResult, self).startTest(test)
+    self.coverage_context = coverage.Coverage(data_suffix=True)
+    self.coverage_context.start()
+
+  def stopTest(self, test):
+    """See unittest.TestResult.stopTest.
+
+    Additionally stops and deinitializes code coverage tracking."""
+    super(CoverageResult, self).stopTest(test)
+    self.coverage_context.stop()
+    self.coverage_context.save()
+    self.coverage_context = None
+
+  def stopTestRun(self):
+    """See unittest.TestResult.stopTestRun."""
+    super(CoverageResult, self).stopTestRun()
+    # TODO(atash): Dig deeper into why the following line fails to properly
+    # combine coverage data from the Cython plugin.
+    #coverage.Coverage().combine()
+
+
+class _Colors:
+  """Namespaced constants for terminal color magic numbers."""
+  HEADER = '\033[95m'
+  INFO = '\033[94m'
+  OK = '\033[92m'
+  WARN = '\033[93m'
+  FAIL = '\033[91m'
+  BOLD = '\033[1m'
+  UNDERLINE = '\033[4m'
+  END = '\033[0m'
+
+
+class TerminalResult(CoverageResult):
+  """Extension to CoverageResult adding basic terminal reporting."""
+
+  def __init__(self, out, id_map):
+    """Initialize the result object.
+
+    Args:
+      out (file-like): Output file to which terminal-colored live results will
+        be written.
+      id_map (callable): See AugmentedResult.__init__.
+    """
+    super(TerminalResult, self).__init__(id_map=id_map)
+    self.out = out
+
+  def startTestRun(self):
+    """See unittest.TestResult.startTestRun."""
+    super(TerminalResult, self).startTestRun()
+    self.out.write(
+        _Colors.HEADER +
+        'Testing gRPC Python...\n' +
+        _Colors.END)
+
+  def stopTestRun(self):
+    """See unittest.TestResult.stopTestRun."""
+    super(TerminalResult, self).stopTestRun()
+    self.out.write(summary(self))
+    self.out.flush()
+
+  def addError(self, test, error):
+    """See unittest.TestResult.addError."""
+    super(TerminalResult, self).addError(test, error)
+    self.out.write(
+        _Colors.FAIL +
+        'ERROR         {}\n'.format(test.id()) +
+        _Colors.END)
+    self.out.flush()
+
+  def addFailure(self, test, error):
+    """See unittest.TestResult.addFailure."""
+    super(TerminalResult, self).addFailure(test, error)
+    self.out.write(
+        _Colors.FAIL +
+        'FAILURE       {}\n'.format(test.id()) +
+        _Colors.END)
+    self.out.flush()
+
+  def addSuccess(self, test):
+    """See unittest.TestResult.addSuccess."""
+    super(TerminalResult, self).addSuccess(test)
+    self.out.write(
+        _Colors.OK +
+        'SUCCESS       {}\n'.format(test.id()) +
+        _Colors.END)
+    self.out.flush()
+
+  def addSkip(self, test, reason):
+    """See unittest.TestResult.addSkip."""
+    super(TerminalResult, self).addSkip(test, reason)
+    self.out.write(
+        _Colors.INFO +
+        'SKIP          {}\n'.format(test.id()) +
+        _Colors.END)
+    self.out.flush()
+
+  def addExpectedFailure(self, test, error):
+    """See unittest.TestResult.addExpectedFailure."""
+    super(TerminalResult, self).addExpectedFailure(test, error)
+    self.out.write(
+        _Colors.INFO +
+        'FAILURE_OK    {}\n'.format(test.id()) +
+        _Colors.END)
+    self.out.flush()
+
+  def addUnexpectedSuccess(self, test):
+    """See unittest.TestResult.addUnexpectedSuccess."""
+    super(TerminalResult, self).addUnexpectedSuccess(test)
+    self.out.write(
+        _Colors.INFO +
+        'UNEXPECTED_OK {}\n'.format(test.id()) +
+        _Colors.END)
+    self.out.flush()
+
+def _traceback_string(type, value, trace):
+  """Generate a descriptive string of a Python exception traceback.
+
+  Args:
+    type (class): The type of the exception.
+    value (Exception): The value of the exception.
+    trace (traceback): Traceback of the exception.
+
+  Returns:
+    str: Formatted exception descriptive string.
+  """
+  buffer = StringIO.StringIO()
+  traceback.print_exception(type, value, trace, file=buffer)
+  return buffer.getvalue()
+
+def summary(result):
+  """A summary string of a result object.
+
+  Args:
+    result (AugmentedResult): The result object to get the summary of.
+
+  Returns:
+    str: The summary string.
+  """
+  assert isinstance(result, AugmentedResult)
+  untested = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.UNTESTED))
+  running = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.RUNNING))
+  failures = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.FAILURE))
+  errors = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.ERROR))
+  successes = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.SUCCESS))
+  skips = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.SKIP))
+  expected_failures = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.EXPECTED_FAILURE))
+  unexpected_successes = list(result.augmented_results(
+      lambda case_result: case_result.kind is CaseResult.Kind.UNEXPECTED_SUCCESS))
+  running_names = [case.name for case in running]
+  finished_count = (len(failures) + len(errors) + len(successes) +
+                    len(expected_failures) + len(unexpected_successes))
+  statistics = (
+      '{finished} tests finished:\n'
+      '\t{successful} successful\n'
+      '\t{unsuccessful} unsuccessful\n'
+      '\t{skipped} skipped\n'
+      '\t{expected_fail} expected failures\n'
+      '\t{unexpected_successful} unexpected successes\n'
+      'Interrupted Tests:\n'
+      '\t{interrupted}\n'
+      .format(finished=finished_count,
+              successful=len(successes),
+              unsuccessful=(len(failures)+len(errors)),
+              skipped=len(skips),
+              expected_fail=len(expected_failures),
+              unexpected_successful=len(unexpected_successes),
+              interrupted=str(running_names)))
+  tracebacks = '\n\n'.join([
+      (_Colors.FAIL + '{test_name}' + _Colors.END + + '\n' +
+       _Colors.BOLD + 'traceback:' + _Colors.END + '\n' +
+       '{traceback}\n' +
+       _Colors.BOLD + 'stdout:' + _Colors.END + '\n' +
+       '{stdout}\n' +
+       _Colors.BOLD + 'stderr:' + _Colors.END + '\n' +
+       '{stderr}\n').format(
+           test_name=result.name,
+           traceback=_traceback_string(*result.traceback),
+           stdout=result.stdout, stderr=result.stderr)
+      for result in itertools.chain(failures, errors)
+  ])
+  notes = 'Unexpected successes: {}\n'.format([
+      result.name for result in unexpected_successes])
+  return statistics + '\nErrors/Failures: \n' + tracebacks + '\n' + notes
+
+
+def jenkins_junit_xml(result):
+  """An XML tree object that when written is recognizable by Jenkins.
+
+  Args:
+    result (AugmentedResult): The result object to get the junit xml output of.
+
+  Returns:
+    ElementTree.ElementTree: The XML tree.
+  """
+  assert isinstance(result, AugmentedResult)
+  root = ElementTree.Element('testsuites')
+  suite = ElementTree.SubElement(root, 'testsuite', {
+      'name': 'Python gRPC tests',
+  })
+  for case in result.cases.values():
+    if case.kind is CaseResult.Kind.SUCCESS:
+      ElementTree.SubElement(suite, 'testcase', {
+          'name': case.name,
+      })
+    elif case.kind in (CaseResult.Kind.ERROR, CaseResult.Kind.FAILURE):
+      case_xml = ElementTree.SubElement(suite, 'testcase', {
+          'name': case.name,
+      })
+      error_xml = ElementTree.SubElement(case_xml, 'error', {})
+      error_xml.text = ''.format(case.stderr, case.traceback)
+  return ElementTree.ElementTree(element=root)
diff --git a/src/python/grpcio/tests/_runner.py b/src/python/grpcio/tests/_runner.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f1ddb57fcfa0956c418314a075ff66c793ea9da
--- /dev/null
+++ b/src/python/grpcio/tests/_runner.py
@@ -0,0 +1,224 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import cStringIO as StringIO
+import collections
+import fcntl
+import multiprocessing
+import os
+import select
+import signal
+import sys
+import threading
+import time
+import unittest
+import uuid
+
+from tests import _loader
+from tests import _result
+
+
+class CapturePipe(object):
+  """A context-manager pipe to redirect output to a byte array.
+
+  Attributes:
+    _redirect_fd (int): File descriptor of file to redirect writes from.
+    _saved_fd (int): A copy of the original value of the redirected file
+      descriptor.
+    _read_thread (threading.Thread or None): Thread upon which reads through the
+      pipe are performed. Only non-None when self is started.
+    _read_fd (int or None): File descriptor of the read end of the redirect
+      pipe. Only non-None when self is started.
+    _write_fd (int or None): File descriptor of the write end of the redirect
+      pipe. Only non-None when self is started.
+    output (bytearray or None): Redirected output from writes to the redirected
+      file descriptor. Only valid during and after self has started.
+  """
+
+  def __init__(self, fd):
+    self._redirect_fd = fd
+    self._saved_fd = os.dup(self._redirect_fd)
+    self._read_thread = None
+    self._read_fd = None
+    self._write_fd = None
+    self.output = None
+
+  def start(self):
+    """Start redirection of writes to the file descriptor."""
+    self._read_fd, self._write_fd = os.pipe()
+    os.dup2(self._write_fd, self._redirect_fd)
+    flags = fcntl.fcntl(self._read_fd, fcntl.F_GETFL)
+    fcntl.fcntl(self._read_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+    self._read_thread = threading.Thread(target=self._read)
+    self._read_thread.start()
+
+  def stop(self):
+    """Stop redirection of writes to the file descriptor."""
+    os.close(self._write_fd)
+    os.dup2(self._saved_fd, self._redirect_fd)  # auto-close self._redirect_fd
+    self._read_thread.join()
+    self._read_thread = None
+    # we waited for the read thread to finish, so _read_fd has been read and we
+    # can close it.
+    os.close(self._read_fd)
+
+  def _read(self):
+    """Read-thread target for self."""
+    self.output = bytearray()
+    while True:
+      select.select([self._read_fd], [], [])
+      read_bytes = os.read(self._read_fd, 1024)
+      if read_bytes:
+        self.output.extend(read_bytes)
+      else:
+        break
+
+  def write_bypass(self, value):
+    """Bypass the redirection and write directly to the original file.
+
+    Arguments:
+      value (str): What to write to the original file.
+    """
+    if self._saved_fd is None:
+      os.write(self._redirect_fd, value)
+    else:
+      os.write(self._saved_fd, value)
+
+  def __enter__(self):
+    self.start()
+    return self
+
+  def __exit__(self, type, value, traceback):
+    self.stop()
+
+  def close(self):
+    """Close any resources used by self not closed by stop()."""
+    os.close(self._saved_fd)
+
+
+class AugmentedCase(collections.namedtuple('AugmentedCase', [
+    'case', 'id'])):
+  """A test case with a guaranteed unique externally specified identifier.
+
+  Attributes:
+    case (unittest.TestCase): TestCase we're decorating with an additional
+      identifier.
+    id (object): Any identifier that may be considered 'unique' for testing
+      purposes.
+  """
+
+  def __new__(cls, case, id=None):
+    if id is None:
+      id = uuid.uuid4()
+    return super(cls, AugmentedCase).__new__(cls, case, id)
+
+
+class Runner(object):
+
+  def run(self, suite):
+    """See setuptools' test_runner setup argument for information."""
+    # Ensure that every test case has no collision with any other test case in
+    # the augmented results.
+    augmented_cases = [AugmentedCase(case, uuid.uuid4())
+                       for case in _loader.iterate_suite_cases(suite)]
+    case_id_by_case = dict((augmented_case.case, augmented_case.id)
+                           for augmented_case in augmented_cases)
+    result_out = StringIO.StringIO()
+    result = _result.TerminalResult(
+        result_out, id_map=lambda case: case_id_by_case[case])
+    stdout_pipe = CapturePipe(sys.stdout.fileno())
+    stderr_pipe = CapturePipe(sys.stderr.fileno())
+    kill_flag = [False]
+
+    def sigint_handler(signal_number, frame):
+      if signal_number == signal.SIGINT:
+        kill_flag[0] = True  # Python 2.7 not having 'local'... :-(
+      signal.signal(signal_number, signal.SIG_DFL)
+
+    def fault_handler(signal_number, frame):
+      stdout_pipe.write_bypass(
+          'Received fault signal {}\nstdout:\n{}\n\nstderr:{}\n'
+          .format(signal_number, stdout_pipe.output, stderr_pipe.output))
+      os._exit(1)
+
+    def check_kill_self():
+      if kill_flag[0]:
+        stdout_pipe.write_bypass('Stopping tests short...')
+        result.stopTestRun()
+        stdout_pipe.write_bypass(result_out.getvalue())
+        stdout_pipe.write_bypass(
+            '\ninterrupted stdout:\n{}\n'.format(stdout_pipe.output))
+        stderr_pipe.write_bypass(
+            '\ninterrupted stderr:\n{}\n'.format(stderr_pipe.output))
+        os._exit(1)
+    signal.signal(signal.SIGINT, sigint_handler)
+    signal.signal(signal.SIGSEGV, fault_handler)
+    signal.signal(signal.SIGBUS, fault_handler)
+    signal.signal(signal.SIGABRT, fault_handler)
+    signal.signal(signal.SIGFPE, fault_handler)
+    signal.signal(signal.SIGILL, fault_handler)
+    # Sometimes output will lag after a test has successfully finished; we
+    # ignore such writes to our pipes.
+    signal.signal(signal.SIGPIPE, signal.SIG_IGN)
+
+    # Run the tests
+    result.startTestRun()
+    for augmented_case in augmented_cases:
+      sys.stdout.write('Running       {}\n'.format(augmented_case.case.id()))
+      sys.stdout.flush()
+      case_thread = threading.Thread(
+          target=augmented_case.case.run, args=(result,))
+      try:
+        with stdout_pipe, stderr_pipe:
+          case_thread.start()
+          while case_thread.is_alive():
+            check_kill_self()
+            time.sleep(0)
+          case_thread.join()
+      except:
+        # re-raise the exception after forcing the with-block to end
+        raise
+      result.set_output(
+          augmented_case.case, stdout_pipe.output, stderr_pipe.output)
+      sys.stdout.write(result_out.getvalue())
+      sys.stdout.flush()
+      result_out.truncate(0)
+      check_kill_self()
+    result.stopTestRun()
+    stdout_pipe.close()
+    stderr_pipe.close()
+
+    # Report results
+    sys.stdout.write(result_out.getvalue())
+    sys.stdout.flush()
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+    with open('report.xml', 'w') as report_xml_file:
+      _result.jenkins_junit_xml(result).write(report_xml_file)
+    return result
+
diff --git a/src/python/grpcio_test/grpc_interop/__init__.py b/src/python/grpcio/tests/interop/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/__init__.py
rename to src/python/grpcio/tests/interop/__init__.py
diff --git a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py b/src/python/grpcio/tests/interop/_insecure_interop_test.py
similarity index 93%
rename from src/python/grpcio_test/grpc_interop/_insecure_interop_test.py
rename to src/python/grpcio/tests/interop/_insecure_interop_test.py
index 5007be28ff6519d0c5c1687131fe5730058d32b8..00b49aba374970f65af47bc97747fea87f40d9f9 100644
--- a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py
+++ b/src/python/grpcio/tests/interop/_insecure_interop_test.py
@@ -33,10 +33,10 @@ import unittest
 
 from grpc.beta import implementations
 
-from grpc_interop import _interop_test_case
-from grpc_interop import methods
-from grpc_interop import server
-from grpc_interop import test_pb2
+from tests.interop import _interop_test_case
+from tests.interop import methods
+from tests.interop import server
+from tests.interop import test_pb2
 
 
 class InsecureInteropTest(
diff --git a/src/python/grpcio_test/grpc_interop/_interop_test_case.py b/src/python/grpcio/tests/interop/_interop_test_case.py
similarity index 98%
rename from src/python/grpcio_test/grpc_interop/_interop_test_case.py
rename to src/python/grpcio/tests/interop/_interop_test_case.py
index b6d06b300dc3c02b8132bb923ebf39dd87fb50ec..ccea17a66da0a35f3a5cdfe09a6a942793bb5461 100644
--- a/src/python/grpcio_test/grpc_interop/_interop_test_case.py
+++ b/src/python/grpcio/tests/interop/_interop_test_case.py
@@ -29,7 +29,7 @@
 
 """Common code for unit tests of the interoperability test code."""
 
-from grpc_interop import methods
+from tests.interop import methods
 
 
 class InteropTestCase(object):
diff --git a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py b/src/python/grpcio/tests/interop/_secure_interop_test.py
similarity index 90%
rename from src/python/grpcio_test/grpc_interop/_secure_interop_test.py
rename to src/python/grpcio/tests/interop/_secure_interop_test.py
index 108e15b0f90771a3c7e7b56188aba3a8a9795ca1..7e3061133f1119b7cf49f9b0ce46c1f815c21078 100644
--- a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py
+++ b/src/python/grpcio/tests/interop/_secure_interop_test.py
@@ -33,12 +33,12 @@ import unittest
 
 from grpc.beta import implementations
 
-from grpc_test.beta import test_utilities
+from tests.interop import _interop_test_case
+from tests.interop import methods
+from tests.interop import resources
+from tests.interop import test_pb2
 
-from grpc_interop import _interop_test_case
-from grpc_interop import methods
-from grpc_interop import resources
-from grpc_interop import test_pb2
+from tests.unit.beta import test_utilities
 
 _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
 
@@ -55,7 +55,7 @@ class SecureInteropTest(
     self.server.start()
     self.stub = test_pb2.beta_create_TestService_stub(
         test_utilities.not_really_secure_channel(
-            '[::]', port, implementations.ssl_client_credentials(
+            '[::]', port, implementations.ssl_channel_credentials(
                 resources.test_root_certificates(), None, None),
                 _SERVER_HOST_OVERRIDE))
 
diff --git a/src/python/grpcio_test/grpc_interop/client.py b/src/python/grpcio/tests/interop/client.py
similarity index 94%
rename from src/python/grpcio_test/grpc_interop/client.py
rename to src/python/grpcio/tests/interop/client.py
index b8d5047ca51b2ec06f71e0b34bb5c4889e7133cd..5c00bce01491c175f31e8be782381b3ba651a2d9 100644
--- a/src/python/grpcio_test/grpc_interop/client.py
+++ b/src/python/grpcio/tests/interop/client.py
@@ -34,11 +34,10 @@ from oauth2client import client as oauth2client_client
 
 from grpc.beta import implementations
 
-from grpc_test.beta import test_utilities
-
-from grpc_interop import methods
-from grpc_interop import resources
-from grpc_interop import test_pb2
+from tests.interop import methods
+from tests.interop import resources
+from tests.interop import test_pb2
+from tests.unit.beta import test_utilities
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
@@ -95,7 +94,7 @@ def _stub(args):
 
     channel = test_utilities.not_really_secure_channel(
         args.server_host, args.server_port,
-        implementations.ssl_client_credentials(root_certificates, None, None),
+        implementations.ssl_channel_credentials(root_certificates, None, None),
         args.server_host_override)
     stub = test_pb2.beta_create_TestService_stub(
         channel, metadata_transformer=metadata_transformer)
@@ -114,7 +113,7 @@ def _test_case_from_arg(test_case_arg):
     raise ValueError('No test case "%s"!' % test_case_arg)
 
 
-def _test_interoperability():
+def test_interoperability():
   args = _args()
   stub = _stub(args)
   test_case = _test_case_from_arg(args.test_case)
@@ -122,4 +121,4 @@ def _test_interoperability():
 
 
 if __name__ == '__main__':
-  _test_interoperability()
+  test_interoperability()
diff --git a/src/python/grpcio_test/grpc_interop/credentials/README b/src/python/grpcio/tests/interop/credentials/README
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/credentials/README
rename to src/python/grpcio/tests/interop/credentials/README
diff --git a/src/python/grpcio_test/grpc_interop/credentials/ca.pem b/src/python/grpcio/tests/interop/credentials/ca.pem
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/credentials/ca.pem
rename to src/python/grpcio/tests/interop/credentials/ca.pem
diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.key b/src/python/grpcio/tests/interop/credentials/server1.key
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/credentials/server1.key
rename to src/python/grpcio/tests/interop/credentials/server1.key
diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.pem b/src/python/grpcio/tests/interop/credentials/server1.pem
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/credentials/server1.pem
rename to src/python/grpcio/tests/interop/credentials/server1.pem
diff --git a/src/python/grpcio_test/grpc_interop/empty.proto b/src/python/grpcio/tests/interop/empty.proto
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/empty.proto
rename to src/python/grpcio/tests/interop/empty.proto
diff --git a/src/python/grpcio_test/grpc_interop/messages.proto b/src/python/grpcio/tests/interop/messages.proto
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/messages.proto
rename to src/python/grpcio/tests/interop/messages.proto
diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio/tests/interop/methods.py
similarity index 99%
rename from src/python/grpcio_test/grpc_interop/methods.py
rename to src/python/grpcio/tests/interop/methods.py
index 3ef854535550984bc0d5c4594265f62b7966042f..b3591aef7bcab8e3e84e22486c8db78155ab0dc3 100644
--- a/src/python/grpcio_test/grpc_interop/methods.py
+++ b/src/python/grpcio/tests/interop/methods.py
@@ -40,9 +40,9 @@ from oauth2client import client as oauth2client_client
 from grpc.framework.common import cardinality
 from grpc.framework.interfaces.face import face
 
-from grpc_interop import empty_pb2
-from grpc_interop import messages_pb2
-from grpc_interop import test_pb2
+from tests.interop import empty_pb2
+from tests.interop import messages_pb2
+from tests.interop import test_pb2
 
 _TIMEOUT = 7
 
diff --git a/src/python/grpcio_test/grpc_interop/resources.py b/src/python/grpcio/tests/interop/resources.py
similarity index 100%
rename from src/python/grpcio_test/grpc_interop/resources.py
rename to src/python/grpcio/tests/interop/resources.py
diff --git a/src/python/grpcio_test/grpc_interop/server.py b/src/python/grpcio/tests/interop/server.py
similarity index 95%
rename from src/python/grpcio_test/grpc_interop/server.py
rename to src/python/grpcio/tests/interop/server.py
index b5410876639af77d9a5b824fdb25e85c83af1f53..6dd55f008c3a680f95d4bf3ac33f7918e88da21e 100644
--- a/src/python/grpcio_test/grpc_interop/server.py
+++ b/src/python/grpcio/tests/interop/server.py
@@ -35,9 +35,9 @@ import time
 
 from grpc.beta import implementations
 
-from grpc_interop import methods
-from grpc_interop import resources
-from grpc_interop import test_pb2
+from tests.interop import methods
+from tests.interop import resources
+from tests.interop import test_pb2
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
@@ -68,7 +68,7 @@ def serve():
       time.sleep(_ONE_DAY_IN_SECONDS)
   except BaseException as e:
     logging.info('Caught exception "%s"; stopping server...', e)
-    server.stop()
+    server.stop(0)
     logging.info('Server stopped; exiting.')
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_test/grpc_interop/test.proto b/src/python/grpcio/tests/interop/test.proto
similarity index 98%
rename from src/python/grpcio_test/grpc_interop/test.proto
rename to src/python/grpcio/tests/interop/test.proto
index b499813e563a43a5b99c9506146f1d5d47791954..9feecc02785e3e1da5ca70cb049ffa9b14c503f9 100644
--- a/src/python/grpcio_test/grpc_interop/test.proto
+++ b/src/python/grpcio/tests/interop/test.proto
@@ -33,8 +33,8 @@
 
 syntax = "proto3";
 
-import "grpc_interop/empty.proto";
-import "grpc_interop/messages.proto";
+import "tests/interop/empty.proto";
+import "tests/interop/messages.proto";
 
 package grpc.testing;
 
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/__init__.py b/src/python/grpcio/tests/protoc_plugin/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_protoc_plugin/__init__.py
rename to src/python/grpcio/tests/protoc_plugin/__init__.py
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
similarity index 88%
rename from src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py
rename to src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
index 259b978de25958e6220b5e4f72d3f8090d846980..ba5b219a88ef9dd5349d4716370604a067f90cae 100644
--- a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py
+++ b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
@@ -45,7 +45,7 @@ import unittest
 from grpc.beta import implementations
 from grpc.framework.foundation import future
 from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
 
 # Identifiers of entities we expect to find in the generated module.
 SERVICER_IDENTIFIER = 'BetaTestServiceServicer'
@@ -218,7 +218,7 @@ class PythonPluginTest(unittest.TestCase):
     protoc_plugin_filename = distutils.spawn.find_executable(
         'grpc_python_plugin')
     test_proto_filename = pkg_resources.resource_filename(
-        'grpc_protoc_plugin', 'test.proto')
+        'tests.protoc_plugin', 'protoc_plugin_test.proto')
     if not os.path.isfile(protoc_command):
       # Assume that if we haven't built protoc that it's on the system.
       protoc_command = 'protoc'
@@ -237,7 +237,7 @@ class PythonPluginTest(unittest.TestCase):
     ]
     subprocess.check_call(' '.join(cmd), shell=True, env=os.environ,
                           cwd=os.path.dirname(test_proto_filename))
-    sys.path.append(self.outdir)
+    sys.path.insert(0, self.outdir)
 
   def tearDown(self):
     try:
@@ -245,22 +245,26 @@ class PythonPluginTest(unittest.TestCase):
     except OSError as exc:
       if exc.errno != errno.ENOENT:
         raise
+    sys.path.remove(self.outdir)
 
   def testImportAttributes(self):
     # check that we can access the generated module and its members.
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None))
     self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None))
     self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None))
     self.assertIsNotNone(getattr(test_pb2, STUB_FACTORY_IDENTIFIER, None))
 
   def testUpDown(self):
-    import test_pb2
+    import protoc_plugin_test_pb2 as test_pb2
+    reload(test_pb2)
     with _CreateService(test_pb2) as (servicer, stub):
       request = test_pb2.SimpleRequest(response_size=13)
 
   def testUnaryCall(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       request = test_pb2.SimpleRequest(response_size=13)
       response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT)
@@ -268,7 +272,8 @@ class PythonPluginTest(unittest.TestCase):
     self.assertEqual(expected_response, response)
 
   def testUnaryCallFuture(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = test_pb2.SimpleRequest(response_size=13)
     with _CreateService(test_pb2) as (methods, stub):
       # Check that the call does not block waiting for the server to respond.
@@ -280,7 +285,8 @@ class PythonPluginTest(unittest.TestCase):
     self.assertEqual(expected_response, response)
 
   def testUnaryCallFutureExpired(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       request = test_pb2.SimpleRequest(response_size=13)
       with methods.pause():
@@ -290,7 +296,8 @@ class PythonPluginTest(unittest.TestCase):
           response_future.result()
 
   def testUnaryCallFutureCancelled(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = test_pb2.SimpleRequest(response_size=13)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
@@ -299,7 +306,8 @@ class PythonPluginTest(unittest.TestCase):
         self.assertTrue(response_future.cancelled())
 
   def testUnaryCallFutureFailed(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = test_pb2.SimpleRequest(response_size=13)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
@@ -308,7 +316,8 @@ class PythonPluginTest(unittest.TestCase):
         self.assertIsNotNone(response_future.exception())
 
   def testStreamingOutputCall(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       responses = stub.StreamingOutputCall(
@@ -320,7 +329,8 @@ class PythonPluginTest(unittest.TestCase):
         self.assertEqual(expected_response, response)
 
   def testStreamingOutputCallExpired(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
@@ -330,7 +340,8 @@ class PythonPluginTest(unittest.TestCase):
           list(responses)
 
   def testStreamingOutputCallCancelled(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (unused_methods, stub):
       responses = stub.StreamingOutputCall(
@@ -341,7 +352,8 @@ class PythonPluginTest(unittest.TestCase):
         next(responses)
 
   def testStreamingOutputCallFailed(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
@@ -351,7 +363,8 @@ class PythonPluginTest(unittest.TestCase):
           next(responses)
 
   def testStreamingInputCall(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       response = stub.StreamingInputCall(
           _streaming_input_request_iterator(test_pb2),
@@ -361,7 +374,8 @@ class PythonPluginTest(unittest.TestCase):
     self.assertEqual(expected_response, response)
 
   def testStreamingInputCallFuture(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
         response_future = stub.StreamingInputCall.future(
@@ -373,7 +387,8 @@ class PythonPluginTest(unittest.TestCase):
     self.assertEqual(expected_response, response)
 
   def testStreamingInputCallFutureExpired(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
         response_future = stub.StreamingInputCall.future(
@@ -385,7 +400,8 @@ class PythonPluginTest(unittest.TestCase):
             response_future.exception(), face.ExpirationError)
 
   def testStreamingInputCallFutureCancelled(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
         response_future = stub.StreamingInputCall.future(
@@ -397,7 +413,8 @@ class PythonPluginTest(unittest.TestCase):
         response_future.result()
 
   def testStreamingInputCallFutureFailed(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
         response_future = stub.StreamingInputCall.future(
@@ -406,7 +423,8 @@ class PythonPluginTest(unittest.TestCase):
         self.assertIsNotNone(response_future.exception())
 
   def testFullDuplexCall(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       responses = stub.FullDuplexCall(
           _full_duplex_request_iterator(test_pb2), test_constants.LONG_TIMEOUT)
@@ -417,7 +435,8 @@ class PythonPluginTest(unittest.TestCase):
         self.assertEqual(expected_response, response)
 
   def testFullDuplexCallExpired(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request_iterator = _full_duplex_request_iterator(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
@@ -427,7 +446,8 @@ class PythonPluginTest(unittest.TestCase):
           list(responses)
 
   def testFullDuplexCallCancelled(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       request_iterator = _full_duplex_request_iterator(test_pb2)
       responses = stub.FullDuplexCall(
@@ -438,7 +458,8 @@ class PythonPluginTest(unittest.TestCase):
         next(responses)
 
   def testFullDuplexCallFailed(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     request_iterator = _full_duplex_request_iterator(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
@@ -449,7 +470,8 @@ class PythonPluginTest(unittest.TestCase):
           next(responses)
 
   def testHalfDuplexCall(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       def half_duplex_request_iterator():
         request = test_pb2.StreamingOutputCallRequest()
@@ -468,7 +490,8 @@ class PythonPluginTest(unittest.TestCase):
         self.assertEqual(expected_response, response)
 
   def testHalfDuplexCallWedged(self):
-    import test_pb2  # pylint: disable=g-import-not-at-top
+    import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
+    reload(test_pb2)
     condition = threading.Condition()
     wait_cell = [False]
     @contextlib.contextmanager
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/test.proto b/src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto
similarity index 100%
rename from src/python/grpcio_test/grpc_protoc_plugin/test.proto
rename to src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto
diff --git a/src/python/grpcio_test/grpc_test/__init__.py b/src/python/grpcio/tests/unit/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/__init__.py
rename to src/python/grpcio/tests/unit/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_adapter/.gitignore b/src/python/grpcio/tests/unit/_adapter/.gitignore
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_adapter/.gitignore
rename to src/python/grpcio/tests/unit/_adapter/.gitignore
diff --git a/src/python/grpcio_test/grpc_test/_adapter/__init__.py b/src/python/grpcio/tests/unit/_adapter/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_adapter/__init__.py
rename to src/python/grpcio/tests/unit/_adapter/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py
rename to src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
index 90ad0b9bcb54fd4cb370f91359f7b86ff83ece01..a6fd82388c014621c50e68749d68c224aff93c94 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py
+++ b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
@@ -115,6 +115,7 @@ class EchoTest(unittest.TestCase):
 
   def tearDown(self):
     self.server.stop()
+    self.server.cancel_all_calls()
     self.server_completion_queue.stop()
     self.client_completion_queue.stop()
     self.server_completion_queue_thread.join()
@@ -286,11 +287,6 @@ class EchoTest(unittest.TestCase):
                         set((server_trailing_metadata_key,
                              server_trailing_binary_metadata_key,)))
 
-    server_timeout_none_event = self.server_completion_queue.get(0)
-    self.assertIsNone(server_timeout_none_event)
-    client_timeout_none_event = self.client_completion_queue.get(0)
-    self.assertIsNone(client_timeout_none_event)
-
     self.assertSequenceEqual(test_data, server_data)
     self.assertSequenceEqual(test_data, client_data)
 
@@ -335,6 +331,7 @@ class CancellationTest(unittest.TestCase):
 
   def tearDown(self):
     self.server.stop()
+    self.server.cancel_all_calls()
     self.server_completion_queue.stop()
     self.client_completion_queue.stop()
     self.server_completion_queue_thread.join()
@@ -410,14 +407,9 @@ class CancellationTest(unittest.TestCase):
 
     finish_event = self.client_events.get()
     self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
-    self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), 
+    self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
                                  finish_event.status)
 
-    server_timeout_none_event = self.server_completion_queue.get(0)
-    self.assertIsNone(server_timeout_none_event)
-    client_timeout_none_event = self.client_completion_queue.get(0)
-    self.assertIsNone(client_timeout_none_event)
-
     self.assertSequenceEqual(test_data, server_data)
     self.assertSequenceEqual(test_data, client_data)
 
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py b/src/python/grpcio/tests/unit/_adapter/_low_test.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/_adapter/_low_test.py
rename to src/python/grpcio/tests/unit/_adapter/_low_test.py
index 8115cd0e8332968d0c242c2ce838edbcf5f2f25c..ec46617996bca6eb83d22184ee742e11d8098749 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
+++ b/src/python/grpcio/tests/unit/_adapter/_low_test.py
@@ -34,7 +34,7 @@ import unittest
 from grpc import _grpcio_metadata
 from grpc._adapter import _types
 from grpc._adapter import _low
-from grpc_test import test_common
+from tests.unit import test_common
 
 
 def wait_for_events(completion_queues, deadline):
@@ -80,11 +80,11 @@ class InsecureServerInsecureClient(unittest.TestCase):
     del self.client_channel
 
     self.client_completion_queue.shutdown()
-    while (self.client_completion_queue.next().type !=
+    while (self.client_completion_queue.next(float('+inf')).type !=
            _types.EventType.QUEUE_SHUTDOWN):
       pass
     self.server_completion_queue.shutdown()
-    while (self.server_completion_queue.next().type !=
+    while (self.server_completion_queue.next(float('+inf')).type !=
            _types.EventType.QUEUE_SHUTDOWN):
       pass
 
@@ -294,8 +294,12 @@ class HangingServerShutdown(unittest.TestCase):
 
     # Now try to shutdown the server and expect that we see server shutdown
     # almost immediately after calling cancel_all_calls.
+
+    # First attempt to cancel all calls before shutting down, and expect
+    # our state machine to catch the erroneous API use.
     with self.assertRaises(RuntimeError):
       self.server.cancel_all_calls()
+
     shutdown_tag = object()
     self.server.shutdown(shutdown_tag)
     pre_cancel_timestamp = time.time()
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py
rename to src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
index b3d6ec8607b4ede9155fbe43a20ad44a8212b12d..f55a7a23eaea0eeabb71c8452c6baf9ddda903b7 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py
+++ b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
@@ -32,7 +32,7 @@
 import abc
 import threading
 
-from grpc_test._junkdrawer import math_pb2
+from tests.unit._junkdrawer import math_pb2
 
 
 class ProtoScenario(object):
diff --git a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
similarity index 96%
rename from src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
rename to src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
index cafb6b6eaecbf5beb437a7c4f620671b0b3584b4..efc990421a3f2a4ca415526d1713d3e2df224c34 100644
--- a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
+++ b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
@@ -41,10 +41,10 @@ from grpc._links import service
 from grpc.beta import interfaces as beta_interfaces
 from grpc.framework.core import implementations
 from grpc.framework.interfaces.base import utilities
-from grpc_test import test_common as grpc_test_common
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import test_cases
-from grpc_test.framework.interfaces.base import test_interfaces
+from tests.unit import test_common as grpc_test_common
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.base import test_cases
+from tests.unit.framework.interfaces.base import test_interfaces
 
 
 class _SerializationBehaviors(
diff --git a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
similarity index 96%
rename from src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py
rename to src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
index a4d4dee38cefd1d19ffece3a78bb277a02e948b6..4faaaadc2b5aac00f8727b1dfe19ac634c019ae6 100644
--- a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
@@ -40,10 +40,10 @@ from grpc.framework.core import implementations as core_implementations
 from grpc.framework.crust import implementations as crust_implementations
 from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.links import utilities
-from grpc_test import test_common as grpc_test_common
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import test_cases
-from grpc_test.framework.interfaces.face import test_interfaces
+from tests.unit import test_common as grpc_test_common
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.face import test_cases
+from tests.unit.framework.interfaces.face import test_interfaces
 
 
 class _SerializationBehaviors(
diff --git a/src/python/grpcio_test/grpc_test/_cython/.gitignore b/src/python/grpcio/tests/unit/_cython/.gitignore
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_cython/.gitignore
rename to src/python/grpcio/tests/unit/_cython/.gitignore
diff --git a/src/python/grpcio_test/grpc_test/_cython/__init__.py b/src/python/grpcio/tests/unit/_cython/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_cython/__init__.py
rename to src/python/grpcio/tests/unit/_cython/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
similarity index 56%
rename from src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py
rename to src/python/grpcio/tests/unit/_cython/cygrpc_test.py
index 1307a30ca0bb4e352856be26488f59761698c72d..876da88de952bd91a1050467516ecb7016c9b25a 100644
--- a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py
+++ b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
@@ -28,11 +28,24 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 import time
+import threading
 import unittest
 
 from grpc._cython import cygrpc
-from grpc_test._cython import test_utilities
-from grpc_test import test_common
+from tests.unit._cython import test_utilities
+from tests.unit import test_common
+from tests.unit import resources
+
+
+_SSL_HOST_OVERRIDE = 'foo.test.google.fr'
+_CALL_CREDENTIALS_METADATA_KEY = 'call-creds-key'
+_CALL_CREDENTIALS_METADATA_VALUE = 'call-creds-value'
+
+def _metadata_plugin_callback(context, callback):
+  callback(cygrpc.Metadata(
+      [cygrpc.Metadatum(_CALL_CREDENTIALS_METADATA_KEY,
+                        _CALL_CREDENTIALS_METADATA_VALUE)]),
+      cygrpc.StatusCode.ok, '')
 
 
 class TypeSmokeTest(unittest.TestCase):
@@ -89,7 +102,17 @@ class TypeSmokeTest(unittest.TestCase):
     channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([]))
     del channel
 
-  @unittest.skip('TODO(atash): undo skip after #2229 is merged')
+  def testCredentialsMetadataPluginUpDown(self):
+    plugin = cygrpc.CredentialsMetadataPlugin(
+        lambda ignored_a, ignored_b: None, '')
+    del plugin
+
+  def testCallCredentialsFromPluginUpDown(self):
+    plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
+    call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
+    del plugin
+    del call_credentials
+
   def testServerStartNoExplicitShutdown(self):
     server = cygrpc.Server()
     completion_queue = cygrpc.CompletionQueue()
@@ -99,7 +122,6 @@ class TypeSmokeTest(unittest.TestCase):
     server.start()
     del server
 
-  @unittest.skip('TODO(atash): undo skip after #2229 is merged')
   def testServerStartShutdown(self):
     completion_queue = cygrpc.CompletionQueue()
     server = cygrpc.Server()
@@ -262,5 +284,169 @@ class InsecureServerInsecureClient(unittest.TestCase):
     del server_call
 
 
+class SecureServerSecureClient(unittest.TestCase):
+
+  def setUp(self):
+    server_credentials = cygrpc.server_credentials_ssl(
+        None, [cygrpc.SslPemKeyCertPair(resources.private_key(),
+                                        resources.certificate_chain())], False)
+    channel_credentials = cygrpc.channel_credentials_ssl(
+        resources.test_root_certificates(), None)
+    self.server_completion_queue = cygrpc.CompletionQueue()
+    self.server = cygrpc.Server()
+    self.server.register_completion_queue(self.server_completion_queue)
+    self.port = self.server.add_http2_port('[::]:0', server_credentials)
+    self.server.start()
+    self.client_completion_queue = cygrpc.CompletionQueue()
+    client_channel_arguments = cygrpc.ChannelArgs([
+        cygrpc.ChannelArg(cygrpc.ChannelArgKey.ssl_target_name_override,
+                          _SSL_HOST_OVERRIDE)])
+    self.client_channel = cygrpc.Channel(
+        'localhost:{}'.format(self.port), client_channel_arguments,
+        channel_credentials)
+
+  def tearDown(self):
+    del self.server
+    del self.client_completion_queue
+    del self.server_completion_queue
+
+  def testEcho(self):
+    DEADLINE = time.time()+5
+    DEADLINE_TOLERANCE = 0.25
+    CLIENT_METADATA_ASCII_KEY = b'key'
+    CLIENT_METADATA_ASCII_VALUE = b'val'
+    CLIENT_METADATA_BIN_KEY = b'key-bin'
+    CLIENT_METADATA_BIN_VALUE = b'\0'*1000
+    SERVER_INITIAL_METADATA_KEY = b'init_me_me_me'
+    SERVER_INITIAL_METADATA_VALUE = b'whodawha?'
+    SERVER_TRAILING_METADATA_KEY = b'california_is_in_a_drought'
+    SERVER_TRAILING_METADATA_VALUE = b'zomg it is'
+    SERVER_STATUS_CODE = cygrpc.StatusCode.ok
+    SERVER_STATUS_DETAILS = b'our work is never over'
+    REQUEST = b'in death a member of project mayhem has a name'
+    RESPONSE = b'his name is robert paulson'
+    METHOD = b'/twinkies'
+    HOST = None  # Default host
+
+    cygrpc_deadline = cygrpc.Timespec(DEADLINE)
+
+    server_request_tag = object()
+    request_call_result = self.server.request_call(
+        self.server_completion_queue, self.server_completion_queue,
+        server_request_tag)
+
+    self.assertEqual(cygrpc.CallError.ok, request_call_result)
+
+    plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
+    call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
+
+    client_call_tag = object()
+    client_call = self.client_channel.create_call(
+        None, 0, self.client_completion_queue, METHOD, HOST, cygrpc_deadline)
+    client_call.set_credentials(call_credentials)
+    client_initial_metadata = cygrpc.Metadata([
+        cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY,
+                         CLIENT_METADATA_ASCII_VALUE),
+        cygrpc.Metadatum(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)])
+    client_start_batch_result = client_call.start_batch(cygrpc.Operations([
+        cygrpc.operation_send_initial_metadata(client_initial_metadata),
+        cygrpc.operation_send_message(REQUEST),
+        cygrpc.operation_send_close_from_client(),
+        cygrpc.operation_receive_initial_metadata(),
+        cygrpc.operation_receive_message(),
+        cygrpc.operation_receive_status_on_client()
+    ]), client_call_tag)
+    self.assertEqual(cygrpc.CallError.ok, client_start_batch_result)
+    client_event_future = test_utilities.CompletionQueuePollFuture(
+        self.client_completion_queue, cygrpc_deadline)
+
+    request_event = self.server_completion_queue.poll(cygrpc_deadline)
+    self.assertEqual(cygrpc.CompletionType.operation_complete,
+                      request_event.type)
+    self.assertIsInstance(request_event.operation_call, cygrpc.Call)
+    self.assertIs(server_request_tag, request_event.tag)
+    self.assertEqual(0, len(request_event.batch_operations))
+    client_metadata_with_credentials = list(client_initial_metadata) + [
+        (_CALL_CREDENTIALS_METADATA_KEY, _CALL_CREDENTIALS_METADATA_VALUE)]
+    self.assertTrue(
+        test_common.metadata_transmitted(client_metadata_with_credentials,
+                                         request_event.request_metadata))
+    self.assertEqual(METHOD, request_event.request_call_details.method)
+    self.assertEqual(_SSL_HOST_OVERRIDE,
+                     request_event.request_call_details.host)
+    self.assertLess(
+        abs(DEADLINE - float(request_event.request_call_details.deadline)),
+        DEADLINE_TOLERANCE)
+
+    server_call_tag = object()
+    server_call = request_event.operation_call
+    server_initial_metadata = cygrpc.Metadata([
+        cygrpc.Metadatum(SERVER_INITIAL_METADATA_KEY,
+                         SERVER_INITIAL_METADATA_VALUE)])
+    server_trailing_metadata = cygrpc.Metadata([
+        cygrpc.Metadatum(SERVER_TRAILING_METADATA_KEY,
+                         SERVER_TRAILING_METADATA_VALUE)])
+    server_start_batch_result = server_call.start_batch([
+        cygrpc.operation_send_initial_metadata(server_initial_metadata),
+        cygrpc.operation_receive_message(),
+        cygrpc.operation_send_message(RESPONSE),
+        cygrpc.operation_receive_close_on_server(),
+        cygrpc.operation_send_status_from_server(
+            server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
+    ], server_call_tag)
+    self.assertEqual(cygrpc.CallError.ok, server_start_batch_result)
+
+    client_event = client_event_future.result()
+    server_event = self.server_completion_queue.poll(cygrpc_deadline)
+
+    self.assertEqual(6, len(client_event.batch_operations))
+    found_client_op_types = set()
+    for client_result in client_event.batch_operations:
+      # we expect each op type to be unique
+      self.assertNotIn(client_result.type, found_client_op_types)
+      found_client_op_types.add(client_result.type)
+      if client_result.type == cygrpc.OperationType.receive_initial_metadata:
+        self.assertTrue(
+            test_common.metadata_transmitted(server_initial_metadata,
+                                             client_result.received_metadata))
+      elif client_result.type == cygrpc.OperationType.receive_message:
+        self.assertEqual(RESPONSE, client_result.received_message.bytes())
+      elif client_result.type == cygrpc.OperationType.receive_status_on_client:
+        self.assertTrue(
+            test_common.metadata_transmitted(server_trailing_metadata,
+                                             client_result.received_metadata))
+        self.assertEqual(SERVER_STATUS_DETAILS,
+                         client_result.received_status_details)
+        self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code)
+    self.assertEqual(set([
+          cygrpc.OperationType.send_initial_metadata,
+          cygrpc.OperationType.send_message,
+          cygrpc.OperationType.send_close_from_client,
+          cygrpc.OperationType.receive_initial_metadata,
+          cygrpc.OperationType.receive_message,
+          cygrpc.OperationType.receive_status_on_client
+      ]), found_client_op_types)
+
+    self.assertEqual(5, len(server_event.batch_operations))
+    found_server_op_types = set()
+    for server_result in server_event.batch_operations:
+      self.assertNotIn(client_result.type, found_server_op_types)
+      found_server_op_types.add(server_result.type)
+      if server_result.type == cygrpc.OperationType.receive_message:
+        self.assertEqual(REQUEST, server_result.received_message.bytes())
+      elif server_result.type == cygrpc.OperationType.receive_close_on_server:
+        self.assertFalse(server_result.received_cancelled)
+    self.assertEqual(set([
+          cygrpc.OperationType.send_initial_metadata,
+          cygrpc.OperationType.receive_message,
+          cygrpc.OperationType.send_message,
+          cygrpc.OperationType.receive_close_on_server,
+          cygrpc.OperationType.send_status_from_server
+      ]), found_server_op_types)
+
+    del client_call
+    del server_call
+
+
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/_cython/test_utilities.py b/src/python/grpcio/tests/unit/_cython/test_utilities.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_cython/test_utilities.py
rename to src/python/grpcio/tests/unit/_cython/test_utilities.py
diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py b/src/python/grpcio/tests/unit/_junkdrawer/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py
rename to src/python/grpcio/tests/unit/_junkdrawer/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py b/src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py
rename to src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py
diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py b/src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py
rename to src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py
diff --git a/src/python/grpcio_test/grpc_test/_links/__init__.py b/src/python/grpcio/tests/unit/_links/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/_links/__init__.py
rename to src/python/grpcio/tests/unit/_links/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
similarity index 94%
rename from src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py
rename to src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
index 8e12e8cc2237c23b9f3566c72248d531e778fb23..890755f81c5af7a4a2cb7d5709ef62e48e3e2f62 100644
--- a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py
+++ b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
@@ -34,9 +34,9 @@ import unittest
 from grpc._adapter import _intermediary_low
 from grpc._links import invocation
 from grpc.framework.interfaces.links import links
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.links import test_cases
-from grpc_test.framework.interfaces.links import test_utilities
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.links import test_cases
+from tests.unit.framework.interfaces.links import test_utilities
 
 _NULL_BEHAVIOR = lambda unused_argument: None
 
diff --git a/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py
rename to src/python/grpcio/tests/unit/_links/_proto_scenarios.py
index 0d74d66297e37e5322336b7a4e541ad646535321..f69ff51b1679956cf3a945fa45136a289cb3c70b 100644
--- a/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py
+++ b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
@@ -32,8 +32,8 @@
 import abc
 import threading
 
-from grpc_test._junkdrawer import math_pb2
-from grpc_test.framework.common import test_constants
+from tests.unit._junkdrawer import math_pb2
+from tests.unit.framework.common import test_constants
 
 
 class ProtoScenario(object):
diff --git a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py b/src/python/grpcio/tests/unit/_links/_transmission_test.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/_links/_transmission_test.py
rename to src/python/grpcio/tests/unit/_links/_transmission_test.py
index 77e83d5561caf474c9586a9fb170d5449b45cadc..888684d197d65d435909291bc999c9480ecc76e3 100644
--- a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py
+++ b/src/python/grpcio/tests/unit/_links/_transmission_test.py
@@ -36,11 +36,11 @@ from grpc._links import invocation
 from grpc._links import service
 from grpc.beta import interfaces as beta_interfaces
 from grpc.framework.interfaces.links import links
-from grpc_test import test_common
-from grpc_test._links import _proto_scenarios
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.links import test_cases
-from grpc_test.framework.interfaces.links import test_utilities
+from tests.unit import test_common
+from tests.unit._links import _proto_scenarios
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.links import test_cases
+from tests.unit.framework.interfaces.links import test_utilities
 
 _IDENTITY = lambda x: x
 
diff --git a/src/python/grpcio_test/grpc_test/beta/__init__.py b/src/python/grpcio/tests/unit/beta/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/beta/__init__.py
rename to src/python/grpcio/tests/unit/beta/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
similarity index 59%
rename from src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
rename to src/python/grpcio/tests/unit/beta/_beta_features_test.py
index 5916a9e3eaef288efc083b4d1325f9f6a09a5036..ea44177b499d4d5aaa0aff826b3bc9cd7133c3f6 100644
--- a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
+++ b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
@@ -36,12 +36,15 @@ from grpc.beta import implementations
 from grpc.beta import interfaces
 from grpc.framework.common import cardinality
 from grpc.framework.interfaces.face import utilities
-from grpc_test import resources
-from grpc_test.beta import test_utilities
-from grpc_test.framework.common import test_constants
+from tests.unit import resources
+from tests.unit.beta import test_utilities
+from tests.unit.framework.common import test_constants
 
 _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
 
+_PER_RPC_CREDENTIALS_METADATA_KEY = 'my-call-credentials-metadata-key'
+_PER_RPC_CREDENTIALS_METADATA_VALUE = 'my-call-credentials-metadata-value'
+
 _GROUP = 'group'
 _UNARY_UNARY = 'unary-unary'
 _UNARY_STREAM = 'unary-stream'
@@ -63,6 +66,7 @@ class _Servicer(object):
     with self._condition:
       self._request = request
       self._peer = context.protocol_context().peer()
+      self._invocation_metadata = context.invocation_metadata()
       context.protocol_context().disable_next_response_compression()
       self._serviced = True
       self._condition.notify_all()
@@ -72,6 +76,7 @@ class _Servicer(object):
     with self._condition:
       self._request = request
       self._peer = context.protocol_context().peer()
+      self._invocation_metadata = context.invocation_metadata()
       context.protocol_context().disable_next_response_compression()
       self._serviced = True
       self._condition.notify_all()
@@ -83,6 +88,7 @@ class _Servicer(object):
       self._request = request
     with self._condition:
       self._peer = context.protocol_context().peer()
+      self._invocation_metadata = context.invocation_metadata()
       context.protocol_context().disable_next_response_compression()
       self._serviced = True
       self._condition.notify_all()
@@ -95,6 +101,7 @@ class _Servicer(object):
         context.protocol_context().disable_next_response_compression()
         yield _RESPONSE
     with self._condition:
+      self._invocation_metadata = context.invocation_metadata()
       self._serviced = True
       self._condition.notify_all()
 
@@ -137,6 +144,11 @@ class _BlockingIterator(object):
       self._condition.notify_all()
 
 
+def _metadata_plugin(context, callback):
+  callback([(_PER_RPC_CREDENTIALS_METADATA_KEY,
+             _PER_RPC_CREDENTIALS_METADATA_VALUE)], None)
+
+
 class BetaFeaturesTest(unittest.TestCase):
 
   def setUp(self):
@@ -167,10 +179,12 @@ class BetaFeaturesTest(unittest.TestCase):
         [(resources.private_key(), resources.certificate_chain(),),])
     port = self._server.add_secure_port('[::]:0', server_credentials)
     self._server.start()
-    self._client_credentials = implementations.ssl_client_credentials(
+    self._channel_credentials = implementations.ssl_channel_credentials(
         resources.test_root_certificates(), None, None)
+    self._call_credentials = implementations.metadata_call_credentials(
+        _metadata_plugin)
     channel = test_utilities.not_really_secure_channel(
-        'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE)
+        'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE)
     stub_options = implementations.stub_options(
         thread_pool_size=test_constants.POOL_SIZE)
     self._dynamic_stub = implementations.dynamic_stub(
@@ -181,21 +195,36 @@ class BetaFeaturesTest(unittest.TestCase):
     self._server.stop(test_constants.SHORT_TIMEOUT).wait()
 
   def test_unary_unary(self):
-    call_options = interfaces.grpc_call_options(disable_compression=True)
+    call_options = interfaces.grpc_call_options(
+        disable_compression=True, credentials=self._call_credentials)
     response = getattr(self._dynamic_stub, _UNARY_UNARY)(
         _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
     self.assertEqual(_RESPONSE, response)
     self.assertIsNotNone(self._servicer.peer())
+    invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+                           self._servicer._invocation_metadata]
+    self.assertIn(
+        (_PER_RPC_CREDENTIALS_METADATA_KEY,
+         _PER_RPC_CREDENTIALS_METADATA_VALUE),
+        invocation_metadata)
 
   def test_unary_stream(self):
-    call_options = interfaces.grpc_call_options(disable_compression=True)
+    call_options = interfaces.grpc_call_options(
+        disable_compression=True, credentials=self._call_credentials)
     response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)(
         _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
     self._servicer.block_until_serviced()
     self.assertIsNotNone(self._servicer.peer())
+    invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+                           self._servicer._invocation_metadata]
+    self.assertIn(
+        (_PER_RPC_CREDENTIALS_METADATA_KEY,
+         _PER_RPC_CREDENTIALS_METADATA_VALUE),
+        invocation_metadata)
 
   def test_stream_unary(self):
-    call_options = interfaces.grpc_call_options()
+    call_options = interfaces.grpc_call_options(
+        credentials=self._call_credentials)
     request_iterator = _BlockingIterator(iter((_REQUEST,)))
     response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future(
         request_iterator, test_constants.LONG_TIMEOUT,
@@ -207,9 +236,16 @@ class BetaFeaturesTest(unittest.TestCase):
     self._servicer.block_until_serviced()
     self.assertIsNotNone(self._servicer.peer())
     self.assertEqual(_RESPONSE, response_future.result())
+    invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+                           self._servicer._invocation_metadata]
+    self.assertIn(
+        (_PER_RPC_CREDENTIALS_METADATA_KEY,
+         _PER_RPC_CREDENTIALS_METADATA_VALUE),
+        invocation_metadata)
 
   def test_stream_stream(self):
-    call_options = interfaces.grpc_call_options()
+    call_options = interfaces.grpc_call_options(
+        credentials=self._call_credentials)
     request_iterator = _BlockingIterator(iter((_REQUEST,)))
     response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)(
         request_iterator, test_constants.SHORT_TIMEOUT,
@@ -222,6 +258,85 @@ class BetaFeaturesTest(unittest.TestCase):
     self._servicer.block_until_serviced()
     self.assertIsNotNone(self._servicer.peer())
     self.assertEqual(_RESPONSE, response)
+    invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+                           self._servicer._invocation_metadata]
+    self.assertIn(
+        (_PER_RPC_CREDENTIALS_METADATA_KEY,
+         _PER_RPC_CREDENTIALS_METADATA_VALUE),
+        invocation_metadata)
+
+
+class ContextManagementAndLifecycleTest(unittest.TestCase):
+
+  def setUp(self):
+    self._servicer = _Servicer()
+    self._method_implementations = {
+        (_GROUP, _UNARY_UNARY):
+            utilities.unary_unary_inline(self._servicer.unary_unary),
+        (_GROUP, _UNARY_STREAM):
+            utilities.unary_stream_inline(self._servicer.unary_stream),
+        (_GROUP, _STREAM_UNARY):
+            utilities.stream_unary_inline(self._servicer.stream_unary),
+        (_GROUP, _STREAM_STREAM):
+            utilities.stream_stream_inline(self._servicer.stream_stream),
+    }
+
+    self._cardinalities = {
+        _UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY,
+        _UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM,
+        _STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY,
+        _STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM,
+    }
+
+    self._server_options = implementations.server_options(
+        thread_pool_size=test_constants.POOL_SIZE)
+    self._server_credentials = implementations.ssl_server_credentials(
+        [(resources.private_key(), resources.certificate_chain(),),])
+    self._channel_credentials = implementations.ssl_channel_credentials(
+        resources.test_root_certificates(), None, None)
+    self._stub_options = implementations.stub_options(
+        thread_pool_size=test_constants.POOL_SIZE)
+
+  def test_stub_context(self):
+    server = implementations.server(
+        self._method_implementations, options=self._server_options)
+    port = server.add_secure_port('[::]:0', self._server_credentials)
+    server.start()
+
+    channel = test_utilities.not_really_secure_channel(
+        'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE)
+    dynamic_stub = implementations.dynamic_stub(
+        channel, _GROUP, self._cardinalities, options=self._stub_options)
+    for _ in range(100):
+      with dynamic_stub:
+        pass
+    for _ in range(10):
+      with dynamic_stub:
+        call_options = interfaces.grpc_call_options(
+            disable_compression=True)
+        response = getattr(dynamic_stub, _UNARY_UNARY)(
+            _REQUEST, test_constants.LONG_TIMEOUT,
+            protocol_options=call_options)
+        self.assertEqual(_RESPONSE, response)
+        self.assertIsNotNone(self._servicer.peer())
+
+    server.stop(test_constants.SHORT_TIMEOUT).wait()
+
+  def test_server_lifecycle(self):
+    for _ in range(100):
+      server = implementations.server(
+          self._method_implementations, options=self._server_options)
+      port = server.add_secure_port('[::]:0', self._server_credentials)
+      server.start()
+      server.stop(test_constants.SHORT_TIMEOUT).wait()
+    for _ in range(100):
+      server = implementations.server(
+          self._method_implementations, options=self._server_options)
+      server.add_secure_port('[::]:0', self._server_credentials)
+      server.add_insecure_port('[::]:0')
+      with server:
+        server.stop(test_constants.SHORT_TIMEOUT)
+      server.stop(test_constants.SHORT_TIMEOUT)
 
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py
rename to src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
index b3c05bdb0c90d3eb728ba117f3f59da4a4a9cb41..5dc87206394968e60ccea208b851c1d2534f91fc 100644
--- a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py
+++ b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
@@ -37,7 +37,7 @@ from grpc._adapter import _low
 from grpc._adapter import _types
 from grpc.beta import _connectivity_channel
 from grpc.beta import interfaces
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
 
 
 def _drive_completion_queue(completion_queue):
diff --git a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py b/src/python/grpcio/tests/unit/beta/_face_interface_test.py
similarity index 92%
rename from src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
rename to src/python/grpcio/tests/unit/beta/_face_interface_test.py
index aa33e1e6f8625e7f414c1562264f9c960f52d731..1c21dfd03d59f85679d135ae58617ea81cd31152 100644
--- a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/beta/_face_interface_test.py
@@ -34,12 +34,12 @@ import unittest
 
 from grpc.beta import implementations
 from grpc.beta import interfaces
-from grpc_test import resources
-from grpc_test import test_common as grpc_test_common
-from grpc_test.beta import test_utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import test_cases
-from grpc_test.framework.interfaces.face import test_interfaces
+from tests.unit import resources
+from tests.unit import test_common as grpc_test_common
+from tests.unit.beta import test_utilities
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.face import test_cases
+from tests.unit.framework.interfaces.face import test_interfaces
 
 _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
 
@@ -91,10 +91,10 @@ class _Implementation(test_interfaces.Implementation):
         [(resources.private_key(), resources.certificate_chain(),),])
     port = server.add_secure_port('[::]:0', server_credentials)
     server.start()
-    client_credentials = implementations.ssl_client_credentials(
+    channel_credentials = implementations.ssl_channel_credentials(
         resources.test_root_certificates(), None, None)
     channel = test_utilities.not_really_secure_channel(
-        'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE)
+        'localhost', port, channel_credentials, _SERVER_HOST_OVERRIDE)
     stub_options = implementations.stub_options(
         request_serializers=serialization_behaviors.request_serializers,
         response_deserializers=serialization_behaviors.response_deserializers,
diff --git a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py b/src/python/grpcio/tests/unit/beta/_not_found_test.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/beta/_not_found_test.py
rename to src/python/grpcio/tests/unit/beta/_not_found_test.py
index 5feb997fef60df7d55ad3656666d6c7f6a955d0e..44fcd1e13c24177cc12ad62fc4b082b217937112 100644
--- a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py
+++ b/src/python/grpcio/tests/unit/beta/_not_found_test.py
@@ -34,7 +34,7 @@ import unittest
 from grpc.beta import implementations
 from grpc.beta import interfaces
 from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
 
 
 class NotFoundTest(unittest.TestCase):
diff --git a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py b/src/python/grpcio/tests/unit/beta/_utilities_test.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/beta/_utilities_test.py
rename to src/python/grpcio/tests/unit/beta/_utilities_test.py
index 996cea91189db0109aa2a01274afccde7402d8a1..08ce98e75169149073bbf530cf645ce26a0ec2c5 100644
--- a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py
+++ b/src/python/grpcio/tests/unit/beta/_utilities_test.py
@@ -38,7 +38,7 @@ from grpc._adapter import _types
 from grpc.beta import implementations
 from grpc.beta import utilities
 from grpc.framework.foundation import future
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
 
 
 def _drive_completion_queue(completion_queue):
diff --git a/src/python/grpcio_test/grpc_test/beta/test_utilities.py b/src/python/grpcio/tests/unit/beta/test_utilities.py
similarity index 92%
rename from src/python/grpcio_test/grpc_test/beta/test_utilities.py
rename to src/python/grpcio/tests/unit/beta/test_utilities.py
index 24a8600e12b1ed3145cd13833bb5441d5c667ea8..0313e06a93e5ded7d34772259628945ba8d260fe 100644
--- a/src/python/grpcio_test/grpc_test/beta/test_utilities.py
+++ b/src/python/grpcio/tests/unit/beta/test_utilities.py
@@ -34,13 +34,13 @@ from grpc.beta import implementations
 
 
 def not_really_secure_channel(
-    host, port, client_credentials, server_host_override):
+    host, port, channel_credentials, server_host_override):
   """Creates an insecure Channel to a remote host.
 
   Args:
     host: The name of the remote host to which to connect.
     port: The port of the remote host to which to connect.
-    client_credentials: The implementations.ClientCredentials with which to
+    channel_credentials: The implementations.ChannelCredentials with which to
       connect.
     server_host_override: The target name used for SSL host name checking.
 
@@ -50,7 +50,7 @@ def not_really_secure_channel(
   """
   hostport = '%s:%d' % (host, port)
   intermediary_low_channel = _intermediary_low.Channel(
-      hostport, client_credentials._intermediary_low_credentials,
+      hostport, channel_credentials._low_credentials,
       server_host_override=server_host_override)
   return implementations.Channel(
       intermediary_low_channel._internal, intermediary_low_channel)
diff --git a/src/python/grpcio_test/grpc_test/credentials/README b/src/python/grpcio/tests/unit/credentials/README
similarity index 100%
rename from src/python/grpcio_test/grpc_test/credentials/README
rename to src/python/grpcio/tests/unit/credentials/README
diff --git a/src/python/grpcio_test/grpc_test/credentials/ca.pem b/src/python/grpcio/tests/unit/credentials/ca.pem
similarity index 100%
rename from src/python/grpcio_test/grpc_test/credentials/ca.pem
rename to src/python/grpcio/tests/unit/credentials/ca.pem
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.key b/src/python/grpcio/tests/unit/credentials/server1.key
similarity index 100%
rename from src/python/grpcio_test/grpc_test/credentials/server1.key
rename to src/python/grpcio/tests/unit/credentials/server1.key
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio/tests/unit/credentials/server1.pem
similarity index 100%
rename from src/python/grpcio_test/grpc_test/credentials/server1.pem
rename to src/python/grpcio/tests/unit/credentials/server1.pem
diff --git a/src/python/grpcio_test/grpc_test/framework/__init__.py b/src/python/grpcio/tests/unit/framework/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/__init__.py
rename to src/python/grpcio/tests/unit/framework/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
similarity index 94%
rename from src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py
rename to src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
index 30bb85f6c3b5ca4ce100d8499939fb84b46a49aa..360ecc95d5d98f598d9bd9ef42789fb7da95fda1 100644
--- a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
@@ -36,10 +36,10 @@ from grpc.framework.core import implementations as core_implementations
 from grpc.framework.crust import implementations as crust_implementations
 from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.links import utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import test_cases
-from grpc_test.framework.interfaces.face import test_interfaces
-from grpc_test.framework.interfaces.links import test_utilities
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.face import test_cases
+from tests.unit.framework.interfaces.face import test_interfaces
+from tests.unit.framework.interfaces.links import test_utilities
 
 
 class _Implementation(test_interfaces.Implementation):
diff --git a/src/python/grpcio_test/grpc_test/framework/common/__init__.py b/src/python/grpcio/tests/unit/framework/common/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/common/__init__.py
rename to src/python/grpcio/tests/unit/framework/common/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py b/src/python/grpcio/tests/unit/framework/common/test_constants.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/common/test_constants.py
rename to src/python/grpcio/tests/unit/framework/common/test_constants.py
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_control.py b/src/python/grpcio/tests/unit/framework/common/test_control.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/common/test_control.py
rename to src/python/grpcio/tests/unit/framework/common/test_control.py
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_coverage.py b/src/python/grpcio/tests/unit/framework/common/test_coverage.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/common/test_coverage.py
rename to src/python/grpcio/tests/unit/framework/common/test_coverage.py
diff --git a/src/python/grpcio_test/grpc_test/framework/core/__init__.py b/src/python/grpcio/tests/unit/framework/core/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/core/__init__.py
rename to src/python/grpcio/tests/unit/framework/core/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
similarity index 95%
rename from src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py
rename to src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
index 8d72f131d578c011d5b7b7418baf9d2963d04c39..13102923061fb35b2f34e6d8c1863a98e7e58625 100644
--- a/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py
+++ b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
@@ -36,9 +36,9 @@ import unittest
 
 from grpc.framework.core import implementations
 from grpc.framework.interfaces.base import utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import test_cases
-from grpc_test.framework.interfaces.base import test_interfaces
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.base import test_cases
+from tests.unit.framework.interfaces.base import test_interfaces
 
 
 class _Implementation(test_interfaces.Implementation):
diff --git a/src/python/grpcio_test/grpc_test/framework/face/__init__.py b/src/python/grpcio/tests/unit/framework/face/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/__init__.py
rename to src/python/grpcio/tests/unit/framework/face/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py b/src/python/grpcio/tests/unit/framework/face/testing/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py
rename to src/python/grpcio/tests/unit/framework/face/testing/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py
rename to src/python/grpcio/tests/unit/framework/face/testing/base_util.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
similarity index 96%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py
rename to src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
index 251e1eb68e29171c739dd3da59c5f06c7415f9d2..06135164215e1b2eba479fbda43fb3a20848ced4 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
@@ -34,12 +34,12 @@ import abc
 import unittest  # pylint: disable=unused-import
 
 from grpc.framework.face import exceptions
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.face.testing import control
-from grpc_test.framework.face.testing import coverage
-from grpc_test.framework.face.testing import digest
-from grpc_test.framework.face.testing import stock_service
-from grpc_test.framework.face.testing import test_case
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.face.testing import control
+from tests.unit.framework.face.testing import coverage
+from tests.unit.framework.face.testing import digest
+from tests.unit.framework.face.testing import stock_service
+from tests.unit.framework.face.testing import test_case
 
 
 class BlockingInvocationInlineServiceTestCase(
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/callback.py b/src/python/grpcio/tests/unit/framework/face/testing/callback.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/callback.py
rename to src/python/grpcio/tests/unit/framework/face/testing/callback.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/control.py b/src/python/grpcio/tests/unit/framework/face/testing/control.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/control.py
rename to src/python/grpcio/tests/unit/framework/face/testing/control.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py
rename to src/python/grpcio/tests/unit/framework/face/testing/coverage.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/digest.py
rename to src/python/grpcio/tests/unit/framework/face/testing/digest.py
index 54ff21779aef6b93148187d29e785d439c296325..39f28b9657f447e923743a8920d3df23d34f5c49 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
@@ -40,9 +40,9 @@ from grpc.framework.face import exceptions
 from grpc.framework.face import interfaces as face_interfaces
 from grpc.framework.foundation import stream
 from grpc.framework.foundation import stream_util
-from grpc_test.framework.face.testing import control as testing_control  # pylint: disable=unused-import
-from grpc_test.framework.face.testing import interfaces  # pylint: disable=unused-import
-from grpc_test.framework.face.testing import service as testing_service  # pylint: disable=unused-import
+from tests.unit.framework.face.testing import control as testing_control  # pylint: disable=unused-import
+from tests.unit.framework.face.testing import interfaces  # pylint: disable=unused-import
+from tests.unit.framework.face.testing import service as testing_service  # pylint: disable=unused-import
 
 _IDENTITY = lambda x: x
 
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
rename to src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
index 9df77678eb958e5aa7c552c7f9492aac048e142b..179f3a2f67c18c82c57f3eacbc9aea1426fbe87f 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
@@ -33,13 +33,13 @@ import abc
 import unittest
 
 from grpc.framework.face import interfaces
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.face.testing import callback as testing_callback
-from grpc_test.framework.face.testing import control
-from grpc_test.framework.face.testing import coverage
-from grpc_test.framework.face.testing import digest
-from grpc_test.framework.face.testing import stock_service
-from grpc_test.framework.face.testing import test_case
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.face.testing import callback as testing_callback
+from tests.unit.framework.face.testing import control
+from tests.unit.framework.face.testing import coverage
+from tests.unit.framework.face.testing import digest
+from tests.unit.framework.face.testing import stock_service
+from tests.unit.framework.face.testing import test_case
 
 
 class EventInvocationSynchronousEventServiceTestCase(
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
rename to src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
index 70d86a0422074ea2a2c54fd537821abe411b602e..485524a3563fb7509819967e9bfa04531df2cb2e 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
@@ -37,12 +37,12 @@ import unittest
 from grpc.framework.face import exceptions
 from grpc.framework.foundation import future
 from grpc.framework.foundation import logging_pool
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.face.testing import control
-from grpc_test.framework.face.testing import coverage
-from grpc_test.framework.face.testing import digest
-from grpc_test.framework.face.testing import stock_service
-from grpc_test.framework.face.testing import test_case
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.face.testing import control
+from tests.unit.framework.face.testing import coverage
+from tests.unit.framework.face.testing import digest
+from tests.unit.framework.face.testing import stock_service
+from tests.unit.framework.face.testing import test_case
 
 _MAXIMUM_POOL_SIZE = 10
 
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py
rename to src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/service.py b/src/python/grpcio/tests/unit/framework/face/testing/service.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/service.py
rename to src/python/grpcio/tests/unit/framework/face/testing/service.py
index ee9d6a3da3ecbc5633bef6019e23c206403c6af5..ac0b89b6eefdabed66b105de77f8d548b29e56ea 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/service.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/service.py
@@ -33,7 +33,7 @@ import abc
 
 # interfaces is referenced from specification in this module.
 from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
-from grpc_test.framework.face.testing import interfaces
+from tests.unit.framework.face.testing import interfaces
 
 
 class UnaryUnaryTestMethodImplementation(interfaces.Method):
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py
rename to src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
index 0f83ca4db13c4d8d1fab1b0f2e6c1a975f1a3399..117c723f79111f55535d06d71a280663371ba63b 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
@@ -33,8 +33,8 @@ from grpc.framework.common import cardinality
 from grpc.framework.foundation import abandonment
 from grpc.framework.foundation import stream
 from grpc.framework.foundation import stream_util
-from grpc_test.framework.face.testing import service
-from grpc_test._junkdrawer import stock_pb2
+from tests.unit.framework.face.testing import service
+from tests.unit._junkdrawer import stock_pb2
 
 SYMBOL_FORMAT = 'test symbol:%03d'
 STREAM_LENGTH = 400
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py
rename to src/python/grpcio/tests/unit/framework/face/testing/test_case.py
index 858d5cf7fdfae38112df9de3e7fe8f9420b503e2..23d4d919c2377ca7e3558a15368445f765445082 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
@@ -33,7 +33,7 @@ import abc
 
 # face_interfaces and interfaces are referenced in specification in this module.
 from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
-from grpc_test.framework.face.testing import interfaces  # pylint: disable=unused-import
+from tests.unit.framework.face.testing import interfaces  # pylint: disable=unused-import
 
 
 class FaceTestCase(object):
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/__init__.py b/src/python/grpcio/tests/unit/framework/foundation/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/foundation/__init__.py
rename to src/python/grpcio/tests/unit/framework/foundation/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py
rename to src/python/grpcio/tests/unit/framework/foundation/_later_test.py
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py
rename to src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py b/src/python/grpcio/tests/unit/framework/foundation/stream_testing.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py
rename to src/python/grpcio/tests/unit/framework/foundation/stream_testing.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py
rename to src/python/grpcio/tests/unit/framework/interfaces/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py
rename to src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
rename to src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
index 46a01876d831320e0fb399e1f1d1e7b8d2d0d0e3..38102b198a70fc3e2ef59c627f03e8fe5e6a2052 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
@@ -37,10 +37,10 @@ import threading
 import time
 
 from grpc.framework.interfaces.base import base
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import _sequence
-from grpc_test.framework.interfaces.base import _state
-from grpc_test.framework.interfaces.base import test_interfaces  # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.base import _sequence
+from tests.unit.framework.interfaces.base import _state
+from tests.unit.framework.interfaces.base import test_interfaces  # pylint: disable=unused-import
 
 _GROUP = 'base test cases test group'
 _METHOD = 'base test cases test method'
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
rename to src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py
index f547d916815908f29006e11f4a7b86f1374ef70d..571d0e1e632e14db535c53f9b4128c49eb0e8860 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py
@@ -33,7 +33,7 @@ import collections
 import enum
 
 from grpc.framework.interfaces.base import base
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
 
 
 class Invocation(
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_state.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py
rename to src/python/grpcio/tests/unit/framework/interfaces/base/_state.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
rename to src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
index ddda1018c34dd3ecdfc83e9da1138b2f19633ba6..4f8e26c9a26c986ffacf436228dde928b3407d21 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
@@ -38,9 +38,9 @@ import unittest
 from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.base import base
 from grpc.framework.interfaces.base import utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import _control
-from grpc_test.framework.interfaces.base import test_interfaces
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.base import _control
+from tests.unit.framework.interfaces.base import test_interfaces
 
 _SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True))
 
@@ -271,6 +271,7 @@ def test_cases(implementation):
                 '_randomness': randomness,
                 '_synchronicity_variation': synchronicity_variation[1],
                 '_controller_creator': controller_creator,
+                '__module__': implementation.__module__,
                }))
 
   return test_case_classes
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py
rename to src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
index 02426ab8460b6bc5cc3a3e5e3aaf3099aaacd180..84afd24d478a71f74c0c2493229e6f6a82626e9d 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
@@ -131,7 +131,7 @@ class Implementation(object):
 
   @abc.abstractmethod
   def service_initial_metadata(self):
-    """Provices an operation's service-side initial metadata.
+    """Provides an operation's service-side initial metadata.
 
     Returns:
       A value to use for an operation's service-side initial metadata, or
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py
similarity index 95%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py
index 363d9ce8f1c1f28e1dd2192de6eaaf9b6449eab9..1ea356c0bf25fbc1f2d0a8af043a8809fd0b9cac 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py
@@ -30,7 +30,7 @@
 """A test constant working around issue 3069."""
 
 # test_constants is referenced from specification in this module.
-from grpc_test.framework.common import test_constants  # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants  # pylint: disable=unused-import
 
 # TODO(issue 3069): Replace uses of this constant with
 # test_constants.SHORT_TIMEOUT.
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
similarity index 95%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
index 2d2a081955a114378943be5be8d16457096c89a3..3bcefa601d01bd18b830285fd30f23c34e4f8ec9 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
@@ -34,13 +34,13 @@ import unittest
 
 # test_interfaces is referenced from specification in this module.
 from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.common import test_control
-from grpc_test.framework.common import test_coverage
-from grpc_test.framework.interfaces.face import _3069_test_constant
-from grpc_test.framework.interfaces.face import _digest
-from grpc_test.framework.interfaces.face import _stock_service
-from grpc_test.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+from tests.unit.framework.common import test_coverage
+from tests.unit.framework.interfaces.face import _3069_test_constant
+from tests.unit.framework.interfaces.face import _digest
+from tests.unit.framework.interfaces.face import _stock_service
+from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 
 class TestCase(test_coverage.Coverage, unittest.TestCase):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
index da56ed7b2752b362067c300f134b73ac13f202bb..9304b6b1db13d7ad3e77ffa5c4014eb6714be8a2 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
@@ -39,9 +39,9 @@ from grpc.framework.common import style
 from grpc.framework.foundation import stream
 from grpc.framework.foundation import stream_util
 from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_control  # pylint: disable=unused-import
-from grpc_test.framework.interfaces.face import _service  # pylint: disable=unused-import
-from grpc_test.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
+from tests.unit.framework.common import test_control  # pylint: disable=unused-import
+from tests.unit.framework.interfaces.face import _service  # pylint: disable=unused-import
+from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 _IDENTITY = lambda x: x
 
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
similarity index 96%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
index 7cb273bf7873314d0fde090805e01087d60a55cc..34db6c3e55f47bb4a2b59ede6d04b40b70a383eb 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
@@ -34,14 +34,14 @@ import unittest
 
 # test_interfaces is referenced from specification in this module.
 from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.common import test_control
-from grpc_test.framework.common import test_coverage
-from grpc_test.framework.interfaces.face import _3069_test_constant
-from grpc_test.framework.interfaces.face import _digest
-from grpc_test.framework.interfaces.face import _receiver
-from grpc_test.framework.interfaces.face import _stock_service
-from grpc_test.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+from tests.unit.framework.common import test_coverage
+from tests.unit.framework.interfaces.face import _3069_test_constant
+from tests.unit.framework.interfaces.face import _digest
+from tests.unit.framework.interfaces.face import _receiver
+from tests.unit.framework.interfaces.face import _stock_service
+from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 
 class TestCase(test_coverage.Coverage, unittest.TestCase):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
similarity index 97%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
index 303273697558ef8203540ca0b29c38fc6fc250be..c178f2f1083fb06a665a742e0286b9f59fc0f994 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
@@ -37,13 +37,13 @@ import unittest
 # test_interfaces is referenced from specification in this module.
 from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.common import test_control
-from grpc_test.framework.common import test_coverage
-from grpc_test.framework.interfaces.face import _3069_test_constant
-from grpc_test.framework.interfaces.face import _digest
-from grpc_test.framework.interfaces.face import _stock_service
-from grpc_test.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+from tests.unit.framework.common import test_coverage
+from tests.unit.framework.interfaces.face import _3069_test_constant
+from tests.unit.framework.interfaces.face import _digest
+from tests.unit.framework.interfaces.face import _stock_service
+from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 
 class _PauseableIterator(object):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
index e25b8a038cc57c39bb04ee0b2fbd15f9da124898..28941e2ad0319c02a74b49668044f67419d1dbb3 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
@@ -33,7 +33,7 @@ import abc
 
 # face is referenced from specification in this module.
 from grpc.framework.interfaces.face import face  # pylint: disable=unused-import
-from grpc_test.framework.interfaces.face import test_interfaces
+from tests.unit.framework.interfaces.face import test_interfaces
 
 
 class UnaryUnaryTestMethodImplementation(test_interfaces.Method):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py
similarity index 98%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py
index 808e2c4e36a71213bbb21eec48185e0f3230e79f..5299655bb3b03264cb619e970904f2c901612b4b 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py
@@ -32,9 +32,9 @@
 from grpc.framework.common import cardinality
 from grpc.framework.foundation import abandonment
 from grpc.framework.foundation import stream
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import _service
-from grpc_test._junkdrawer import stock_pb2
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.face import _service
+from tests.unit._junkdrawer import stock_pb2
 
 _STOCK_GROUP_NAME = 'Stock'
 _SYMBOL_FORMAT = 'test symbol:%03d'
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
similarity index 82%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
index ca623662f7797b91378237b388c638a896c1428b..462829b66066880ff790986513264b56f14d96f8 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
@@ -33,11 +33,11 @@
 import unittest  # pylint: disable=unused-import
 
 # test_interfaces is referenced from specification in this module.
-from grpc_test.framework.interfaces.face import _blocking_invocation_inline_service
-from grpc_test.framework.interfaces.face import _event_invocation_synchronous_event_service
-from grpc_test.framework.interfaces.face import _future_invocation_asynchronous_event_service
-from grpc_test.framework.interfaces.face import _invocation
-from grpc_test.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
+from tests.unit.framework.interfaces.face import _blocking_invocation_inline_service
+from tests.unit.framework.interfaces.face import _event_invocation_synchronous_event_service
+from tests.unit.framework.interfaces.face import _future_invocation_asynchronous_event_service
+from tests.unit.framework.interfaces.face import _invocation
+from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 _TEST_CASE_SUPERCLASSES = (
     _blocking_invocation_inline_service.TestCase,
@@ -63,5 +63,7 @@ def test_cases(implementation):
       test_case_classes.append(
           type(invoker_constructor.name() + super_class.NAME, (super_class,),
                {'implementation': implementation,
-                'invoker_constructor': invoker_constructor}))
+                'invoker_constructor': invoker_constructor,
+                '__module__': implementation.__module__,
+               }))
   return test_case_classes
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py
rename to src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py
rename to src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
similarity index 99%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
rename to src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
index ecf49d9cdb54cdefb654687d8bb90ca6ab5b9fb9..dace6c23f3f0b9b50f41caa391f9e4fdf6aded53 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
@@ -34,8 +34,8 @@ import abc
 import unittest  # pylint: disable=unused-import
 
 from grpc.framework.interfaces.links import links
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.links import test_utilities
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.links import test_utilities
 
 
 def at_least_n_payloads_received_predicate(n):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py
rename to src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py
diff --git a/src/python/grpcio_test/grpc_test/resources.py b/src/python/grpcio/tests/unit/resources.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/resources.py
rename to src/python/grpcio/tests/unit/resources.py
diff --git a/src/python/grpcio_test/grpc_test/test_common.py b/src/python/grpcio/tests/unit/test_common.py
similarity index 100%
rename from src/python/grpcio_test/grpc_test/test_common.py
rename to src/python/grpcio/tests/unit/test_common.py
diff --git a/src/python/grpcio/tox.ini b/src/python/grpcio/tox.ini
new file mode 100644
index 0000000000000000000000000000000000000000..bfb1ca0cfada221126fd49fdf7b560d9d5cded8b
--- /dev/null
+++ b/src/python/grpcio/tox.ini
@@ -0,0 +1,19 @@
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+skipsdist = true
+envlist = py27
+
+[testenv]
+commands =
+    {envpython} setup.py build_py
+    {envpython} setup.py test
+    coverage combine
+    coverage html --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py'
+    coverage report --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py'
+deps =
+    -rrequirements.txt
+passenv = *
diff --git a/src/python/grpcio_test/.gitignore b/src/python/grpcio_test/.gitignore
deleted file mode 100644
index 6158313bde0c9613594b01ffbf1ab3c8254cc4bb..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-MANIFEST
-*.egg-info/
-build/
-dist/
-*.egg
-*.egg/
-*.eggs/
-*_pb2.py
-.coverage
-.coverage.*
-.cache/
-nosetests.xml
diff --git a/src/python/grpcio_test/MANIFEST.in b/src/python/grpcio_test/MANIFEST.in
deleted file mode 100644
index c9327307dc5fe0624329ba16cd3cd5ae0f2792db..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/MANIFEST.in
+++ /dev/null
@@ -1,4 +0,0 @@
-graft grpc_interop
-graft grpc_test
-include commands.py
-include requirements.txt
diff --git a/src/python/grpcio_test/commands.py b/src/python/grpcio_test/commands.py
deleted file mode 100644
index edaa2aa72db94666b812b23bc03c99753278fb3f..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/commands.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Provides distutils command classes for the GRPC Python test setup process."""
-
-import distutils
-import os
-import os.path
-import subprocess
-import sys
-
-import setuptools
-from setuptools.command import build_py
-
-
-class RunTests(setuptools.Command):
-  """Command to run all tests via py.test."""
-
-  description = ''
-  user_options = [('pytest-args=', 'a', 'arguments to pass to py.test')]
-
-  def initialize_options(self):
-    self.pytest_args = []
-
-  def finalize_options(self):
-    pass
-
-  def run(self):
-    # We import here to ensure that setup.py has had a chance to install the
-    # relevant package eggs first.
-    import pytest
-
-    self.run_command('build_proto_modules')
-    result = pytest.main(self.pytest_args)
-    if result != 0:
-      raise SystemExit(result)
-
-
-class BuildProtoModules(setuptools.Command):
-  """Command to generate project *_pb2.py modules from proto files."""
-
-  description = ''
-  user_options = []
-
-  def initialize_options(self):
-    pass
-
-  def finalize_options(self):
-    self.protoc_command = distutils.spawn.find_executable('protoc')
-    self.grpc_python_plugin_command = distutils.spawn.find_executable(
-        'grpc_python_plugin')
-
-  def run(self):
-    paths = []
-    root_directory = os.getcwd()
-    for walk_root, directories, filenames in os.walk(root_directory):
-      for filename in filenames:
-        if filename.endswith('.proto'):
-          paths.append(os.path.join(walk_root, filename))
-    command = [
-        self.protoc_command,
-        '--plugin=protoc-gen-python-grpc={}'.format(
-            self.grpc_python_plugin_command),
-        '-I {}'.format(root_directory),
-        '--python_out={}'.format(root_directory),
-        '--python-grpc_out={}'.format(root_directory),
-    ] + paths
-    try:
-      subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
-                              stderr=subprocess.STDOUT)
-    except subprocess.CalledProcessError as e:
-      raise Exception('{}\nOutput:\n{}'.format(e.message, e.output))
-
-
-class BuildPy(build_py.build_py):
-  """Custom project build command."""
-
-  def run(self):
-    self.run_command('build_proto_modules')
-    build_py.build_py.run(self)
diff --git a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py b/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py
deleted file mode 100644
index f1bec238cf5503eb8411a43dcf91b765a07ab7c0..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Fork of grpc._adapter._low_test; the grpc._cython.types adapter in
-# grpc._cython.low should transparently support the semantics expected of
-# grpc._adapter._low.
-
-import time
-import unittest
-
-from grpc._adapter import _types
-from grpc._cython import adapter_low as _low
-
-
-class InsecureServerInsecureClient(unittest.TestCase):
-
-  def setUp(self):
-    self.server_completion_queue = _low.CompletionQueue()
-    self.server = _low.Server(self.server_completion_queue, [])
-    self.port = self.server.add_http2_port('[::]:0')
-    self.client_completion_queue = _low.CompletionQueue()
-    self.client_channel = _low.Channel('localhost:%d'%self.port, [])
-
-    self.server.start()
-
-  def tearDown(self):
-    self.server.shutdown()
-    del self.client_channel
-
-    self.client_completion_queue.shutdown()
-    while (self.client_completion_queue.next().type !=
-               _types.EventType.QUEUE_SHUTDOWN):
-      pass
-    self.server_completion_queue.shutdown()
-    while (self.server_completion_queue.next().type !=
-               _types.EventType.QUEUE_SHUTDOWN):
-      pass
-
-    del self.client_completion_queue
-    del self.server_completion_queue
-    del self.server
-
-  @unittest.skip('TODO(atash): implement grpc._cython.adapter_low')
-  def testEcho(self):
-    DEADLINE = time.time()+5
-    DEADLINE_TOLERANCE = 0.25
-    CLIENT_METADATA_ASCII_KEY = 'key'
-    CLIENT_METADATA_ASCII_VALUE = 'val'
-    CLIENT_METADATA_BIN_KEY = 'key-bin'
-    CLIENT_METADATA_BIN_VALUE = b'\0'*1000
-    SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
-    SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
-    SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought'
-    SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
-    SERVER_STATUS_CODE = _types.StatusCode.OK
-    SERVER_STATUS_DETAILS = 'our work is never over'
-    REQUEST = 'in death a member of project mayhem has a name'
-    RESPONSE = 'his name is robert paulson'
-    METHOD = 'twinkies'
-    HOST = 'hostess'
-    server_request_tag = object()
-    request_call_result = self.server.request_call(self.server_completion_queue,
-                                                   server_request_tag)
-
-    self.assertEqual(_types.CallError.OK, request_call_result)
-
-    client_call_tag = object()
-    client_call = self.client_channel.create_call(self.client_completion_queue,
-                                                  METHOD, HOST, DEADLINE)
-    client_initial_metadata = [
-        (CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE),
-        (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]
-    client_start_batch_result = client_call.start_batch([
-        _types.OpArgs.send_initial_metadata(client_initial_metadata),
-        _types.OpArgs.send_message(REQUEST),
-        _types.OpArgs.send_close_from_client(),
-        _types.OpArgs.recv_initial_metadata(),
-        _types.OpArgs.recv_message(),
-        _types.OpArgs.recv_status_on_client()
-    ], client_call_tag)
-    self.assertEqual(_types.CallError.OK, client_start_batch_result)
-
-    request_event = self.server_completion_queue.next(DEADLINE)
-    self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type)
-    self.assertIsInstance(request_event.call, _low.Call)
-    self.assertIs(server_request_tag, request_event.tag)
-    self.assertEqual(1, len(request_event.results))
-    self.assertEqual(dict(client_initial_metadata),
-                      dict(request_event.results[0].initial_metadata))
-    self.assertEqual(METHOD, request_event.call_details.method)
-    self.assertEqual(HOST, request_event.call_details.host)
-    self.assertLess(abs(DEADLINE - request_event.call_details.deadline),
-                    DEADLINE_TOLERANCE)
-
-    server_call_tag = object()
-    server_call = request_event.call
-    server_initial_metadata = [
-        (SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]
-    server_trailing_metadata = [
-        (SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)]
-    server_start_batch_result = server_call.start_batch([
-        _types.OpArgs.send_initial_metadata(server_initial_metadata),
-        _types.OpArgs.recv_message(),
-        _types.OpArgs.send_message(RESPONSE),
-        _types.OpArgs.recv_close_on_server(),
-        _types.OpArgs.send_status_from_server(
-            server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
-    ], server_call_tag)
-    self.assertEqual(_types.CallError.OK, server_start_batch_result)
-
-    client_event = self.client_completion_queue.next(DEADLINE)
-    server_event = self.server_completion_queue.next(DEADLINE)
-
-    self.assertEqual(6, len(client_event.results))
-    found_client_op_types = set()
-    for client_result in client_event.results:
-      # we expect each op type to be unique
-      self.assertNotIn(client_result.type, found_client_op_types)
-      found_client_op_types.add(client_result.type)
-      if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
-        self.assertEqual(dict(server_initial_metadata),
-                          dict(client_result.initial_metadata))
-      elif client_result.type == _types.OpType.RECV_MESSAGE:
-        self.assertEqual(RESPONSE, client_result.message)
-      elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
-        self.assertEqual(dict(server_trailing_metadata),
-                          dict(client_result.trailing_metadata))
-        self.assertEqual(SERVER_STATUS_DETAILS, client_result.status.details)
-        self.assertEqual(SERVER_STATUS_CODE, client_result.status.code)
-    self.assertEqual(set([
-          _types.OpType.SEND_INITIAL_METADATA,
-          _types.OpType.SEND_MESSAGE,
-          _types.OpType.SEND_CLOSE_FROM_CLIENT,
-          _types.OpType.RECV_INITIAL_METADATA,
-          _types.OpType.RECV_MESSAGE,
-          _types.OpType.RECV_STATUS_ON_CLIENT
-      ]), found_client_op_types)
-
-    self.assertEqual(5, len(server_event.results))
-    found_server_op_types = set()
-    for server_result in server_event.results:
-      self.assertNotIn(client_result.type, found_server_op_types)
-      found_server_op_types.add(server_result.type)
-      if server_result.type == _types.OpType.RECV_MESSAGE:
-        self.assertEqual(REQUEST, server_result.message)
-      elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
-        self.assertFalse(server_result.cancelled)
-    self.assertEqual(set([
-          _types.OpType.SEND_INITIAL_METADATA,
-          _types.OpType.RECV_MESSAGE,
-          _types.OpType.SEND_MESSAGE,
-          _types.OpType.RECV_CLOSE_ON_SERVER,
-          _types.OpType.SEND_STATUS_FROM_SERVER
-      ]), found_server_op_types)
-
-    del client_call
-    del server_call
-
-
-if __name__ == '__main__':
-  unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/conftest.py b/src/python/grpcio_test/grpc_test/conftest.py
deleted file mode 100644
index 357320ec64bfd3137491f5fd8f1ad5eacc34c033..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/grpc_test/conftest.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import types
-import unittest
-
-import pytest
-
-
-class LoadTestsSuiteCollector(pytest.Collector):
-
-  def __init__(self, name, parent, suite):
-    super(LoadTestsSuiteCollector, self).__init__(name, parent=parent)
-    self.suite = suite
-    self.obj = suite
-
-  def collect(self):
-    collected = []
-    for case in self.suite:
-      if isinstance(case, unittest.TestCase):
-        collected.append(LoadTestsCase(case.id(), self, case))
-      elif isinstance(case, unittest.TestSuite):
-        collected.append(
-            LoadTestsSuiteCollector('suite_child_of_mine', self, case))
-    return collected
-
-  def reportinfo(self):
-    return str(self.suite)
-
-
-class LoadTestsCase(pytest.Function):
-
-  def __init__(self, name, parent, item):
-    super(LoadTestsCase, self).__init__(name, parent, callobj=self._item_run)
-    self.item = item
-
-  def _item_run(self):
-    result = unittest.TestResult()
-    self.item(result)
-    if result.failures:
-      test_method, trace = result.failures[0]
-      pytest.fail(trace, False)
-    elif result.errors:
-      test_method, trace = result.errors[0]
-      pytest.fail(trace, False)
-    elif result.skipped:
-      test_method, reason = result.skipped[0]
-      pytest.skip(reason)
-
-
-def pytest_pycollect_makeitem(collector, name, obj):
-  if name == 'load_tests' and isinstance(obj, types.FunctionType):
-    suite = unittest.TestSuite()
-    loader = unittest.TestLoader()
-    pattern = '*'
-    try:
-      # Check that the 'load_tests' object is actually a callable that actually
-      # accepts the arguments expected for the load_tests protocol.
-      suite = obj(loader, suite, pattern)
-    except Exception as e:
-      return None
-    else:
-      return LoadTestsSuiteCollector(name, collector, suite)
diff --git a/src/python/grpcio_test/requirements.txt b/src/python/grpcio_test/requirements.txt
deleted file mode 100644
index fea80ca07f1ad687686af5859cea20cf18106341..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-grpcio>=0.11.0b0
-oauth2client>=1.4.7
-protobuf>=3.0.0a3
-pytest>=2.6
-pytest-cov>=2.0
-pytest-xdist>=1.11
diff --git a/src/python/grpcio_test/setup.cfg b/src/python/grpcio_test/setup.cfg
deleted file mode 100644
index 3be93cb918916fb700ba2818f202296dc327c62c..0000000000000000000000000000000000000000
--- a/src/python/grpcio_test/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[pytest]
-python_files = *_test.py
diff --git a/src/ruby/bin/math.proto b/src/ruby/bin/math.proto
deleted file mode 100755
index 311e148c021f66a8ed450e8258c60961314f546f..0000000000000000000000000000000000000000
--- a/src/ruby/bin/math.proto
+++ /dev/null
@@ -1,80 +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.
-
-syntax = "proto3";
-
-package math;
-
-message DivArgs {
-  int64 dividend = 1;
-  int64 divisor = 2;
-}
-
-message DivReply {
-  int64 quotient = 1;
-  int64 remainder = 2;
-}
-
-message FibArgs {
-  int64 limit = 1;
-}
-
-message Num {
-  int64 num = 1;
-}
-
-message FibReply {
-  int64 count = 1;
-}
-
-service Math {
-  // Div divides args.dividend by args.divisor and returns the quotient and
-  // remainder.
-  rpc Div (DivArgs) returns (DivReply) {
-  }
-
-  // DivMany accepts an arbitrary number of division args from the client stream
-  // and sends back the results in the reply stream.  The stream continues until
-  // the client closes its end; the server does the same after sending all the
-  // replies.  The stream ends immediately if either end aborts.
-  rpc DivMany (stream DivArgs) returns (stream DivReply) {
-  }
-
-  // Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
-  // generates up to limit numbers; otherwise it continues until the call is
-  // canceled.  Unlike Fib above, Fib has no final FibReply.
-  rpc Fib (FibArgs) returns (stream Num) {
-  }
-
-  // Sum sums a stream of numbers, returning the final result once the stream
-  // is closed.
-  rpc Sum (stream Num) returns (Num) {
-  }
-}
diff --git a/src/ruby/bin/math.rb b/src/ruby/bin/math.rb
index 323993ed439e9cbd46668ac14180583de26ea174..60429a15052e2e378d8c1e8d7d2b06879eaa63e5 100755
--- a/src/ruby/bin/math.rb
+++ b/src/ruby/bin/math.rb
@@ -1,32 +1,3 @@
-# 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.
-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: math.proto
 
diff --git a/src/ruby/bin/math_services.rb b/src/ruby/bin/math_services.rb
index cf58a53913fa970f4902da61102e5feffbae3ba2..2d482129c2afa1dca6d4962951d2f26aebc63c58 100755
--- a/src/ruby/bin/math_services.rb
+++ b/src/ruby/bin/math_services.rb
@@ -1,32 +1,3 @@
-# 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.
-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # Source: math.proto for package 'math'
 
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 61cf18cf549167c0784a8095d1dfeaec847ca598..363abe9a46322bdbe27614cb25eb2f8c2bdf2794 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
   s.add_development_dependency 'rake-compiler', '~> 0.9'
   s.add_development_dependency 'rspec', '~> 3.2'
   s.add_development_dependency 'rubocop', '~> 0.30.0'
+  s.add_development_dependency 'signet', '~>0.6.0'
 
   s.extensions = %w(ext/grpc/extconf.rb)
 end
diff --git a/src/ruby/pb/README.md b/src/ruby/pb/README.md
index 84644e1098896e2c0ae5b9bb22cbc9dab18bf8fa..e04aef185caaa51720922dbd73e02c82da147450 100644
--- a/src/ruby/pb/README.md
+++ b/src/ruby/pb/README.md
@@ -20,7 +20,7 @@ re-generate the surface.
 
 ```bash
 $ # (from this directory)
-$ protoc -I . grpc/health/v1alpha/health.proto \
+$ protoc -I ../../proto ../../proto/grpc/health/v1alpha/health.proto \
     --grpc_out=. \
     --ruby_out=. \
     --plugin=protoc-gen-grpc=`which grpc_ruby_plugin`
diff --git a/src/python/grpcio_test/setup.py b/src/ruby/pb/generate_proto_ruby.sh
old mode 100644
new mode 100755
similarity index 51%
rename from src/python/grpcio_test/setup.py
rename to src/ruby/pb/generate_proto_ruby.sh
index e9ee45a92a46de95f709765737d76a58c122e270..576b1c08d300f0a1bf97388a38ae71e18b91524f
--- a/src/python/grpcio_test/setup.py
+++ b/src/ruby/pb/generate_proto_ruby.sh
@@ -1,3 +1,4 @@
+#!/bin/sh
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -27,68 +28,24 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""A setup module for the GRPC Python interop testing package."""
+# Regenerates gRPC service stubs from proto files.
+set +e
+cd $(dirname $0)/../../..
 
-import os
-import os.path
+PROTOC=bins/opt/protobuf/protoc
+PLUGIN=protoc-gen-grpc=bins/opt/grpc_ruby_plugin
 
-import setuptools
+$PROTOC -I src/proto src/proto/grpc/health/v1alpha/health.proto \
+    --grpc_out=src/ruby/pb \
+    --ruby_out=src/ruby/pb \
+    --plugin=$PLUGIN
 
-# Ensure we're in the proper directory whether or not we're being used by pip.
-os.chdir(os.path.dirname(os.path.abspath(__file__)))
+$PROTOC -I . test/proto/{messages,test,empty}.proto \
+    --grpc_out=src/ruby/pb \
+    --ruby_out=src/ruby/pb \
+    --plugin=$PLUGIN
 
-# Break import-style to ensure we can actually find our commands module.
-import commands
-
-_PACKAGES = setuptools.find_packages('.')
-
-_PACKAGE_DIRECTORIES = {
-    '': '.',
-}
-
-_PACKAGE_DATA = {
-    'grpc_interop': [
-        'credentials/ca.pem',
-        'credentials/server1.key',
-        'credentials/server1.pem',
-    ],
-    'grpc_protoc_plugin': [
-        'test.proto',
-    ],
-    'grpc_test': [
-        'credentials/ca.pem',
-        'credentials/server1.key',
-        'credentials/server1.pem',
-    ],
-}
-
-_SETUP_REQUIRES = (
-    'pytest>=2.6',
-    'pytest-cov>=2.0',
-    'pytest-xdist>=1.11',
-    'pytest-timeout>=0.5',
-)
-
-_INSTALL_REQUIRES = (
-    'oauth2client>=1.4.7',
-    'grpcio>=0.11.0b0',
-    # TODO(issue 3321): Unpin protobuf dependency.
-    'protobuf==3.0.0a3',
-)
-
-_COMMAND_CLASS = {
-    'test': commands.RunTests,
-    'build_proto_modules': commands.BuildProtoModules,
-    'build_py': commands.BuildPy,
-}
-
-setuptools.setup(
-    name='grpcio_test',
-    version='0.11.0b0',
-    packages=_PACKAGES,
-    package_dir=_PACKAGE_DIRECTORIES,
-    package_data=_PACKAGE_DATA,
-    install_requires=_INSTALL_REQUIRES + _SETUP_REQUIRES,
-    setup_requires=_SETUP_REQUIRES,
-    cmdclass=_COMMAND_CLASS,
-)
+$PROTOC -I src/proto/math src/proto/math/math.proto \
+    --grpc_out=src/ruby/bin \
+    --ruby_out=src/ruby/bin \
+    --plugin=$PLUGIN
diff --git a/src/ruby/pb/test/proto/messages.rb b/src/ruby/pb/test/proto/messages.rb
index 9b7f97728599005b364454e7000e9d6c28ed7bcf..5222c9824a7e28a9ba4ac3d9ab088c888772a2bd 100644
--- a/src/ruby/pb/test/proto/messages.rb
+++ b/src/ruby/pb/test/proto/messages.rb
@@ -6,7 +6,7 @@ require 'google/protobuf'
 Google::Protobuf::DescriptorPool.generated_pool.build do
   add_message "grpc.testing.Payload" do
     optional :type, :enum, 1, "grpc.testing.PayloadType"
-    optional :body, :string, 2
+    optional :body, :bytes, 2
   end
   add_message "grpc.testing.EchoStatus" do
     optional :code, :int32, 1
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 20d14c797f99600c7696bf0e89780f8061aab38e..c1e472c00e715305a6328e5202e61128f5bd3c8f 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -205,9 +205,9 @@
   CXX_gcov = g++
   LD_gcov = gcc
   LDXX_gcov = g++
-  CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage
+  CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
   LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
-  DEFINES_gcov = _DEBUG DEBUG
+  DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
 
 
   # General settings.
diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template
index de5ed7cd8c3f9da8df49c0ac083836a0d91452dd..67fc8f66025747484c12796e90c85f5d245f799f 100644
--- a/templates/gRPC.podspec.template
+++ b/templates/gRPC.podspec.template
@@ -97,7 +97,7 @@
 
       ss.requires_arc = false
       ss.libraries = 'z'
-      ss.dependency 'OpenSSL', '~> 1.0.204.1'
+      ss.dependency 'BoringSSL', '~> 1.0'
 
       # ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
     end
diff --git a/test/core/bad_client/gen_build_yaml.py b/test/core/bad_client/gen_build_yaml.py
index 3df889ecdaf2ec0c0ed0d0b0a8a86ad0c474b07c..bdb0176ba9712b4c23d25d9d9b15b6f3de0f88d2 100755
--- a/test/core/bad_client/gen_build_yaml.py
+++ b/test/core/bad_client/gen_build_yaml.py
@@ -41,7 +41,9 @@ default_test_options = TestOptions(False)
 # maps test names to options
 BAD_CLIENT_TESTS = {
     'connection_prefix': default_test_options,
+    'headers': default_test_options,
     'initial_settings_frame': default_test_options,
+    'unknown_frame': default_test_options,
 }
 
 def main():
diff --git a/test/core/bad_client/tests/headers.c b/test/core/bad_client/tests/headers.c
new file mode 100644
index 0000000000000000000000000000000000000000..5547aca210dbffc090760fddb8dee60082e15583
--- /dev/null
+++ b/test/core/bad_client/tests/headers.c
@@ -0,0 +1,221 @@
+/*
+ *
+ * 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 "test/core/bad_client/bad_client.h"
+#include "src/core/surface/server.h"
+
+#define PFX_STR                      \
+  "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
+  "\x00\x00\x00\x04\x00\x00\x00\x00\x00"
+
+static void verifier(grpc_server *server, grpc_completion_queue *cq) {
+  while (grpc_server_has_open_connections(server)) {
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
+  }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  /* partial http2 header prefixes */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01\x04",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01\x05",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01\x04\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01\x04\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR "\x00\x00\x00\x01\x04\x00\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR "\x00\x00\x00\x01\x04\x00\x00\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR "\x00\x00\x00\x01\x04\x00\x00\x00\x01",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+
+  /* test adding prioritization data */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x01\x01\x24\x00\x00\x00\x01"
+                           "\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x02\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x03\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x04\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00\x00\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x05\x01\x24\x00\x00\x00\x01"
+                           "\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x05\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x05\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x05\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x05\x01\x24\x00\x00\x00\x01"
+                           "\x00\x00\x00\x00\x00",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+
+  /* test looking up an invalid index */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x01\x01\x04\x00\x00\x00\x01"
+                           "\xfe",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x04\x01\x04\x00\x00\x00\x01"
+                           "\x7f\x7f\x01""a",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x04\x01\x04\x00\x00\x00\x01"
+                           "\x0f\x7f\x01""a",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x04\x01\x04\x00\x00\x00\x01"
+                           "\x1f\x7f\x01""a",
+                           0);
+  /* test nvr, not indexed in static table */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x03\x01\x04\x00\x00\x00\x01"
+                           "\x01\x01""a",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x03\x01\x04\x00\x00\x00\x01"
+                           "\x11\x01""a",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  /* illegal op code */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x01\x01\x04\x00\x00\x00\x01"
+                           "\x80",
+                           0);
+  /* parse some long indices */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x02\x01\x04\x00\x00\x00\x01"
+                           "\xff\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x03\x01\x04\x00\x00\x00\x01"
+                           "\xff\x80\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x04\x01\x04\x00\x00\x00\x01"
+                           "\xff\x80\x80\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x05\x01\x04\x00\x00\x00\x01"
+                           "\xff\x80\x80\x80\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x06\x01\x04\x00\x00\x00\x01"
+                           "\xff\x80\x80\x80\x80\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x07\x01\x04\x00\x00\x00\x01"
+                           "\xff\x80\x80\x80\x80\x80\x00",
+                           0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x08\x01\x04\x00\x00\x00\x01"
+                           "\xff\x80\x80\x80\x80\x80\x80\x00",
+                           0);
+  /* end of headers mid-opcode */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x01\x01\x04\x00\x00\x00\x01"
+                           "\x01",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+
+  /* dynamic table size update: set to default */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR 
+                           "\x00\x00\x03\x01\x04\x00\x00\x00\x01"
+                           "\x3f\xe1\x1f",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR 
+                           "\x00\x00\x03\x01\x04\x00\x00\x00\x01"
+                           "\x3f\xf1\x1f",
+                           0);
+
+  /* non-ending header followed by continuation frame */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR 
+                           "\x00\x00\x00\x01\x00\x00\x00\x00\x01"
+                           "\x00\x00\x00\x09\x04\x00\x00\x00\x01",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+  /* non-ending header followed by non-continuation frame */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR 
+                           "\x00\x00\x00\x01\x00\x00\x00\x00\x01"
+                           "\x00\x00\x00\x00\x04\x00\x00\x00\x01",
+                           0);
+  /* opening with a continuation frame */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR 
+                           "\x00\x00\x00\x09\x04\x00\x00\x00\x01",
+                           0);
+
+  /* an invalid header found with fuzzing */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR 
+                           "\x00\x00\x00\x01\x39\x67\xed\x1d\x64",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+
+  return 0;
+}
diff --git a/test/core/bad_client/tests/initial_settings_frame.c b/test/core/bad_client/tests/initial_settings_frame.c
index 827e93b67c70ae1c90cf004d840788d681ec6920..6ed15bbed1459b0bc90f689a60114834d213a88b 100644
--- a/test/core/bad_client/tests/initial_settings_frame.c
+++ b/test/core/bad_client/tests/initial_settings_frame.c
@@ -35,6 +35,7 @@
 #include "src/core/surface/server.h"
 
 #define PFX_STR "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+#define ONE_SETTING_HDR "\x00\x00\x06\x04\x00\x00\x00\x00\x00"
 
 static void verifier(grpc_server *server, grpc_completion_queue *cq) {
   while (grpc_server_has_open_connections(server)) {
@@ -90,6 +91,10 @@ int main(int argc, char **argv) {
                            PFX_STR "\x00\x00\x04\x04\x00\x00\x00\x00\x00", 0);
   GRPC_RUN_BAD_CLIENT_TEST(verifier,
                            PFX_STR "\x00\x00\x05\x04\x00\x00\x00\x00\x00", 0);
+  /* some settings values are illegal */
+  /* max frame size = 0 */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier,
+                           PFX_STR ONE_SETTING_HDR "\x00\x05\x00\x00\x00\x00", GRPC_BAD_CLIENT_DISCONNECT);
 
   return 0;
 }
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.c b/test/core/bad_client/tests/unknown_frame.c
similarity index 67%
rename from src/python/grpcio/grpc/_adapter/_c/types.c
rename to test/core/bad_client/tests/unknown_frame.c
index 8dedf5902b32d47cf41d9ff5bf97a233d16bfd98..8ea81390c941c5242f9ecea507dc4f556d559865 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types.c
+++ b/test/core/bad_client/tests/unknown_frame.c
@@ -31,31 +31,28 @@
  *
  */
 
-#include "grpc/_adapter/_c/types.h"
+#include "test/core/bad_client/bad_client.h"
+#include "src/core/surface/server.h"
 
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
+#define PFX_STR                      \
+  "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
+  "\x00\x00\x00\x04\x00\x00\x00\x00\x00"
 
-int pygrpc_module_add_types(PyObject *module) {
-  int i;
-  PyTypeObject *types[] = {
-      &pygrpc_CallCredentials_type,
-      &pygrpc_ChannelCredentials_type,
-      &pygrpc_ServerCredentials_type,
-      &pygrpc_CompletionQueue_type,
-      &pygrpc_Call_type,
-      &pygrpc_Channel_type,
-      &pygrpc_Server_type
-  };
-  for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
-    if (PyType_Ready(types[i]) < 0) {
-      return -1;
-    }
-  }
-  for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
-    Py_INCREF(types[i]);
-    PyModule_AddObject(module, types[i]->tp_name, (PyObject *)types[i]);
+static void verifier(grpc_server *server, grpc_completion_queue *cq) {
+  while (grpc_server_has_open_connections(server)) {
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  /* test adding prioritization data */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, PFX_STR
+                           "\x00\x00\x00\x88\x00\x00\x00\x00\x01",
+                           GRPC_BAD_CLIENT_DISCONNECT);
+
   return 0;
 }
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..58aeef18f725e78630686b6e48187a461e897bdf
--- /dev/null
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -0,0 +1,558 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <limits.h>
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+static void *tag(gpr_intptr i) { return (void *)i; }
+
+struct test_state {
+  int is_client;
+  grpc_channel *chan;
+  grpc_call *call;
+  gpr_timespec deadline;
+  grpc_completion_queue *cq;
+  cq_verifier *cqv;
+  grpc_op ops[6];
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_status_code status;
+  char *details;
+  size_t details_capacity;
+  grpc_call *server_call;
+  grpc_server *server;
+  grpc_metadata_array server_initial_metadata_recv;
+  grpc_call_details call_details;
+};
+
+static struct test_state g_state;
+
+static void prepare_test(int is_client) {
+  int port;
+  char *server_hostport;
+  grpc_op *op;
+  g_state.is_client = is_client;
+  grpc_metadata_array_init(&g_state.initial_metadata_recv);
+  grpc_metadata_array_init(&g_state.trailing_metadata_recv);
+  g_state.deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2);
+  g_state.cq = grpc_completion_queue_create(NULL);
+  g_state.cqv = cq_verifier_create(g_state.cq);
+  g_state.details = NULL;
+  g_state.details_capacity = 0;
+
+  if (is_client) {
+    /* create a call, channel to a non existant server */
+    g_state.chan =
+        grpc_insecure_channel_create("nonexistant:54321", NULL, NULL);
+    g_state.call = grpc_channel_create_call(
+        g_state.chan, NULL, GRPC_PROPAGATE_DEFAULTS, g_state.cq, "/Foo",
+        "nonexistant", g_state.deadline, NULL);
+  } else {
+    g_state.server = grpc_server_create(NULL, NULL);
+    grpc_server_register_completion_queue(g_state.server, g_state.cq, NULL);
+    port = grpc_pick_unused_port_or_die();
+    gpr_join_host_port(&server_hostport, "0.0.0.0", port);
+    grpc_server_add_insecure_http2_port(g_state.server, server_hostport);
+    grpc_server_start(g_state.server);
+    gpr_free(server_hostport);
+    gpr_join_host_port(&server_hostport, "localhost", port);
+    g_state.chan = grpc_insecure_channel_create(server_hostport, NULL, NULL);
+    gpr_free(server_hostport);
+    g_state.call = grpc_channel_create_call(
+        g_state.chan, NULL, GRPC_PROPAGATE_DEFAULTS, g_state.cq, "/Foo", "bar",
+        g_state.deadline, NULL);
+    grpc_metadata_array_init(&g_state.server_initial_metadata_recv);
+    grpc_call_details_init(&g_state.call_details);
+    op = g_state.ops;
+    op->op = GRPC_OP_SEND_INITIAL_METADATA;
+    op->data.send_initial_metadata.count = 0;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                     (size_t)(op - g_state.ops),
+                                                     tag(1), NULL));
+    GPR_ASSERT(GRPC_CALL_OK ==
+               grpc_server_request_call(g_state.server, &g_state.server_call,
+                                        &g_state.call_details,
+                                        &g_state.server_initial_metadata_recv,
+                                        g_state.cq, g_state.cq, tag(101)));
+    cq_expect_completion(g_state.cqv, tag(101), 1);
+    cq_expect_completion(g_state.cqv, tag(1), 1);
+    cq_verify(g_state.cqv);
+  }
+}
+
+static void cleanup_test() {
+  grpc_call_destroy(g_state.call);
+  cq_verifier_destroy(g_state.cqv);
+  grpc_channel_destroy(g_state.chan);
+  gpr_free(g_state.details);
+  grpc_metadata_array_destroy(&g_state.initial_metadata_recv);
+  grpc_metadata_array_destroy(&g_state.trailing_metadata_recv);
+
+  if (!g_state.is_client) {
+    grpc_call_destroy(g_state.server_call);
+    grpc_server_shutdown_and_notify(g_state.server, g_state.cq, tag(1000));
+    GPR_ASSERT(grpc_completion_queue_pluck(g_state.cq, tag(1000),
+                                           GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                           NULL)
+                   .type == GRPC_OP_COMPLETE);
+    grpc_server_destroy(g_state.server);
+    grpc_call_details_destroy(&g_state.call_details);
+    grpc_metadata_array_destroy(&g_state.server_initial_metadata_recv);
+  }
+  grpc_completion_queue_shutdown(g_state.cq);
+  while (grpc_completion_queue_next(g_state.cq,
+                                    gpr_inf_future(GPR_CLOCK_REALTIME), NULL)
+             .type != GRPC_QUEUE_SHUTDOWN)
+    ;
+  grpc_completion_queue_destroy(g_state.cq);
+}
+
+static void test_non_null_reserved_on_start_batch() {
+  prepare_test(1);
+  GPR_ASSERT(GRPC_CALL_ERROR ==
+             grpc_call_start_batch(g_state.call, NULL, 0, NULL, tag(1)));
+  cleanup_test();
+}
+
+static void test_non_null_reserved_on_op() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = tag(2);
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_send_initial_metadata_more_than_once() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                   (size_t)(op - g_state.ops),
+                                                   tag(1), NULL));
+  cq_expect_completion(g_state.cqv, tag(1), 0);
+  cq_verify(g_state.cqv);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_too_many_metadata() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = (size_t)INT_MAX + 1;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_METADATA ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_send_null_message() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_MESSAGE ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_send_messages_at_the_same_time() {
+  grpc_op *op;
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  prepare_test(1);
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = tag(2);
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  grpc_byte_buffer_destroy(request_payload);
+  cleanup_test();
+}
+
+static void test_send_server_status_from_client() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_NOT_ON_CLIENT ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_receive_initial_metadata_twice_at_client() {
+  grpc_op *op;
+  prepare_test(1);
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &g_state.initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                   (size_t)(op - g_state.ops),
+                                                   tag(1), NULL));
+  cq_expect_completion(g_state.cqv, tag(1), 0);
+  cq_verify(g_state.cqv);
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &g_state.initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                   (size_t)(op - g_state.ops),
+                                                   tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_receive_message_with_invalid_flags() {
+  grpc_op *op;
+  grpc_byte_buffer *payload = NULL;
+  prepare_test(1);
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &payload;
+  op->flags = 1;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_FLAGS == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                                    (size_t)(op - g_state.ops),
+                                                                    tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_receive_two_messages_at_the_same_time() {
+  grpc_op *op;
+  grpc_byte_buffer *payload = NULL;
+  prepare_test(1);
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                                    (size_t)(op - g_state.ops),
+                                                                    tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_recv_close_on_server_from_client() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_NOT_ON_CLIENT ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_recv_status_on_client_twice() {
+  grpc_op *op;
+  prepare_test(1);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata =
+      &g_state.trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &g_state.status;
+  op->data.recv_status_on_client.status_details = &g_state.details;
+  op->data.recv_status_on_client.status_details_capacity =
+      &g_state.details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
+                                                   (size_t)(op - g_state.ops),
+                                                   tag(1), NULL));
+  cq_expect_completion(g_state.cqv, tag(1), 1);
+  cq_verify(g_state.cqv);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = NULL;
+  op->data.recv_status_on_client.status = NULL;
+  op->data.recv_status_on_client.status_details = NULL;
+  op->data.recv_status_on_client.status_details_capacity = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
+static void test_send_close_from_client_on_server() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_NOT_ON_SERVER ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+static void test_recv_status_on_client_from_server() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata =
+      &g_state.trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &g_state.status;
+  op->data.recv_status_on_client.status_details = &g_state.details;
+  op->data.recv_status_on_client.status_details_capacity =
+      &g_state.details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_NOT_ON_SERVER ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+static void test_send_status_from_server_with_invalid_flags() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 1;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_FLAGS ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+static void test_too_many_trailing_metadata() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count =
+      (size_t)INT_MAX + 1;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_METADATA ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+static void test_send_server_status_twice() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+static void test_recv_close_on_server_with_invalid_flags() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = NULL;
+  op->flags = 1;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_FLAGS ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+static void test_recv_close_on_server_twice() {
+  grpc_op *op;
+  prepare_test(0);
+
+  op = g_state.ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS ==
+             grpc_call_start_batch(g_state.server_call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(2), NULL));
+  cleanup_test();
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+  test_non_null_reserved_on_start_batch();
+  test_non_null_reserved_on_op();
+  test_send_initial_metadata_more_than_once();
+  test_too_many_metadata();
+  test_send_null_message();
+  test_send_messages_at_the_same_time();
+  test_send_server_status_from_client();
+  test_receive_initial_metadata_twice_at_client();
+  test_receive_message_with_invalid_flags();
+  test_receive_two_messages_at_the_same_time();
+  test_recv_close_on_server_from_client();
+  test_recv_status_on_client_twice();
+  test_send_close_from_client_on_server();
+  test_recv_status_on_client_from_server();
+  test_send_status_from_server_with_invalid_flags();
+  test_too_many_trailing_metadata();
+  test_send_server_status_twice();
+  test_recv_close_on_server_with_invalid_flags();
+  test_recv_close_on_server_twice();
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index b2b7cfdb6e0c1f49f798566e035790f5b0024618..834113488c99826634dd1bf00c8ca6bb9e2e0b79 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -31,8 +31,10 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
 #include "src/core/security/credentials.h"
 
+#include <stdlib.h>
 #include <string.h>
 
 #include "src/core/httpcli/httpcli.h"
@@ -1013,6 +1015,31 @@ static void test_metadata_plugin_failure(void) {
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+static void test_get_well_known_google_credentials_file_path(void) {
+#ifdef GPR_POSIX_FILE
+  char *path;
+  char *old_home = gpr_getenv("HOME");
+  gpr_setenv("HOME", "/tmp");
+  path = grpc_get_well_known_google_credentials_file_path();
+  GPR_ASSERT(path != NULL);
+  GPR_ASSERT(0 == strcmp("/tmp/.config/" GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY
+                         "/" GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE,
+                         path));
+  gpr_free(path);
+#if defined(GPR_POSIX_ENV) || defined(GPR_LINUX_ENV)
+  unsetenv("HOME");
+  path = grpc_get_well_known_google_credentials_file_path();
+  GPR_ASSERT(path == NULL);
+#endif /* GPR_POSIX_ENV || GPR_LINUX_ENV */
+  gpr_setenv("HOME", old_home);
+  gpr_free(old_home);
+#else /* GPR_POSIX_FILE */
+  char *path = grpc_get_well_known_google_credentials_file_path();
+  GPR_ASSERT(path != NULL);
+  gpr_free(path);
+#endif
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_empty_md_store();
@@ -1043,5 +1070,6 @@ int main(int argc, char **argv) {
   test_google_default_creds_access_token();
   test_metadata_plugin_success();
   test_metadata_plugin_failure();
+  test_get_well_known_google_credentials_file_path();
   return 0;
 }
diff --git a/test/core/support/slice_buffer_test.c b/test/core/support/slice_buffer_test.c
index a48278434f1be3e0a81ebbb403a3c807c8f0b37a..cf2da84c2bbad33c47b88fe99e801893b9c0370a 100644
--- a/test/core/support/slice_buffer_test.c
+++ b/test/core/support/slice_buffer_test.c
@@ -35,13 +35,12 @@
 #include <grpc/support/slice_buffer.h>
 #include "test/core/util/test_config.h"
 
-int main(int argc, char **argv) {
+void test_slice_buffer_add() {
   gpr_slice_buffer buf;
   gpr_slice aaa = gpr_slice_from_copied_string("aaa");
   gpr_slice bb = gpr_slice_from_copied_string("bb");
   size_t i;
 
-  grpc_test_init(argc, argv);
   gpr_slice_buffer_init(&buf);
   for (i = 0; i < 10; i++) {
     gpr_slice_ref(aaa);
@@ -70,6 +69,61 @@ int main(int argc, char **argv) {
   GPR_ASSERT(buf.count == 0);
   GPR_ASSERT(buf.length == 0);
   gpr_slice_buffer_destroy(&buf);
+}
+
+void test_slice_buffer_move_first() {
+  gpr_slice slices[3];
+  gpr_slice_buffer src;
+  gpr_slice_buffer dst;
+  int idx = 0;
+  size_t src_len = 0;
+  size_t dst_len = 0;
+
+  slices[0] = gpr_slice_from_copied_string("aaa");
+  slices[1] = gpr_slice_from_copied_string("bbbb");
+  slices[2] = gpr_slice_from_copied_string("ccc");
+
+  gpr_slice_buffer_init(&src);
+  gpr_slice_buffer_init(&dst);
+  for (idx = 0; idx < 3; idx++) {
+    gpr_slice_ref(slices[idx]);
+    /* For this test, it is important that we add each slice at a new
+       slice index */
+    gpr_slice_buffer_add_indexed(&src, slices[idx]);
+    gpr_slice_buffer_add_indexed(&dst, slices[idx]);
+  }
+
+  /* Case 1: Move more than the first slice's length from src to dst */
+  src_len = src.length;
+  dst_len = dst.length;
+  gpr_slice_buffer_move_first(&src, 4, &dst);
+  src_len -= 4;
+  dst_len += 4;
+  GPR_ASSERT(src.length == src_len);
+  GPR_ASSERT(dst.length == dst_len);
+
+  /* src now has two slices ["bbb"] and  ["ccc"] */
+  /* Case 2: Move the first slice from src to dst */
+  gpr_slice_buffer_move_first(&src, 3, &dst);
+  src_len -= 3;
+  dst_len += 3;
+  GPR_ASSERT(src.length == src_len);
+  GPR_ASSERT(dst.length == dst_len);
+
+  /* src now has one slice ["ccc"] */
+  /* Case 3: Move less than the first slice's length from src to dst*/
+  gpr_slice_buffer_move_first(&src, 2, &dst);
+  src_len -= 2;
+  dst_len += 2;
+  GPR_ASSERT(src.length == src.length);
+  GPR_ASSERT(dst.length == dst.length);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  test_slice_buffer_add();
+  test_slice_buffer_move_first();
 
   return 0;
 }
diff --git a/test/core/support/slice_test.c b/test/core/support/slice_test.c
index 1d202f06186108bf53035f3af36627577517211e..9e0e22c24b8896c44567052698f1e9a0727a766b 100644
--- a/test/core/support/slice_test.c
+++ b/test/core/support/slice_test.c
@@ -94,12 +94,27 @@ static void do_nothing_with_len_1(void *ignored, size_t len) {
 
 static void test_slice_new_with_len_returns_something_sensible(void) {
   gpr_uint8 x;
+  int num_refs = 5; /* To test adding/removing an arbitrary number of refs */
+  int i;
 
   gpr_slice slice = gpr_slice_new_with_len(&x, 1, do_nothing_with_len_1);
-  GPR_ASSERT(slice.refcount);
+  GPR_ASSERT(slice.refcount); /* ref count is initialized to 1 at this point */
   GPR_ASSERT(slice.data.refcounted.bytes == &x);
   GPR_ASSERT(slice.data.refcounted.length == 1);
   GPR_ASSERT(do_nothing_with_len_1_calls == 0);
+
+  /* Add an arbitrary number of refs to the slice and remoe the refs. This is to
+     make sure that that the destroy callback (i.e do_nothing_with_len_1()) is
+     not called until the last unref operation */
+  for (i = 0; i < num_refs; i++) {
+    gpr_slice_ref(slice);
+  }
+  for (i = 0; i < num_refs; i++) {
+    gpr_slice_unref(slice);
+  }
+  GPR_ASSERT(do_nothing_with_len_1_calls == 0); /* Shouldn't be called yet */
+
+  /* last unref */
   gpr_slice_unref(slice);
   GPR_ASSERT(do_nothing_with_len_1_calls == 1);
 }
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 220b16b60f5a06c787d732c3d73fe19d4eb25121..6bc5f792e52f8565de2f0a1cdb64e266c84f85a2 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -153,6 +153,7 @@ struct test {
   gpr_int64 counter;
   int thread_count; /* used to allocate thread ids */
   int done;         /* threads not yet completed */
+  int incr_step;    /* how much to increment/decrement refcount each time */
 
   gpr_mu mu; /* protects iterations, counter, thread_count, done */
 
@@ -170,13 +171,14 @@ struct test {
 };
 
 /* Return pointer to a new struct test. */
-static struct test *test_new(int threads, gpr_int64 iterations) {
+static struct test *test_new(int threads, gpr_int64 iterations, int incr_step) {
   struct test *m = gpr_malloc(sizeof(*m));
   m->threads = threads;
   m->iterations = iterations;
   m->counter = 0;
   m->thread_count = 0;
   m->done = threads;
+  m->incr_step = incr_step;
   gpr_mu_init(&m->mu);
   gpr_cv_init(&m->cv);
   gpr_cv_init(&m->done_cv);
@@ -238,9 +240,12 @@ static void mark_thread_done(struct test *m) {
 
 /* Test several threads running (*body)(struct test *m) for increasing settings
    of m->iterations, until about timeout_s to 2*timeout_s seconds have elapsed.
-   If extra!=NULL, run (*extra)(m) in an additional thread.  */
+   If extra!=NULL, run (*extra)(m) in an additional thread.
+   incr_step controls by how much m->refcount should be incremented/decremented
+   (if at all) each time in the tests.
+   */
 static void test(const char *name, void (*body)(void *m),
-                 void (*extra)(void *m), int timeout_s) {
+                 void (*extra)(void *m), int timeout_s, int incr_step) {
   gpr_int64 iterations = 1024;
   struct test *m;
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
@@ -251,7 +256,7 @@ static void test(const char *name, void (*body)(void *m),
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
     fprintf(stderr, " %ld", (long)iterations);
-    m = test_new(10, iterations);
+    m = test_new(10, iterations, incr_step);
     if (extra != NULL) {
       gpr_thd_id id;
       GPR_ASSERT(gpr_thd_new(&id, extra, m, NULL));
@@ -259,7 +264,7 @@ static void test(const char *name, void (*body)(void *m),
     }
     test_create_threads(m, body);
     test_wait(m);
-    if (m->counter != m->threads * m->iterations) {
+    if (m->counter != m->threads * m->iterations * m->incr_step) {
       fprintf(stderr, "counter %ld  threads %d  iterations %ld\n",
               (long)m->counter, m->threads, (long)m->iterations);
       GPR_ASSERT(0);
@@ -406,14 +411,18 @@ static void statsinc(void *v /*=m*/) {
   mark_thread_done(m);
 }
 
-/* Increment m->refcount m->iterations times, decrement m->thread_refcount
-   once, and if it reaches zero, set m->event to (void*)1; then mark thread as
-   done.  */
+/* Increment m->refcount by m->incr_step for m->iterations times. Decrement
+   m->thread_refcount once, and if it reaches zero, set m->event to (void*)1;
+   then mark thread as done.  */
 static void refinc(void *v /*=m*/) {
   struct test *m = v;
   gpr_int64 i;
   for (i = 0; i != m->iterations; i++) {
-    gpr_ref(&m->refcount);
+    if (m->incr_step == 1) {
+      gpr_ref(&m->refcount);
+    } else {
+      gpr_refn(&m->refcount, m->incr_step);
+    }
   }
   if (gpr_unref(&m->thread_refcount)) {
     gpr_event_set(&m->event, (void *)1);
@@ -421,12 +430,13 @@ static void refinc(void *v /*=m*/) {
   mark_thread_done(m);
 }
 
-/* Wait until m->event is set to (void *)1, then decrement m->refcount
-   m->stats_counter m->iterations times, and ensure that the last decrement
-   caused the counter to reach zero, then mark thread as done.  */
+
+/* Wait until m->event is set to (void *)1, then decrement m->refcount by 1
+   (m->threads * m->iterations * m->incr_step) times, and ensure that the last
+   decrement caused the counter to reach zero, then mark thread as done.  */
 static void refcheck(void *v /*=m*/) {
   struct test *m = v;
-  gpr_int64 n = m->iterations * m->threads;
+  gpr_int64 n = m->iterations * m->threads * m->incr_step;
   gpr_int64 i;
   GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future(GPR_CLOCK_REALTIME)) ==
              (void *)1);
@@ -444,13 +454,16 @@ static void refcheck(void *v /*=m*/) {
 
 int main(int argc, char *argv[]) {
   grpc_test_init(argc, argv);
-  test("mutex", &inc, NULL, 1);
-  test("mutex try", &inctry, NULL, 1);
-  test("cv", &inc_by_turns, NULL, 1);
-  test("timedcv", &inc_with_1ms_delay, NULL, 1);
-  test("queue", &many_producers, &consumer, 10);
-  test("stats_counter", &statsinc, NULL, 1);
-  test("refcount", &refinc, &refcheck, 1);
-  test("timedevent", &inc_with_1ms_delay_event, NULL, 1);
+  test("mutex", &inc, NULL, 1, 1);
+  test("mutex try", &inctry, NULL, 1, 1);
+  test("cv", &inc_by_turns, NULL, 1, 1);
+  test("timedcv", &inc_with_1ms_delay, NULL, 1, 1);
+  test("queue", &many_producers, &consumer, 10, 1);
+  test("stats_counter", &statsinc, NULL, 1, 1);
+  test("refcount by 1", &refinc, &refcheck, 1, 1);
+  test("refcount by 3", &refinc, &refcheck, 1, 3); /* incr_step of 3 is an
+                                                      arbitrary choice. Any
+                                                      number > 1 is okay here */
+  test("timedevent", &inc_with_1ms_delay_event, NULL, 1, 1);
   return 0;
 }
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index e3fc7897884b7b8cf8dffb6825405439a85bf16d..7a5cf30506f71dd0f336ead1274ec4894f08e228 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -175,6 +175,19 @@ static void test_pluck(void) {
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+static void test_pluck_after_shutdown(void) {
+  grpc_event ev;
+  grpc_completion_queue *cc;
+
+  LOG_TEST("test_pluck_after_shutdown");
+  cc = grpc_completion_queue_create(NULL);
+  grpc_completion_queue_shutdown(cc);
+  ev = grpc_completion_queue_pluck(cc, NULL, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                   NULL);
+  GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
+  grpc_completion_queue_destroy(cc);
+}
+
 #define TEST_THREAD_EVENTS 10000
 
 typedef struct test_thread_options {
@@ -343,6 +356,7 @@ int main(int argc, char **argv) {
   test_shutdown_then_next_with_timeout();
   test_cq_end_op();
   test_pluck();
+  test_pluck_after_shutdown();
   test_threading(1, 1);
   test_threading(1, 10);
   test_threading(10, 1);
diff --git a/test/core/surface/multi_init_test.c b/test/core/surface/init_test.c
similarity index 84%
rename from test/core/surface/multi_init_test.c
rename to test/core/surface/init_test.c
index 99b7a52ff98bbef20b01752de404367991d9382d..d4451e45672e931db2471838b3cf00a8b367fd78 100644
--- a/test/core/surface/multi_init_test.c
+++ b/test/core/surface/init_test.c
@@ -32,8 +32,11 @@
  */
 
 #include <grpc/grpc.h>
+#include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
+static int g_flag;
+
 static void test(int rounds) {
   int i;
   for (i = 0; i < rounds; i++) {
@@ -44,7 +47,7 @@ static void test(int rounds) {
   }
 }
 
-static void test_mixed() {
+static void test_mixed(void) {
   grpc_init();
   grpc_init();
   grpc_shutdown();
@@ -53,11 +56,23 @@ static void test_mixed() {
   grpc_shutdown();
 }
 
+static void plugin_init(void) { g_flag = 1; }
+static void plugin_destroy(void) { g_flag = 2; }
+
+static void test_plugin() {
+  grpc_register_plugin(plugin_init, plugin_destroy);
+  grpc_init();
+  GPR_ASSERT(g_flag == 1);
+  grpc_shutdown();
+  GPR_ASSERT(g_flag == 2);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test(1);
   test(2);
   test(3);
   test_mixed();
+  test_plugin();
   return 0;
 }
diff --git a/test/core/tsi/transport_security_test.c b/test/core/tsi/transport_security_test.c
index 858b92fc9d294da25646d966ce7c8b834077f160..7ce343987bb3d06a86958cc1e7832bbaa14d8e1b 100644
--- a/test/core/tsi/transport_security_test.c
+++ b/test/core/tsi/transport_security_test.c
@@ -43,6 +43,7 @@
 #include <openssl/crypto.h>
 
 #include "src/core/support/string.h"
+#include "src/core/tsi/fake_transport_security.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "test/core/util/test_config.h"
 
@@ -296,8 +297,70 @@ static void test_peer_matches_name(void) {
   }
 }
 
+typedef struct {
+  tsi_result res;
+  const char *str;
+} tsi_result_string_pair;
+
+static void test_result_strings(void) {
+  const tsi_result_string_pair results[] = {
+      {TSI_OK, "TSI_OK"},
+      {TSI_UNKNOWN_ERROR, "TSI_UNKNOWN_ERROR"},
+      {TSI_INVALID_ARGUMENT, "TSI_INVALID_ARGUMENT"},
+      {TSI_PERMISSION_DENIED, "TSI_PERMISSION_DENIED"},
+      {TSI_INCOMPLETE_DATA, "TSI_INCOMPLETE_DATA"},
+      {TSI_FAILED_PRECONDITION, "TSI_FAILED_PRECONDITION"},
+      {TSI_UNIMPLEMENTED, "TSI_UNIMPLEMENTED"},
+      {TSI_INTERNAL_ERROR, "TSI_INTERNAL_ERROR"},
+      {TSI_DATA_CORRUPTED, "TSI_DATA_CORRUPTED"},
+      {TSI_NOT_FOUND, "TSI_NOT_FOUND"},
+      {TSI_PROTOCOL_FAILURE, "TSI_PROTOCOL_FAILURE"},
+      {TSI_HANDSHAKE_IN_PROGRESS, "TSI_HANDSHAKE_IN_PROGRESS"},
+      {TSI_OUT_OF_RESOURCES, "TSI_OUT_OF_RESOURCES"}};
+  size_t i;
+  for (i = 0; i < GPR_ARRAY_SIZE(results); i++) {
+    GPR_ASSERT(strcmp(results[i].str, tsi_result_to_string(results[i].res)) ==
+               0);
+  }
+  GPR_ASSERT(strcmp("UNKNOWN", tsi_result_to_string((tsi_result)42)) == 0);
+}
+
+static void test_protector_invalid_args(void) {
+  GPR_ASSERT(tsi_frame_protector_protect(NULL, NULL, NULL, NULL, NULL) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(tsi_frame_protector_protect_flush(NULL, NULL, NULL, NULL) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(tsi_frame_protector_unprotect(NULL, NULL, NULL, NULL, NULL) ==
+             TSI_INVALID_ARGUMENT);
+}
+
+static void test_handshaker_invalid_args(void) {
+  GPR_ASSERT(tsi_handshaker_get_result(NULL) == TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(tsi_handshaker_extract_peer(NULL, NULL) == TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(tsi_handshaker_create_frame_protector(NULL, NULL, NULL) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(tsi_handshaker_process_bytes_from_peer(NULL, NULL, NULL) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(tsi_handshaker_get_bytes_to_send_to_peer(NULL, NULL, NULL) ==
+             TSI_INVALID_ARGUMENT);
+}
+
+static void test_handshaker_invalid_state(void) {
+  tsi_handshaker *h = tsi_create_fake_handshaker(0);
+  tsi_peer peer;
+  tsi_frame_protector *p;
+  GPR_ASSERT(tsi_handshaker_extract_peer(h, &peer) == TSI_FAILED_PRECONDITION);
+  GPR_ASSERT(tsi_handshaker_create_frame_protector(h, NULL, &p) ==
+             TSI_FAILED_PRECONDITION);
+  tsi_handshaker_destroy(h);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_peer_matches_name();
+  test_result_strings();
+  test_protector_invalid_args();
+  test_handshaker_invalid_args();
+  test_handshaker_invalid_state();
   return 0;
 }
diff --git a/tools/http2_interop/http2interop_test.go b/tools/http2_interop/http2interop_test.go
index b35d08556944e6ff60654878eaade07c361a0216..fb314da1964a099a4d9c855339439148d3e3db69 100644
--- a/tools/http2_interop/http2interop_test.go
+++ b/tools/http2_interop/http2interop_test.go
@@ -3,6 +3,7 @@ package http2interop
 import (
 	"crypto/tls"
 	"crypto/x509"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -67,7 +68,8 @@ func (ctx *HTTP2InteropCtx) Close() error {
 	return nil
 }
 
-func TestClientShortSettings(t *testing.T) {
+func TestSoonClientShortSettings(t *testing.T) {
+	defer Report(t)
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -78,7 +80,8 @@ func TestClientShortSettings(t *testing.T) {
 	}
 }
 
-func TestShortPreface(t *testing.T) {
+func TestSoonShortPreface(t *testing.T) {
+	defer Report(t)
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -89,7 +92,8 @@ func TestShortPreface(t *testing.T) {
 	}
 }
 
-func TestUnknownFrameType(t *testing.T) {
+func TestSoonUnknownFrameType(t *testing.T) {
+	defer Report(t)
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -99,7 +103,8 @@ func TestUnknownFrameType(t *testing.T) {
 	}
 }
 
-func TestClientPrefaceWithStreamId(t *testing.T) {
+func TestSoonClientPrefaceWithStreamId(t *testing.T) {
+	defer Report(t)
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -108,7 +113,8 @@ func TestClientPrefaceWithStreamId(t *testing.T) {
 	matchError(t, err, "EOF")
 }
 
-func TestTLSApplicationProtocol(t *testing.T) {
+func TestSoonTLSApplicationProtocol(t *testing.T) {
+	defer Report(t)
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
@@ -117,7 +123,8 @@ func TestTLSApplicationProtocol(t *testing.T) {
 	matchError(t, err, "EOF", "broken pipe")
 }
 
-func TestTLSMaxVersion(t *testing.T) {
+func TestSoonTLSMaxVersion(t *testing.T) {
+	defer Report(t)
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
@@ -128,7 +135,8 @@ func TestTLSMaxVersion(t *testing.T) {
 	matchError(t, err, "EOF", "server selected unsupported protocol")
 }
 
-func TestTLSBadCipherSuites(t *testing.T) {
+func TestSoonTLSBadCipherSuites(t *testing.T) {
+	defer Report(t)
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
@@ -151,5 +159,25 @@ func matchError(t *testing.T, err error, matches ...string) {
 
 func TestMain(m *testing.M) {
 	flag.Parse()
-	os.Exit(m.Run())
+	m.Run()
+	var fatal bool
+	var any bool
+	for _, ci := range allCaseInfos.Cases {
+		if ci.Skipped {
+			continue
+		}
+		any = true
+		if !ci.Passed && ci.Fatal {
+			fatal = true
+		}
+	}
+
+	if err := json.NewEncoder(os.Stderr).Encode(&allCaseInfos); err != nil {
+		fmt.Println("Failed to encode", err)
+	}
+	var code int
+	if !any || fatal {
+		code = 1
+	}
+	os.Exit(code)
 }
diff --git a/tools/http2_interop/s6.5.go b/tools/http2_interop/s6.5.go
index 8145b6e031ab4af02383f8389b6488438f872d9d..32468abe831606f3b944aac640d37d444f579f9e 100644
--- a/tools/http2_interop/s6.5.go
+++ b/tools/http2_interop/s6.5.go
@@ -11,7 +11,6 @@ func testSmallMaxFrameSize(ctx *HTTP2InteropCtx) error {
 		return err
 	}
 	defer conn.Close()
-	conn.Log = ctx.T.Log
 	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
 	sf := &SettingsFrame{
diff --git a/tools/http2_interop/s6.5_test.go b/tools/http2_interop/s6.5_test.go
index 48e8ced5764a61598207fa4e70f5314ea4b05769..9dadd4e699c18f18a0f3fc7cb9ca79f1341a79c3 100644
--- a/tools/http2_interop/s6.5_test.go
+++ b/tools/http2_interop/s6.5_test.go
@@ -4,8 +4,9 @@ import (
 	"testing"
 )
 
-func TestSmallMaxFrameSize(t *testing.T) {
-	if *testCase != "experimental" {
+func TestSoonSmallMaxFrameSize(t *testing.T) {
+	defer Report(t)
+	if *testCase != "framing" {
 		t.SkipNow()
 	}
 	ctx := InteropCtx(t)
diff --git a/tools/http2_interop/testsuite.go b/tools/http2_interop/testsuite.go
new file mode 100644
index 0000000000000000000000000000000000000000..51d36e217ed7c8632436595a82523ce98bc07113
--- /dev/null
+++ b/tools/http2_interop/testsuite.go
@@ -0,0 +1,56 @@
+package http2interop
+
+import (
+	"path"
+	"runtime"
+	"strings"
+	"sync"
+	"testing"
+)
+
+// When a test is skipped or fails, runtime.Goexit() is called which destroys the callstack.
+// This means the name of the test case is lost, so we need to grab a copy of pc before.
+func Report(t testing.TB) {
+	// If the goroutine panics, Fatal()s, or Skip()s, the function name is at the 3rd callstack
+	// layer.  On success, its at 1st.  Since it's hard to check which happened, just try both.
+	pcs := make([]uintptr, 10)
+	total := runtime.Callers(1, pcs)
+	var name string
+	for _, pc := range pcs[:total] {
+		fn := runtime.FuncForPC(pc)
+		fullName := fn.Name()
+		if strings.HasPrefix(path.Ext(fullName), ".Test") {
+			// Skip the leading .
+			name = string([]byte(path.Ext(fullName))[1:])
+			break
+		}
+	}
+	if name == "" {
+		return
+	}
+
+	allCaseInfos.lock.Lock()
+	defer allCaseInfos.lock.Unlock()
+	allCaseInfos.Cases = append(allCaseInfos.Cases, &caseInfo{
+		Name:    name,
+		Passed:  !t.Failed() && !t.Skipped(),
+		Skipped: t.Skipped(),
+		Fatal:   t.Failed() && !strings.HasPrefix(name, "TestSoon"),
+	})
+}
+
+type caseInfo struct {
+	Name    string `json:"name"`
+	Passed  bool   `json:"passed"`
+	Skipped bool   `json:"skipped,omitempty"`
+	Fatal   bool   `json:"fatal,omitempty"`
+}
+
+type caseInfos struct {
+	lock  sync.Mutex
+	Cases []*caseInfo `json:"cases"`
+}
+
+var (
+	allCaseInfos = caseInfos{}
+)
diff --git a/tools/jenkins/grpc_interop_python/Dockerfile b/tools/jenkins/grpc_interop_python/Dockerfile
index 5850f5f321e0794c75ae0c52e0f2865b5d980545..6034cbf95504719cc3fc9649d48902cd5cc51859 100644
--- a/tools/jenkins/grpc_interop_python/Dockerfile
+++ b/tools/jenkins/grpc_interop_python/Dockerfile
@@ -75,6 +75,7 @@ RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
 # Install Python requisites
 RUN /bin/bash -l -c "pip install --upgrade pip"
 RUN /bin/bash -l -c "pip install virtualenv"
+RUN /bin/bash -l -c "pip install tox"
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/jenkins/grpc_jenkins_slave/Dockerfile b/tools/jenkins/grpc_jenkins_slave/Dockerfile
index 5b8c24c076ca217204a539a5109f4f24151b8b66..916e5e83fb572628c58ff899eab4133682e5674e 100644
--- a/tools/jenkins/grpc_jenkins_slave/Dockerfile
+++ b/tools/jenkins/grpc_jenkins_slave/Dockerfile
@@ -131,7 +131,7 @@ RUN apt-get update && apt-get install -y \
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
 
 # For sanity test
 RUN pip install simplejson mako
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index 24cf6ba7c88e5222afd8a73fe72e1078536dc663..57080ce9348dce69599b1b3372f2e340d6a2261b 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -34,71 +34,16 @@ set -ex
 cd $(dirname $0)/../..
 
 ROOT=`pwd`
-PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
 GRPCIO=$ROOT/src/python/grpcio
-GRPCIO_TEST=$ROOT/src/python/grpcio_test
-GRPCIO_HEALTH_CHECKING=$ROOT/src/python/grpcio_health_checking
-
-install_grpcio_deps() {
-  cd $GRPCIO
-  pip install -r requirements.txt
-}
-install_grpcio_test_deps() {
-  cd $GRPCIO_TEST
-  pip install -r requirements.txt
-}
-
-install_grpcio() {
-  CFLAGS="-I$ROOT/include -std=c89" LDFLAGS=-L$ROOT/libs/$CONFIG GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install $GRPCIO
-}
-install_grpcio_test() {
-  pip install $GRPCIO_TEST
-}
-install_grpcio_health_checking() {
-  pip install $GRPCIO_HEALTH_CHECKING
-}
-
-# Cleans the environment of previous installations
-clean_grpcio_all() {
-  (yes | pip uninstall grpcio) || true
-  (yes | pip uninstall grpcio_test) || true
-  (yes | pip uninstall grpcio_health_checking) || true
-}
-
-# Builds the testing environment.
-make_virtualenv() {
-  virtualenv_name="python"$1"_virtual_environment"
-  if [ ! -d $virtualenv_name ]
-  then
-    # Build the entire virtual environment
-    virtualenv -p `which "python"$1` $virtualenv_name
-    source $virtualenv_name/bin/activate
-
-    # Install grpcio
-    install_grpcio_deps
-    install_grpcio
-
-    # Install grpcio_test
-    install_grpcio_test_deps
-    install_grpcio_test
-
-    # Install grpcio_health_checking
-    install_grpcio_health_checking
-  else
-    source $virtualenv_name/bin/activate
-    # Uninstall and re-install the packages we care about. Don't use
-    # --force-reinstall or --ignore-installed to avoid propagating this
-    # unnecessarily to dependencies. Don't use --no-deps to avoid missing
-    # dependency upgrades.
-    clean_grpcio_all
-    install_grpcio || (
-      # Fall back to rebuilding the entire environment
-      rm -rf $virtualenv_name
-      make_virtualenv $1
-    )
-    install_grpcio_test
-    install_grpcio_health_checking
-  fi
-}
-
-make_virtualenv $1
+export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG
+export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG
+export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
+export CFLAGS="-I$ROOT/include -std=c89"
+export LDFLAGS="-L$ROOT/libs/$CONFIG"
+export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
+
+cd $GRPCIO
+tox --notest
+
+$GRPCIO/.tox/py27/bin/python $GRPCIO/setup.py build
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 5435a1d02fcb7d0c189f9748e68a927b1605f11c..37b631bd0da96dc49f20632b056b14c9abfb6b35 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -60,14 +60,14 @@ class CXXLanguage:
     self.server_cwd = None
     self.safename = 'cxx'
 
-  def client_args(self):
-    return ['bins/opt/interop_client']
+  def client_cmd(self, args):
+    return ['bins/opt/interop_client'] + args
 
   def cloud_to_prod_env(self):
     return {}
 
-  def server_args(self):
-    return ['bins/opt/interop_server', '--use_tls=true']
+  def server_cmd(self, args):
+    return ['bins/opt/interop_server', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -86,14 +86,14 @@ class CSharpLanguage:
     self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug'
     self.safename = str(self)
 
-  def client_args(self):
-    return ['mono', 'Grpc.IntegrationTesting.Client.exe']
+  def client_cmd(self, args):
+    return ['mono', 'Grpc.IntegrationTesting.Client.exe'] + args
 
   def cloud_to_prod_env(self):
     return _SSL_CERT_ENV
 
-  def server_args(self):
-    return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true']
+  def server_cmd(self, args):
+    return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -112,14 +112,14 @@ class JavaLanguage:
     self.server_cwd = '../grpc-java'
     self.safename = str(self)
 
-  def client_args(self):
-    return ['./run-test-client.sh']
+  def client_cmd(self, args):
+    return ['./run-test-client.sh'] + args
 
   def cloud_to_prod_env(self):
     return {}
 
-  def server_args(self):
-    return ['./run-test-server.sh', '--use_tls=true']
+  def server_cmd(self, args):
+    return ['./run-test-server.sh', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -139,14 +139,14 @@ class GoLanguage:
     self.server_cwd = '/go/src/google.golang.org/grpc/interop/server'
     self.safename = str(self)
 
-  def client_args(self):
-    return ['go', 'run', 'client.go']
+  def client_cmd(self, args):
+    return ['go', 'run', 'client.go'] + args
 
   def cloud_to_prod_env(self):
     return {}
 
-  def server_args(self):
-    return ['go', 'run', 'server.go', '--use_tls=true']
+  def server_cmd(self, args):
+    return ['go', 'run', 'server.go', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -168,8 +168,8 @@ class Http2Client:
     self.client_cwd = None
     self.safename = str(self)
 
-  def client_args(self):
-    return ['tools/http2_interop/http2_interop.test', '-test.v']
+  def client_cmd(self, args):
+    return ['tools/http2_interop/http2_interop.test', '-test.v'] + args
 
   def cloud_to_prod_env(self):
     return {}
@@ -190,14 +190,14 @@ class NodeLanguage:
     self.server_cwd = None
     self.safename = str(self)
 
-  def client_args(self):
-    return ['node', 'src/node/interop/interop_client.js']
+  def client_cmd(self, args):
+    return ['node', 'src/node/interop/interop_client.js'] + args
 
   def cloud_to_prod_env(self):
     return _SSL_CERT_ENV
 
-  def server_args(self):
-    return ['node', 'src/node/interop/interop_server.js', '--use_tls=true']
+  def server_cmd(self, args):
+    return ['node', 'src/node/interop/interop_server.js', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -215,8 +215,8 @@ class PHPLanguage:
     self.client_cwd = None
     self.safename = str(self)
 
-  def client_args(self):
-    return ['src/php/bin/interop_client.sh']
+  def client_cmd(self, args):
+    return ['src/php/bin/interop_client.sh'] + args
 
   def cloud_to_prod_env(self):
     return _SSL_CERT_ENV
@@ -238,14 +238,14 @@ class RubyLanguage:
     self.server_cwd = None
     self.safename = str(self)
 
-  def client_args(self):
-    return ['ruby', 'src/ruby/bin/interop/interop_client.rb']
+  def client_cmd(self, args):
+    return ['ruby', 'src/ruby/bin/interop/interop_client.rb'] + args
 
   def cloud_to_prod_env(self):
     return _SSL_CERT_ENV
 
-  def server_args(self):
-    return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls=true']
+  def server_cmd(self, args):
+    return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -264,17 +264,29 @@ class PythonLanguage:
     self.server_cwd = None
     self.safename = str(self)
 
-  def client_args(self):
-    return ['python2.7_virtual_environment/bin/python', '-m', 'grpc_interop.client']
+  def client_cmd(self, args):
+    return [
+        'src/python/grpcio/.tox/py27/bin/python',
+        'src/python/grpcio/setup.py',
+        'run_interop',
+        '--client',
+        '--args=\'{}\''.format(' '.join(args))
+    ]
 
   def cloud_to_prod_env(self):
     return _SSL_CERT_ENV
 
-  def server_args(self):
-    return ['python2.7_virtual_environment/bin/python', '-m', 'grpc_interop.server', '--use_tls=true']
+  def server_cmd(self, args):
+    return [
+        'src/python/grpcio/.tox/py27/bin/python',
+        'src/python/grpcio/setup.py',
+        'run_interop',
+        '--server',
+        '--args=\'{}\''.format(' '.join(args) + ' --use_tls=true')
+    ]
 
   def global_env(self):
-    return {'LD_LIBRARY_PATH': 'libs/opt'}
+    return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT)}
 
   def unimplemented_test_cases(self):
     return ['jwt_token_creds', 'per_rpc_creds']
@@ -307,6 +319,8 @@ _AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
 
 _HTTP2_TEST_CASES = ["tls", "framing"]
 
+DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
+
 def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
   """Wraps given cmdline array to create 'docker run' cmdline from it."""
   docker_cmdline = ['docker', 'run', '-i', '--rm=true']
@@ -317,7 +331,7 @@ def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
       docker_cmdline += ['-e', '%s=%s' % (k,v)]
 
   # set working directory
-  workdir = '/var/local/git/grpc'
+  workdir = DOCKER_WORKDIR_ROOT
   if cwd:
     workdir = os.path.join(workdir, cwd)
   docker_cmdline += ['-w', workdir]
@@ -334,12 +348,12 @@ def bash_login_cmdline(cmdline):
   return ['bash', '-l', '-c', ' '.join(cmdline)]
 
 
-def add_auth_options(language, test_case, cmdline, env):
+def auth_options(language, test_case):
   """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
 
   language = str(language)
-  cmdline = list(cmdline)
-  env = env.copy()
+  cmdargs = []
+  env = {}
 
   # TODO(jtattermusch): this file path only works inside docker
   key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
@@ -351,19 +365,19 @@ def add_auth_options(language, test_case, cmdline, env):
     if language in ['csharp', 'node', 'php', 'python', 'ruby']:
       env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
     else:
-      cmdline += [key_file_arg]
+      cmdargs += [key_file_arg]
 
   if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
-    cmdline += [oauth_scope_arg]
+    cmdargs += [oauth_scope_arg]
 
   if test_case == 'oauth2_auth_token' and language == 'c++':
     # C++ oauth2 test uses GCE creds and thus needs to know the default account
-    cmdline += [default_account_arg]
+    cmdargs += [default_account_arg]
 
   if test_case == 'compute_engine_creds':
-    cmdline += [oauth_scope_arg, default_account_arg]
+    cmdargs += [oauth_scope_arg, default_account_arg]
 
-  return (cmdline, env)
+  return (cmdargs, env)
 
 
 def _job_kill_handler(job):
@@ -378,18 +392,20 @@ def _job_kill_handler(job):
 
 def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
   """Creates jobspec for cloud-to-prod interop test"""
-  cmdline = language.client_args() + [
+  container_name = None
+  cmdargs = [
       '--server_host_override=grpc-test.sandbox.google.com',
       '--server_host=grpc-test.sandbox.google.com',
       '--server_port=443',
       '--use_tls=true',
       '--test_case=%s' % test_case]
-  cwd = language.client_cwd
   environ = dict(language.cloud_to_prod_env(), **language.global_env())
-  container_name = None
   if auth:
-    cmdline, environ = add_auth_options(language, test_case, cmdline, environ)
-  cmdline = bash_login_cmdline(cmdline)
+    auth_cmdargs, auth_env = auth_options(language, test_case)
+    cmdargs += auth_cmdargs
+    environ.update(auth_env)
+  cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
+  cwd = language.client_cwd
 
   if docker_image:
     container_name = dockerjob.random_name('interop_client_%s' % language.safename)
@@ -419,13 +435,13 @@ def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
 def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
                            server_port, docker_image=None):
   """Creates jobspec for cloud-to-cloud interop test"""
-  cmdline = bash_login_cmdline(language.client_args() +
-                               ['--server_host_override=foo.test.google.fr',
-                                '--use_tls=true',
-                                '--use_test_ca=true',
-                                '--test_case=%s' % test_case,
-                                '--server_host=%s' % server_host,
-                                '--server_port=%s' % server_port])
+  cmdline = bash_login_cmdline(language.client_cmd([
+      '--server_host_override=foo.test.google.fr',
+      '--use_tls=true',
+      '--use_test_ca=true',
+      '--test_case=%s' % test_case,
+      '--server_host=%s' % server_host,
+      '--server_port=%s' % server_port]))
   cwd = language.client_cwd
   environ = language.global_env()
   if docker_image:
@@ -455,8 +471,8 @@ def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
 def server_jobspec(language, docker_image):
   """Create jobspec for running a server"""
   container_name = dockerjob.random_name('interop_server_%s' % language.safename)
-  cmdline = bash_login_cmdline(language.server_args() +
-                               ['--port=%s' % _DEFAULT_SERVER_PORT])
+  cmdline = bash_login_cmdline(
+      language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
   environ = language.global_env()
   docker_cmdline = docker_run_cmdline(cmdline,
                                       image=docker_image,
@@ -547,7 +563,7 @@ argp.add_argument('--http2_interop',
                   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
@@ -571,7 +587,7 @@ 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={}
@@ -593,10 +609,10 @@ if args.use_docker:
     num_failures, _ = jobset.run(
         build_jobs, newline_on_success=True, maxjobs=args.jobs)
     if num_failures == 0:
-      jobset.message('SUCCESS', 'All docker images built successfully.', 
+      jobset.message('SUCCESS', 'All docker images built successfully.',
                      do_newline=True)
     else:
-      jobset.message('FAILED', 'Failed to build interop docker images.', 
+      jobset.message('FAILED', 'Failed to build interop docker images.',
                      do_newline=True)
       for image in docker_images.itervalues():
         dockerjob.remove_image(image, skip_nonexistent=True)
@@ -622,7 +638,7 @@ 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:
@@ -630,7 +646,7 @@ try:
         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:
@@ -658,7 +674,7 @@ 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":
@@ -678,7 +694,7 @@ try:
       dockerjob.remove_image(image, skip_nonexistent=True)
     sys.exit(1)
 
-  num_failures, resultset = jobset.run(jobs, newline_on_success=True, 
+  num_failures, resultset = jobset.run(jobs, newline_on_success=True,
                                        maxjobs=args.jobs)
   if num_failures:
     jobset.message('FAILED', 'Some tests failed', do_newline=True)
@@ -686,7 +702,7 @@ try:
     jobset.message('SUCCESS', 'All tests passed', do_newline=True)
 
   report_utils.render_junit_xml_report(resultset, 'report.xml')
-  
+
   report_utils.render_interop_html_report(
       set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES, 
       _HTTP2_TEST_CASES, resultset, num_failures,
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index 848775e9b199e7c55361424a6f91c763785c85a3..042b40485df68d0f6e73b3be776d5d1ca20c047a 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -34,10 +34,18 @@ set -ex
 cd $(dirname $0)/../..
 
 ROOT=`pwd`
-GRPCIO_TEST=$ROOT/src/python/grpcio_test
+GRPCIO=$ROOT/src/python/grpcio
 export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG
 export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG
 export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
-source "python"$PYVER"_virtual_environment"/bin/activate
+export CFLAGS="-I$ROOT/include -std=c89"
+export LDFLAGS="-L$ROOT/libs/$CONFIG"
+export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
 
-"python"$PYVER $GRPCIO_TEST/setup.py test -a "-n8 --cov=grpc --junitxml=./report.xml --timeout=300 -v --boxed --timeout_method=thread"
+cd $GRPCIO
+tox
+
+mkdir -p $ROOT/reports
+rm -rf $ROOT/reports/python-coverage
+(mv -T $GRPCIO/htmlcov $ROOT/reports/python-coverage) || true
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 66a6f9f552565e9be7341cc872084cc336b85cec..082e52c3ee45bee55971cff60e67aca5850c0a01 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -702,6 +702,34 @@
       "test/core/httpcli/httpcli_test.c"
     ]
   }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "init_test", 
+    "src": [
+      "test/core/surface/init_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "invalid_call_argument_test", 
+    "src": [
+      "test/core/end2end/invalid_call_argument_test.c"
+    ]
+  }, 
   {
     "deps": [
       "gpr", 
@@ -798,20 +826,6 @@
       "test/core/compression/message_compress_test.c"
     ]
   }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "language": "c", 
-    "name": "multi_init_test", 
-    "src": [
-      "test/core/surface/multi_init_test.c"
-    ]
-  }, 
   {
     "deps": [
       "gpr", 
@@ -14194,6 +14208,21 @@
       "test/core/bad_client/tests/connection_prefix.c"
     ]
   }, 
+  {
+    "deps": [
+      "bad_client_test", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "headers_bad_client_test", 
+    "src": [
+      "test/core/bad_client/tests/headers.c"
+    ]
+  }, 
   {
     "deps": [
       "bad_client_test", 
@@ -14209,6 +14238,21 @@
       "test/core/bad_client/tests/initial_settings_frame.c"
     ]
   }, 
+  {
+    "deps": [
+      "bad_client_test", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "unknown_frame_bad_client_test", 
+    "src": [
+      "test/core/bad_client/tests/unknown_frame.c"
+    ]
+  }, 
   {
     "deps": [], 
     "headers": [
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 2431001316b527471d346cc072ce20bd1f003b0b..7d24d67768220f6cb001049b7d0c9f5f1fcf48a7 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -807,7 +807,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "json_rewrite_test", 
+    "name": "init_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -825,7 +825,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "json_test", 
+    "name": "invalid_call_argument_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -843,7 +843,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "lame_client_test", 
+    "name": "json_rewrite_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -861,7 +861,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "lb_policies_test", 
+    "name": "json_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -879,7 +879,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "message_compress_test", 
+    "name": "lame_client_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -897,7 +897,25 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "multi_init_test", 
+    "name": "lb_policies_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "message_compress_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -15447,6 +15465,24 @@
       "windows"
     ]
   }, 
+  {
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "headers_bad_client_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
   {
     "ci_platforms": [
       "linux", 
@@ -15464,5 +15500,23 @@
       "posix", 
       "windows"
     ]
+  }, 
+  {
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "unknown_frame_bad_client_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
   }
 ]
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index be259e872bbdc14b37fde1e378a915501a9c7fac..b2c118efb7ca58ce93b073ccfbd59fc1c7f9a607 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1599,16 +1599,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpcli_parser_test", "vcxp
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_rewrite", "vcxproj\test\json_rewrite\json_rewrite.vcxproj", "{57B36FF6-25B1-2475-D07A-2E9097E2C792}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "init_test", "vcxproj\test\init_test\init_test.vcxproj", "{117CA7AD-C42B-9217-6C95-42A801777BC5}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_rewrite_test", "vcxproj\test\json_rewrite_test\json_rewrite_test.vcxproj", "{DD4C2B4E-9C47-6AA4-8E16-7B69AF8FA1D2}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "invalid_call_argument_test", "vcxproj\test\invalid_call_argument_test\invalid_call_argument_test.vcxproj", "{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1619,7 +1621,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_rewrite_test", "vcxpro
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_test", "vcxproj\test\json_test\json_test.vcxproj", "{05230AC7-4529-E6CF-0506-A063B5FF6642}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_rewrite", "vcxproj\test\json_rewrite\json_rewrite.vcxproj", "{57B36FF6-25B1-2475-D07A-2E9097E2C792}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_rewrite_test", "vcxproj\test\json_rewrite_test\json_rewrite_test.vcxproj", "{DD4C2B4E-9C47-6AA4-8E16-7B69AF8FA1D2}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1630,7 +1641,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_test", "vcxproj\test\j
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lame_client_test", "vcxproj\test\lame_client_test\lame_client_test.vcxproj", "{6E60B394-E17D-658A-6648-A2E6E183226F}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json_test", "vcxproj\test\json_test\json_test.vcxproj", "{05230AC7-4529-E6CF-0506-A063B5FF6642}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1641,7 +1652,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lame_client_test", "vcxproj
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lb_policies_test", "vcxproj\test\lb_policies_test\lb_policies_test.vcxproj", "{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lame_client_test", "vcxproj\test\lame_client_test\lame_client_test.vcxproj", "{6E60B394-E17D-658A-6648-A2E6E183226F}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1652,7 +1663,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lb_policies_test", "vcxproj
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_compress_test", "vcxproj\test\message_compress_test\message_compress_test.vcxproj", "{07170557-CCB0-D23C-8018-C2909D115DF9}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lb_policies_test", "vcxproj\test\lb_policies_test\lb_policies_test.vcxproj", "{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1663,7 +1674,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_compress_test", "vc
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_init_test", "vcxproj\test\multi_init_test\multi_init_test.vcxproj", "{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_compress_test", "vcxproj\test\message_compress_test\message_compress_test.vcxproj", "{07170557-CCB0-D23C-8018-C2909D115DF9}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -10012,6 +10023,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "connection_prefix_bad_clien
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "headers_bad_client_test", "vcxproj\test\headers_bad_client_test\headers_bad_client_test.vcxproj", "{7819A11E-607E-F0C0-FC47-C704CF7D818C}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{BA67B418-B699-E41A-9CC4-0279C49481A5} = {BA67B418-B699-E41A-9CC4-0279C49481A5}
+		{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} = {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "initial_settings_frame_bad_client_test", "vcxproj\test\initial_settings_frame_bad_client_test\initial_settings_frame_bad_client_test.vcxproj", "{6756895E-05BF-8CC7-58F2-868DF0C0300C}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -10024,6 +10047,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "initial_settings_frame_bad_
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unknown_frame_bad_client_test", "vcxproj\test\unknown_frame_bad_client_test\unknown_frame_bad_client_test.vcxproj", "{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{BA67B418-B699-E41A-9CC4-0279C49481A5} = {BA67B418-B699-E41A-9CC4-0279C49481A5}
+		{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} = {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -12388,6 +12423,38 @@ Global
 		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|Win32.Build.0 = Release|Win32
 		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|x64.ActiveCfg = Release|x64
 		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|x64.Build.0 = Release|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug|Win32.ActiveCfg = Debug|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug|x64.ActiveCfg = Debug|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release|Win32.ActiveCfg = Release|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release|x64.ActiveCfg = Release|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug|Win32.Build.0 = Debug|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug|x64.Build.0 = Debug|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release|Win32.Build.0 = Release|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release|x64.Build.0 = Release|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug-DLL|x64.Build.0 = Debug|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release-DLL|Win32.Build.0 = Release|Win32
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release-DLL|x64.ActiveCfg = Release|x64
+		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release-DLL|x64.Build.0 = Release|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug|x64.ActiveCfg = Debug|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release|Win32.ActiveCfg = Release|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release|x64.ActiveCfg = Release|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug|Win32.Build.0 = Debug|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug|x64.Build.0 = Debug|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release|Win32.Build.0 = Release|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release|x64.Build.0 = Release|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug-DLL|x64.Build.0 = Debug|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release-DLL|Win32.Build.0 = Release|Win32
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release-DLL|x64.ActiveCfg = Release|x64
+		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release-DLL|x64.Build.0 = Release|x64
 		{57B36FF6-25B1-2475-D07A-2E9097E2C792}.Debug|Win32.ActiveCfg = Debug|Win32
 		{57B36FF6-25B1-2475-D07A-2E9097E2C792}.Debug|x64.ActiveCfg = Debug|x64
 		{57B36FF6-25B1-2475-D07A-2E9097E2C792}.Release|Win32.ActiveCfg = Release|Win32
@@ -12484,22 +12551,6 @@ Global
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release-DLL|Win32.Build.0 = Release|Win32
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release-DLL|x64.ActiveCfg = Release|x64
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release-DLL|x64.Build.0 = Release|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug|Win32.ActiveCfg = Debug|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug|x64.ActiveCfg = Debug|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release|Win32.ActiveCfg = Release|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release|x64.ActiveCfg = Release|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug|Win32.Build.0 = Debug|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug|x64.Build.0 = Debug|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release|Win32.Build.0 = Release|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release|x64.Build.0 = Release|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Debug-DLL|x64.Build.0 = Debug|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release-DLL|Win32.Build.0 = Release|Win32
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release-DLL|x64.ActiveCfg = Release|x64
-		{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}.Release-DLL|x64.Build.0 = Release|x64
 		{88AF688E-E43C-5E20-6966-CF559F597D82}.Debug|Win32.ActiveCfg = Debug|Win32
 		{88AF688E-E43C-5E20-6966-CF559F597D82}.Debug|x64.ActiveCfg = Debug|x64
 		{88AF688E-E43C-5E20-6966-CF559F597D82}.Release|Win32.ActiveCfg = Release|Win32
@@ -22340,6 +22391,22 @@ Global
 		{AF9D0EB2-2A53-B815-3A63-E82C7F91DB29}.Release-DLL|Win32.Build.0 = Release|Win32
 		{AF9D0EB2-2A53-B815-3A63-E82C7F91DB29}.Release-DLL|x64.ActiveCfg = Release|x64
 		{AF9D0EB2-2A53-B815-3A63-E82C7F91DB29}.Release-DLL|x64.Build.0 = Release|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug|x64.ActiveCfg = Debug|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release|Win32.ActiveCfg = Release|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release|x64.ActiveCfg = Release|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug|Win32.Build.0 = Debug|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug|x64.Build.0 = Debug|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release|Win32.Build.0 = Release|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release|x64.Build.0 = Release|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Debug-DLL|x64.Build.0 = Debug|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release-DLL|Win32.Build.0 = Release|Win32
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release-DLL|x64.ActiveCfg = Release|x64
+		{7819A11E-607E-F0C0-FC47-C704CF7D818C}.Release-DLL|x64.Build.0 = Release|x64
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Debug|x64.ActiveCfg = Debug|x64
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release|Win32.ActiveCfg = Release|Win32
@@ -22356,6 +22423,22 @@ Global
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release-DLL|Win32.Build.0 = Release|Win32
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release-DLL|x64.ActiveCfg = Release|x64
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release-DLL|x64.Build.0 = Release|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug|x64.ActiveCfg = Debug|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release|Win32.ActiveCfg = Release|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release|x64.ActiveCfg = Release|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug|Win32.Build.0 = Debug|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug|x64.Build.0 = Debug|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release|Win32.Build.0 = Release|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release|x64.Build.0 = Release|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug-DLL|x64.Build.0 = Debug|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release-DLL|Win32.Build.0 = Release|Win32
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release-DLL|x64.ActiveCfg = Release|x64
+		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release-DLL|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/vsprojects/vcxproj/test/headers_bad_client_test/headers_bad_client_test.vcxproj b/vsprojects/vcxproj/test/headers_bad_client_test/headers_bad_client_test.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..8f701e77e7abbf7a161922ba5e4f7444c6473b0e
--- /dev/null
+++ b/vsprojects/vcxproj/test/headers_bad_client_test/headers_bad_client_test.vcxproj
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{7819A11E-607E-F0C0-FC47-C704CF7D818C}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="..\..\..\..\vsprojects\global.props" />
+    <Import Project="..\..\..\..\vsprojects\openssl.props" />
+    <Import Project="..\..\..\..\vsprojects\winsock.props" />
+    <Import Project="..\..\..\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>headers_bad_client_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>headers_bad_client_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\..\test\core\bad_client\tests\headers.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\test\bad_client_test\bad_client_test.vcxproj">
+      <Project>{BA67B418-B699-E41A-9CC4-0279C49481A5}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc_test_util_unsecure\grpc_test_util_unsecure.vcxproj">
+      <Project>{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc_unsecure\grpc_unsecure.vcxproj">
+      <Project>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/headers_bad_client_test/headers_bad_client_test.vcxproj.filters b/vsprojects/vcxproj/test/headers_bad_client_test/headers_bad_client_test.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..7a668cbb4889073dfee9dee80bee75c4e06eca8b
--- /dev/null
+++ b/vsprojects/vcxproj/test/headers_bad_client_test/headers_bad_client_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="..\..\..\..\test\core\bad_client\tests\headers.c">
+      <Filter>test\core\bad_client\tests</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{bdc6ff03-9ac0-5d30-d9ed-40818f6564e6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{d3e7fdf7-05cb-3f0a-21fb-693d2778fc8c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\bad_client">
+      <UniqueIdentifier>{127cb39a-52f9-f426-43ce-05c25664b685}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\bad_client\tests">
+      <UniqueIdentifier>{57a2c0dc-4757-15ea-5ae5-500deffa46fd}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/multi_init_test/multi_init_test.vcxproj b/vsprojects/vcxproj/test/init_test/init_test.vcxproj
similarity index 98%
rename from vsprojects/vcxproj/test/multi_init_test/multi_init_test.vcxproj
rename to vsprojects/vcxproj/test/init_test/init_test.vcxproj
index d4ef5a1e69c7241f03e2e80e6f77528b4b96610c..9653c936d641c0f4455c7efa03a2b10fc2f180e9 100644
--- a/vsprojects/vcxproj/test/multi_init_test/multi_init_test.vcxproj
+++ b/vsprojects/vcxproj/test/init_test/init_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{26D0B11B-FCB4-6527-4B5E-FC2A51BE5FB9}</ProjectGuid>
+    <ProjectGuid>{117CA7AD-C42B-9217-6C95-42A801777BC5}</ProjectGuid>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
@@ -55,13 +55,13 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>multi_init_test</TargetName>
+    <TargetName>init_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>multi_init_test</TargetName>
+    <TargetName>init_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
@@ -143,7 +143,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\..\..\test\core\surface\multi_init_test.c">
+    <ClCompile Include="..\..\..\..\test\core\surface\init_test.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/multi_init_test/multi_init_test.vcxproj.filters b/vsprojects/vcxproj/test/init_test/init_test.vcxproj.filters
similarity index 63%
rename from vsprojects/vcxproj/test/multi_init_test/multi_init_test.vcxproj.filters
rename to vsprojects/vcxproj/test/init_test/init_test.vcxproj.filters
index e1e8efc831bc3ffb57078a473c58d836e67a729d..9188683c110529e9b0ac5b619d606e6366de94e2 100644
--- a/vsprojects/vcxproj/test/multi_init_test/multi_init_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/init_test/init_test.vcxproj.filters
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="..\..\..\..\test\core\surface\multi_init_test.c">
+    <ClCompile Include="..\..\..\..\test\core\surface\init_test.c">
       <Filter>test\core\surface</Filter>
     </ClCompile>
   </ItemGroup>
 
   <ItemGroup>
     <Filter Include="test">
-      <UniqueIdentifier>{9fd58330-04b7-e69b-7217-2b6df7135781}</UniqueIdentifier>
+      <UniqueIdentifier>{a29deb69-37b5-31c0-c4a2-da409b5fe7ac}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core">
-      <UniqueIdentifier>{a1129343-c108-ef14-75a6-89805909cda1}</UniqueIdentifier>
+      <UniqueIdentifier>{cecabaca-db86-b86c-3ad7-ad6fc6958f15}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core\surface">
-      <UniqueIdentifier>{7b12af46-5c98-9a39-b0db-82bdc9fb52d2}</UniqueIdentifier>
+      <UniqueIdentifier>{93a3608f-710d-f929-fa89-6f762d06cb4c}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vcxproj/test/invalid_call_argument_test/invalid_call_argument_test.vcxproj b/vsprojects/vcxproj/test/invalid_call_argument_test/invalid_call_argument_test.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..427687dc57411bb6d863cd3f8ca2b3632fc2f2ab
--- /dev/null
+++ b/vsprojects/vcxproj/test/invalid_call_argument_test/invalid_call_argument_test.vcxproj
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="..\..\..\..\vsprojects\global.props" />
+    <Import Project="..\..\..\..\vsprojects\openssl.props" />
+    <Import Project="..\..\..\..\vsprojects\winsock.props" />
+    <Import Project="..\..\..\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>invalid_call_argument_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>invalid_call_argument_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\..\test\core\end2end\invalid_call_argument_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/invalid_call_argument_test/invalid_call_argument_test.vcxproj.filters b/vsprojects/vcxproj/test/invalid_call_argument_test/invalid_call_argument_test.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..a13db9dcb12f9a970456596f0a6077e79f999cc1
--- /dev/null
+++ b/vsprojects/vcxproj/test/invalid_call_argument_test/invalid_call_argument_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="..\..\..\..\test\core\end2end\invalid_call_argument_test.c">
+      <Filter>test\core\end2end</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{d5718e1e-f9c3-5b35-6b92-0309cc63bcf3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{f192acd9-1a23-2b42-3be6-6dd97ffc4778}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{b3e4e7e4-425a-9fc6-6771-7ac8cc4d78eb}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/unknown_frame_bad_client_test/unknown_frame_bad_client_test.vcxproj b/vsprojects/vcxproj/test/unknown_frame_bad_client_test/unknown_frame_bad_client_test.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..21104cafe6498d0fddbb61b2d56fd11a95e51f11
--- /dev/null
+++ b/vsprojects/vcxproj/test/unknown_frame_bad_client_test/unknown_frame_bad_client_test.vcxproj
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="..\..\..\..\vsprojects\global.props" />
+    <Import Project="..\..\..\..\vsprojects\openssl.props" />
+    <Import Project="..\..\..\..\vsprojects\winsock.props" />
+    <Import Project="..\..\..\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>unknown_frame_bad_client_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>unknown_frame_bad_client_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\..\test\core\bad_client\tests\unknown_frame.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\test\bad_client_test\bad_client_test.vcxproj">
+      <Project>{BA67B418-B699-E41A-9CC4-0279C49481A5}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc_test_util_unsecure\grpc_test_util_unsecure.vcxproj">
+      <Project>{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc_unsecure\grpc_unsecure.vcxproj">
+      <Project>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/unknown_frame_bad_client_test/unknown_frame_bad_client_test.vcxproj.filters b/vsprojects/vcxproj/test/unknown_frame_bad_client_test/unknown_frame_bad_client_test.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..d585856331f70adb5c58394568dff6c4b20959e8
--- /dev/null
+++ b/vsprojects/vcxproj/test/unknown_frame_bad_client_test/unknown_frame_bad_client_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="..\..\..\..\test\core\bad_client\tests\unknown_frame.c">
+      <Filter>test\core\bad_client\tests</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{77ca54f4-deb2-3a34-5548-0a2bc7cbacc1}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{2e30ac00-932d-ab0d-fabf-e0ea035aae46}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\bad_client">
+      <UniqueIdentifier>{527abde4-b314-c50f-b007-dd3fdb2445ba}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\bad_client\tests">
+      <UniqueIdentifier>{691de782-c331-3836-ac26-43873334f0c0}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+