소스 검색

Merge remote-tracking branch 'upstream/master' into trailing_metadata_status

kpayson64 7 년 전
부모
커밋
586267cd8d
100개의 변경된 파일1254개의 추가작업 그리고 3972개의 파일을 삭제
  1. 6 0
      .clang-tidy
  2. 9 2
      .pylintrc
  3. 9 2
      .pylintrc-tests
  4. 47 0
      CMakeLists.txt
  5. 50 0
      Makefile
  6. 2 1
      bazel/grpc_build_system.bzl
  7. 1 0
      build.yaml
  8. 1 0
      gRPC-Core.podspec
  9. 2 0
      grpc.gyp
  10. 2 0
      include/grpc/impl/codegen/grpc_types.h
  11. 7 4
      include/grpcpp/impl/codegen/call.h
  12. 26 3
      include/grpcpp/impl/codegen/server_interface.h
  13. 2 0
      include/grpcpp/server_builder.h
  14. 2 1
      src/compiler/csharp_generator.cc
  15. 63 36
      src/core/ext/filters/client_channel/client_channel.cc
  16. 13 0
      src/core/ext/filters/client_channel/http_proxy.cc
  17. 29 34
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
  18. 2 3
      src/core/ext/filters/deadline/deadline_filter.cc
  19. 1 3
      src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
  20. 1 1
      src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
  21. 3 2
      src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
  22. 2 0
      src/core/lib/gprpp/inlined_vector.h
  23. 12 12
      src/core/lib/iomgr/call_combiner.h
  24. 3 1
      src/core/lib/iomgr/cfstream_handle.cc
  25. 2 2
      src/core/lib/iomgr/endpoint_pair_posix.cc
  26. 12 0
      src/core/lib/iomgr/error.cc
  27. 5 0
      src/core/lib/iomgr/error.h
  28. 36 9
      src/core/lib/iomgr/ev_epoll1_linux.cc
  29. 45 10
      src/core/lib/iomgr/ev_epollex_linux.cc
  30. 47 21
      src/core/lib/iomgr/ev_epollsig_linux.cc
  31. 10 4
      src/core/lib/iomgr/ev_poll_posix.cc
  32. 17 9
      src/core/lib/iomgr/ev_posix.cc
  33. 20 4
      src/core/lib/iomgr/ev_posix.h
  34. 7 7
      src/core/lib/iomgr/tcp_client_cfstream.cc
  35. 3 5
      src/core/lib/iomgr/tcp_client_posix.cc
  36. 1 1
      src/core/lib/iomgr/tcp_posix.cc
  37. 3 3
      src/core/lib/iomgr/tcp_server_posix.cc
  38. 1 1
      src/core/lib/iomgr/tcp_server_utils_posix_common.cc
  39. 2 3
      src/core/lib/iomgr/udp_server.cc
  40. 14 4
      src/core/lib/surface/call.cc
  41. 1 1
      src/csharp/Grpc.Core.Testing/TestCalls.cs
  42. 2 0
      src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
  43. 101 0
      src/csharp/Grpc.Examples.Tests/MathClientMockableTest.cs
  44. 47 0
      src/csharp/Grpc.Examples.Tests/MathServiceImplTestabilityTest.cs
  45. 12 12
      src/csharp/Grpc.Examples/MathGrpc.cs
  46. 4 4
      src/csharp/Grpc.HealthCheck/HealthGrpc.cs
  47. 12 12
      src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs
  48. 0 23
      src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
  49. 0 1
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  50. 7 7
      src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
  51. 4 4
      src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs
  52. 33 33
      src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
  53. 15 15
      src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs
  54. 4 4
      src/csharp/Grpc.Reflection/ReflectionGrpc.cs
  55. 3 1
      src/csharp/tests.json
  56. 4 1
      src/objective-c/GRPCClient/GRPCCall.m
  57. 16 7
      src/objective-c/GRPCClient/private/GRPCHost.m
  58. 1 16
      src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
  59. 2 0
      src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m
  60. 3 3
      src/objective-c/tests/Connectivity/Podfile
  61. 2 1
      src/objective-c/tests/GRPCClientTests.m
  62. 2 1
      src/php/README.md
  63. 0 4
      src/proto/grpc/testing/messages.proto
  64. 10 8
      src/python/grpcio/grpc/__init__.py
  65. 2 5
      src/python/grpcio/grpc/_channel.py
  66. 0 0
      src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd.pxi
  67. 0 0
      src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
  68. 1 1
      src/python/grpcio/grpc/_cython/cygrpc.pxd
  69. 1 1
      src/python/grpcio/grpc/_cython/cygrpc.pyx
  70. 13 4
      src/python/grpcio/grpc/_interceptor.py
  71. 20 1
      src/python/grpcio/grpc/_server.py
  72. 2 0
      src/python/grpcio/grpc/_utilities.py
  73. 1 0
      src/python/grpcio/grpc/beta/_server_adaptations.py
  74. 2 0
      src/python/grpcio/grpc/beta/utilities.py
  75. 4 4
      src/python/grpcio/grpc/framework/foundation/stream_util.py
  76. 1 1
      src/python/grpcio_testing/grpc_testing/__init__.py
  77. 2 2
      src/python/grpcio_testing/grpc_testing/_server/_handler.py
  78. 6 5
      src/python/grpcio_tests/tests/_loader.py
  79. 15 26
      src/python/grpcio_tests/tests/_result.py
  80. 2 2
      src/python/grpcio_tests/tests/interop/methods.py
  81. 1 0
      src/python/grpcio_tests/tests/tests.json
  82. 0 13
      src/python/grpcio_tests/tests/unit/_junkdrawer/__init__.py
  83. 0 164
      src/python/grpcio_tests/tests/unit/_junkdrawer/stock_pb2.py
  84. 52 0
      src/python/grpcio_tests/tests/unit/_server_test.py
  85. 3 3
      templates/test/cpp/naming/resolver_component_tests_defs.include
  86. 0 3359
      test/core/avl/avl_test.cc
  87. 8 0
      test/core/end2end/end2end_nosec_tests.cc
  88. 8 0
      test/core/end2end/end2end_tests.cc
  89. 1 0
      test/core/end2end/gen_build_yaml.py
  90. 1 0
      test/core/end2end/generate_tests.bzl
  91. 246 0
      test/core/end2end/tests/no_error_on_hotpath.cc
  92. 2 0
      test/core/gprpp/inlined_vector_test.cc
  93. 1 0
      test/core/iomgr/BUILD
  94. 4 6
      test/core/iomgr/ev_epollsig_linux_test.cc
  95. 8 8
      test/core/iomgr/fd_posix_test.cc
  96. 2 3
      test/core/iomgr/pollset_set_test.cc
  97. 12 8
      test/core/iomgr/tcp_posix_test.cc
  98. 19 6
      test/core/transport/status_conversion_test.cc
  99. 5 0
      test/cpp/end2end/end2end_test.cc
  100. 4 4
      test/cpp/microbenchmarks/bm_pollset.cc

+ 6 - 0
.clang-tidy

@@ -0,0 +1,6 @@
+---
+Checks: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size'
+WarningsAsErrors: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size'
+CheckOptions:
+  - key:    readability-function-size.StatementThreshold
+    value:  '450'

+ 9 - 2
.pylintrc

@@ -72,6 +72,13 @@ disable=
 	# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have
 	# this one if we extracted just a few more helper functions...
 	too-many-nested-blocks,
-	# NOTE(nathaniel): I have disputed the premise of this inspection from
-	# the beginning and will continue to do so until it goes away for good.
+	# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary
+	# super-init requirement for abstract class implementations for now.
+	super-init-not-called,
+	# NOTE(nathaniel): A single statement that always returns program
+	# control is better than two statements the first of which sometimes
+	# returns program control and the second of which always returns
+	# program control. Probably generally, but definitely in the cases of
+	# if:/else: and for:/else:.
 	useless-else-on-loop,
+	no-else-return,

+ 9 - 2
.pylintrc-tests

@@ -103,6 +103,13 @@ disable=
 	# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have
 	# this one if we extracted just a few more helper functions...
 	too-many-nested-blocks,
-	# NOTE(nathaniel): I have disputed the premise of this inspection from
-	# the beginning and will continue to do so until it goes away for good.
+	# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary
+	# super-init requirement for abstract class implementations for now.
+	super-init-not-called,
+	# NOTE(nathaniel): A single statement that always returns program
+	# control is better than two statements the first of which sometimes
+	# returns program control and the second of which always returns
+	# program control. Probably generally, but definitely in the cases of
+	# if:/else: and for:/else:.
 	useless-else-on-loop,
+	no-else-return,

+ 47 - 0
CMakeLists.txt

@@ -663,6 +663,9 @@ endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx address_sorting_test)
 endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx cancel_ares_query_test)
+endif()
 
 add_custom_target(buildtests
   DEPENDS buildtests_c buildtests_cxx)
@@ -5298,6 +5301,7 @@ add_library(end2end_tests
   test/core/end2end/tests/max_message_length.cc
   test/core/end2end/tests/negative_deadline.cc
   test/core/end2end/tests/network_status_change.cc
+  test/core/end2end/tests/no_error_on_hotpath.cc
   test/core/end2end/tests/no_logging.cc
   test/core/end2end/tests/no_op.cc
   test/core/end2end/tests/payload.cc
@@ -5416,6 +5420,7 @@ add_library(end2end_nosec_tests
   test/core/end2end/tests/max_message_length.cc
   test/core/end2end/tests/negative_deadline.cc
   test/core/end2end/tests/network_status_change.cc
+  test/core/end2end/tests/no_error_on_hotpath.cc
   test/core/end2end/tests/no_logging.cc
   test/core/end2end/tests/no_op.cc
   test/core/end2end/tests/payload.cc
@@ -15840,6 +15845,48 @@ target_link_libraries(address_sorting_test
   ${_gRPC_GFLAGS_LIBRARIES}
 )
 
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
+add_executable(cancel_ares_query_test
+  test/cpp/naming/cancel_ares_query_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(cancel_ares_query_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(cancel_ares_query_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
+  grpc_test_util
+  gpr_test_util
+  grpc++
+  grpc
+  gpr
+  grpc++_test_config
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
 endif()
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)

+ 50 - 0
Makefile

@@ -1316,6 +1316,7 @@ resolver_component_tests_runner_invoker_unsecure: $(BINDIR)/$(CONFIG)/resolver_c
 resolver_component_tests_runner_invoker: $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker
 address_sorting_test_unsecure: $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure
 address_sorting_test: $(BINDIR)/$(CONFIG)/address_sorting_test
+cancel_ares_query_test: $(BINDIR)/$(CONFIG)/cancel_ares_query_test
 alts_credentials_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/alts_credentials_fuzzer_one_entry
 api_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/api_fuzzer_one_entry
 client_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/client_fuzzer_one_entry
@@ -1753,6 +1754,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
   $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
   $(BINDIR)/$(CONFIG)/address_sorting_test \
+  $(BINDIR)/$(CONFIG)/cancel_ares_query_test \
 
 else
 buildtests_cxx: privatelibs_cxx \
@@ -1877,6 +1879,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
   $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
   $(BINDIR)/$(CONFIG)/address_sorting_test \
+  $(BINDIR)/$(CONFIG)/cancel_ares_query_test \
 
 endif
 
@@ -2362,6 +2365,8 @@ test_cxx: buildtests_cxx
 	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure || ( echo test address_sorting_test_unsecure failed ; exit 1 )
 	$(E) "[RUN]     Testing address_sorting_test"
 	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test || ( echo test address_sorting_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cancel_ares_query_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cancel_ares_query_test || ( echo test cancel_ares_query_test failed ; exit 1 )
 
 
 flaky_test_cxx: buildtests_cxx
@@ -9991,6 +9996,7 @@ LIBEND2END_TESTS_SRC = \
     test/core/end2end/tests/max_message_length.cc \
     test/core/end2end/tests/negative_deadline.cc \
     test/core/end2end/tests/network_status_change.cc \
+    test/core/end2end/tests/no_error_on_hotpath.cc \
     test/core/end2end/tests/no_logging.cc \
     test/core/end2end/tests/no_op.cc \
     test/core/end2end/tests/payload.cc \
@@ -10107,6 +10113,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \
     test/core/end2end/tests/max_message_length.cc \
     test/core/end2end/tests/negative_deadline.cc \
     test/core/end2end/tests/network_status_change.cc \
+    test/core/end2end/tests/no_error_on_hotpath.cc \
     test/core/end2end/tests/no_logging.cc \
     test/core/end2end/tests/no_op.cc \
     test/core/end2end/tests/payload.cc \
@@ -23687,6 +23694,49 @@ endif
 endif
 
 
+CANCEL_ARES_QUERY_TEST_SRC = \
+    test/cpp/naming/cancel_ares_query_test.cc \
+
+CANCEL_ARES_QUERY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CANCEL_ARES_QUERY_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/cancel_ares_query_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/cancel_ares_query_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/cancel_ares_query_test: $(PROTOBUF_DEP) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cancel_ares_query_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/naming/cancel_ares_query_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+
+deps_cancel_ares_query_test: $(CANCEL_ARES_QUERY_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CANCEL_ARES_QUERY_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ALTS_CREDENTIALS_FUZZER_ONE_ENTRY_SRC = \
     test/core/security/alts_credentials_fuzzer.cc \
     test/core/util/one_corpus_entry_fuzzer.cc \

+ 2 - 1
bazel/grpc_build_system.bzl

@@ -110,7 +110,7 @@ def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = False,
     generate_mocks = generate_mocks,
   )
 
-def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate"):
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate", tags = []):
   copts = []
   if language.upper() == "C":
     copts = if_not_windows(["-std=c99"])
@@ -140,6 +140,7 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
           poller,
           '$(location %s)' % name,
         ] + args['args'],
+        tags = tags,
       )
   else:
     native.cc_test(**args)

+ 1 - 0
build.yaml

@@ -2032,6 +2032,7 @@ targets:
   dict: test/core/end2end/fuzzers/api_fuzzer.dictionary
   maxlen: 2048
 - name: arena_test
+  cpu_cost: 10
   build: test
   language: c
   src:

+ 1 - 0
gRPC-Core.podspec

@@ -1216,6 +1216,7 @@ Pod::Spec.new do |s|
                       'test/core/end2end/tests/max_message_length.cc',
                       'test/core/end2end/tests/negative_deadline.cc',
                       'test/core/end2end/tests/network_status_change.cc',
+                      'test/core/end2end/tests/no_error_on_hotpath.cc',
                       'test/core/end2end/tests/no_logging.cc',
                       'test/core/end2end/tests/no_op.cc',
                       'test/core/end2end/tests/payload.cc',

+ 2 - 0
grpc.gyp

@@ -2630,6 +2630,7 @@
         'test/core/end2end/tests/max_message_length.cc',
         'test/core/end2end/tests/negative_deadline.cc',
         'test/core/end2end/tests/network_status_change.cc',
+        'test/core/end2end/tests/no_error_on_hotpath.cc',
         'test/core/end2end/tests/no_logging.cc',
         'test/core/end2end/tests/no_op.cc',
         'test/core/end2end/tests/payload.cc',
@@ -2720,6 +2721,7 @@
         'test/core/end2end/tests/max_message_length.cc',
         'test/core/end2end/tests/negative_deadline.cc',
         'test/core/end2end/tests/network_status_change.cc',
+        'test/core/end2end/tests/no_error_on_hotpath.cc',
         'test/core/end2end/tests/no_logging.cc',
         'test/core/end2end/tests/no_op.cc',
         'test/core/end2end/tests/payload.cc',

+ 2 - 0
include/grpc/impl/codegen/grpc_types.h

@@ -336,6 +336,8 @@ typedef struct {
 /** If non-zero, client authority filter is disabled for the channel */
 #define GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER \
   "grpc.disable_client_authority_filter"
+/** If set to zero, disables use of http proxies. Enabled by default. */
+#define GRPC_ARG_ENABLE_HTTP_PROXY "grpc.enable_http_proxy"
 /** \} */
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a

+ 7 - 4
include/grpcpp/impl/codegen/call.h

@@ -573,10 +573,13 @@ class CallOpClientRecvStatus {
       binary_error_details =
           grpc::string(iter->second.begin(), iter->second.length());
     }
-    *recv_status_ = Status(static_cast<StatusCode>(status_code_),
-                           grpc::string(GRPC_SLICE_START_PTR(error_message_),
-                                        GRPC_SLICE_END_PTR(error_message_)),
-                           binary_error_details);
+    *recv_status_ =
+        Status(static_cast<StatusCode>(status_code_),
+               GRPC_SLICE_IS_EMPTY(error_message_)
+                   ? grpc::string()
+                   : grpc::string(GRPC_SLICE_START_PTR(error_message_),
+                                  GRPC_SLICE_END_PTR(error_message_)),
+               binary_error_details);
     client_context_->set_debug_error_string(
         debug_error_string_ != nullptr ? debug_error_string_ : "");
     g_core_codegen_interface->grpc_slice_unref(error_message_);

+ 26 - 3
include/grpcpp/impl/codegen/server_interface.h

@@ -49,12 +49,35 @@ class ServerInterface : public internal::CallHook {
  public:
   virtual ~ServerInterface() {}
 
-  /// Shutdown the server, blocking until all rpc processing finishes.
-  /// Forcefully terminate pending calls after \a deadline expires.
+  /// \a Shutdown does the following things:
+  ///
+  /// 1. Shutdown the server: deactivate all listening ports, mark it in
+  ///    "shutdown mode" so that further call Request's or incoming RPC matches
+  ///    are no longer allowed. Also return all Request'ed-but-not-yet-active
+  ///    calls as failed (!ok). This refers to calls that have been requested
+  ///    at the server by the server-side library or application code but that
+  ///    have not yet been matched to incoming RPCs from the client. Note that
+  ///    this would even include default calls added automatically by the gRPC
+  ///    C++ API without the user's input (e.g., "Unimplemented RPC method")
+  ///
+  /// 2. Block until all rpc method handlers invoked automatically by the sync
+  ///    API finish.
+  ///
+  /// 3. If all pending calls complete (and all their operations are
+  ///    retrieved by Next) before \a deadline expires, this finishes
+  ///    gracefully. Otherwise, forcefully cancel all pending calls associated
+  ///    with the server after \a deadline expires. In the case of the sync API,
+  ///    if the RPC function for a streaming call has already been started and
+  ///    takes a week to complete, the RPC function won't be forcefully
+  ///    terminated (since that would leave state corrupt and incomplete) and
+  ///    the method handler will just keep running (which will prevent the
+  ///    server from completing the "join" operation that it needs to do at
+  ///    shutdown time).
   ///
   /// All completion queue associated with the server (for example, for async
   /// serving) must be shutdown *after* this method has returned:
   /// See \a ServerBuilder::AddCompletionQueue for details.
+  /// They must also be drained (by repeated Next) after being shutdown.
   ///
   /// \param deadline How long to wait until pending rpcs are forcefully
   /// terminated.
@@ -63,7 +86,7 @@ class ServerInterface : public internal::CallHook {
     ShutdownInternal(TimePoint<T>(deadline).raw_time());
   }
 
-  /// Shutdown the server, waiting for all rpc processing to finish.
+  /// Shutdown the server without a deadline and forced cancellation.
   ///
   /// All completion queue associated with the server (for example, for async
   /// serving) must be shutdown *after* this method has returned:

+ 2 - 0
include/grpcpp/server_builder.h

@@ -144,12 +144,14 @@ class ServerBuilder {
   // Fine control knobs
 
   /// Set max receive message size in bytes.
+  /// The default is GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH.
   ServerBuilder& SetMaxReceiveMessageSize(int max_receive_message_size) {
     max_receive_message_size_ = max_receive_message_size;
     return *this;
   }
 
   /// Set max send message size in bytes.
+  /// The default is GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH.
   ServerBuilder& SetMaxSendMessageSize(int max_send_message_size) {
     max_send_message_size_ = max_send_message_size;
     return *this;

+ 2 - 1
src/compiler/csharp_generator.cc

@@ -202,7 +202,8 @@ std::string GetCSharpMethodType(MethodType method_type) {
 std::string GetServiceNameFieldName() { return "__ServiceName"; }
 
 std::string GetMarshallerFieldName(const Descriptor* message) {
-  return "__Marshaller_" + message->name();
+  return "__Marshaller_" +
+         grpc_generator::StringReplace(message->full_name(), ".", "_", true);
 }
 
 std::string GetMethodFieldName(const MethodDescriptor* method) {

+ 63 - 36
src/core/ext/filters/client_channel/client_channel.cc

@@ -1723,6 +1723,29 @@ static void recv_message_ready(void* arg, grpc_error* error) {
 // recv_trailing_metadata handling
 //
 
+// Sets *status and *server_pushback_md based on batch_data and error.
+static void get_call_status(subchannel_batch_data* batch_data,
+                            grpc_error* error, grpc_status_code* status,
+                            grpc_mdelem** server_pushback_md) {
+  grpc_call_element* elem = batch_data->elem;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (error != GRPC_ERROR_NONE) {
+    grpc_error_get_status(error, calld->deadline, status, nullptr, nullptr,
+                          nullptr);
+  } else {
+    grpc_metadata_batch* md_batch =
+        batch_data->batch.payload->recv_trailing_metadata
+            .recv_trailing_metadata;
+    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
+    *status =
+        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
+    if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
+      *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
 // Adds recv_trailing_metadata_ready closure to closures.
 static void add_closure_for_recv_trailing_metadata_ready(
     grpc_call_element* elem, subchannel_batch_data* batch_data,
@@ -1837,6 +1860,34 @@ static void add_closures_to_fail_unstarted_pending_batches(
   GRPC_ERROR_UNREF(error);
 }
 
+// Runs necessary closures upon completion of a call attempt.
+static void run_closures_for_completed_call(subchannel_batch_data* batch_data,
+                                            grpc_error* error) {
+  grpc_call_element* elem = batch_data->elem;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
+  // Construct list of closures to execute.
+  grpc_core::CallCombinerClosureList closures;
+  // First, add closure for recv_trailing_metadata_ready.
+  add_closure_for_recv_trailing_metadata_ready(
+      elem, batch_data, GRPC_ERROR_REF(error), &closures);
+  // If there are deferred recv_initial_metadata_ready or recv_message_ready
+  // callbacks, add them to closures.
+  add_closures_for_deferred_recv_callbacks(batch_data, retry_state, &closures);
+  // Add closures to fail any pending batches that have not yet been started.
+  add_closures_to_fail_unstarted_pending_batches(
+      elem, retry_state, GRPC_ERROR_REF(error), &closures);
+  // Don't need batch_data anymore.
+  batch_data_unref(batch_data);
+  // Schedule all of the closures identified above.
+  // Note: This will release the call combiner.
+  closures.RunClosures(calld->call_combiner);
+  GRPC_ERROR_UNREF(error);
+}
+
 // Intercepts recv_trailing_metadata_ready callback for retries.
 // Commits the call and returns the trailing metadata up the stack.
 static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
@@ -1857,20 +1908,8 @@ static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
   // Get the call's status and check for server pushback metadata.
   grpc_status_code status = GRPC_STATUS_OK;
   grpc_mdelem* server_pushback_md = nullptr;
-  if (error != GRPC_ERROR_NONE) {
-    grpc_error_get_status(error, calld->deadline, &status, nullptr, nullptr,
-                          nullptr);
-  } else {
-    grpc_metadata_batch* md_batch =
-        batch_data->batch.payload->recv_trailing_metadata
-            .recv_trailing_metadata;
-    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
-    status =
-        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
-    if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
-      server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
-    }
-  }
+  get_call_status(batch_data, GRPC_ERROR_REF(error), &status,
+                  &server_pushback_md);
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand,
             calld, grpc_status_code_to_string(status));
@@ -1892,36 +1931,24 @@ static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
   }
   // Not retrying, so commit the call.
   retry_commit(elem, retry_state);
-  // Construct list of closures to execute.
-  grpc_core::CallCombinerClosureList closures;
-  // First, add closure for recv_trailing_metadata_ready.
-  add_closure_for_recv_trailing_metadata_ready(
-      elem, batch_data, GRPC_ERROR_REF(error), &closures);
-  // If there are deferred recv_initial_metadata_ready or recv_message_ready
-  // callbacks, add them to closures.
-  add_closures_for_deferred_recv_callbacks(batch_data, retry_state, &closures);
-  // Add closures to fail any pending batches that have not yet been started.
-  add_closures_to_fail_unstarted_pending_batches(
-      elem, retry_state, GRPC_ERROR_REF(error), &closures);
-  // Don't need batch_data anymore.
-  batch_data_unref(batch_data);
-  // Schedule all of the closures identified above.
-  // Note: This will release the call combiner.
-  closures.RunClosures(calld->call_combiner);
+  // Run any necessary closures.
+  run_closures_for_completed_call(batch_data, GRPC_ERROR_REF(error));
 }
 
 //
 // on_complete callback handling
 //
 
-// For any pending batch completed in batch_data, adds the necessary
-// completion closures to closures.
+// Adds the on_complete closure for the pending batch completed in
+// batch_data to closures.
 static void add_closure_for_completed_pending_batch(
     grpc_call_element* elem, subchannel_batch_data* batch_data,
     subchannel_call_retry_state* retry_state, grpc_error* error,
     grpc_core::CallCombinerClosureList* closures) {
   pending_batch* pending = pending_batch_find(
       elem, "completed", [batch_data](grpc_transport_stream_op_batch* batch) {
+        // Match the pending batch with the same set of send ops as the
+        // subchannel batch we've just completed.
         return batch->on_complete != nullptr &&
                batch_data->batch.send_initial_metadata ==
                    batch->send_initial_metadata &&
@@ -2023,8 +2050,8 @@ static void on_complete(void* arg, grpc_error* error) {
     // Add closure for the completed pending batch, if any.
     add_closure_for_completed_pending_batch(elem, batch_data, retry_state,
                                             GRPC_ERROR_REF(error), &closures);
-    // If needed, add a callback to start_retriable_subchannel_batches() to
-    // start any replay or pending send ops on the subchannel call.
+    // If needed, add a callback to start any replay or pending send ops on
+    // the subchannel call.
     if (!retry_state->completed_recv_trailing_metadata) {
       add_closures_for_replay_or_pending_send_ops(elem, batch_data, retry_state,
                                                   &closures);
@@ -2033,7 +2060,7 @@ static void on_complete(void* arg, grpc_error* error) {
   // Track number of pending subchannel send batches and determine if this
   // was the last one.
   --calld->num_pending_retriable_subchannel_send_batches;
-  const bool last_callback_complete =
+  const bool last_send_batch_complete =
       calld->num_pending_retriable_subchannel_send_batches == 0;
   // Don't need batch_data anymore.
   batch_data_unref(batch_data);
@@ -2041,7 +2068,7 @@ static void on_complete(void* arg, grpc_error* error) {
   // Note: This yeilds the call combiner.
   closures.RunClosures(calld->call_combiner);
   // If this was the last subchannel send batch, unref the call stack.
-  if (last_callback_complete) {
+  if (last_send_batch_complete) {
     GRPC_CALL_STACK_UNREF(calld->owning_call, "subchannel_send_batches");
   }
 }

+ 13 - 0
src/core/ext/filters/client_channel/http_proxy.cc

@@ -83,11 +83,24 @@ done:
   return proxy_name;
 }
 
+/**
+ * Checks the value of GRPC_ARG_ENABLE_HTTP_PROXY to determine if http_proxy
+ * should be used.
+ */
+bool http_proxy_enabled(const grpc_channel_args* args) {
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_ENABLE_HTTP_PROXY);
+  return grpc_channel_arg_get_bool(arg, true);
+}
+
 static bool proxy_mapper_map_name(grpc_proxy_mapper* mapper,
                                   const char* server_uri,
                                   const grpc_channel_args* args,
                                   char** name_to_resolve,
                                   grpc_channel_args** new_args) {
+  if (!http_proxy_enabled(args)) {
+    return false;
+  }
   char* user_cred = nullptr;
   *name_to_resolve = get_http_proxy_server(&user_cred);
   if (*name_to_resolve == nullptr) return false;

+ 29 - 34
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc

@@ -21,6 +21,7 @@
 #if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER)
 
 #include <ares.h>
+#include <string.h>
 #include <sys/ioctl.h>
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
@@ -55,8 +56,8 @@ typedef struct fd_node {
   bool readable_registered;
   /** if the writable closure has been registered */
   bool writable_registered;
-  /** if the fd is being shut down */
-  bool shutting_down;
+  /** if the fd has been shutdown yet from grpc iomgr perspective */
+  bool already_shutdown;
 } fd_node;
 
 struct grpc_ares_ev_driver {
@@ -101,25 +102,20 @@ static void fd_node_destroy(fd_node* fdn) {
   gpr_log(GPR_DEBUG, "delete fd: %d", grpc_fd_wrapped_fd(fdn->fd));
   GPR_ASSERT(!fdn->readable_registered);
   GPR_ASSERT(!fdn->writable_registered);
+  GPR_ASSERT(fdn->already_shutdown);
   gpr_mu_destroy(&fdn->mu);
   /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up
      immediately by another thread, and should not be closed by the following
      grpc_fd_orphan. */
-  grpc_fd_orphan(fdn->fd, nullptr, nullptr, true /* already_closed */,
-                 "c-ares query finished");
+  int dummy_release_fd;
+  grpc_fd_orphan(fdn->fd, nullptr, &dummy_release_fd, "c-ares query finished");
   gpr_free(fdn);
 }
 
-static void fd_node_shutdown(fd_node* fdn) {
-  gpr_mu_lock(&fdn->mu);
-  fdn->shutting_down = true;
-  if (!fdn->readable_registered && !fdn->writable_registered) {
-    gpr_mu_unlock(&fdn->mu);
-    fd_node_destroy(fdn);
-  } else {
-    grpc_fd_shutdown(
-        fdn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING("c-ares fd shutdown"));
-    gpr_mu_unlock(&fdn->mu);
+static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) {
+  if (!fdn->already_shutdown) {
+    fdn->already_shutdown = true;
+    grpc_fd_shutdown(fdn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(reason));
   }
 }
 
@@ -127,7 +123,10 @@ grpc_error* grpc_ares_ev_driver_create(grpc_ares_ev_driver** ev_driver,
                                        grpc_pollset_set* pollset_set) {
   *ev_driver = static_cast<grpc_ares_ev_driver*>(
       gpr_malloc(sizeof(grpc_ares_ev_driver)));
-  int status = ares_init(&(*ev_driver)->channel);
+  ares_options opts;
+  memset(&opts, 0, sizeof(opts));
+  opts.flags |= ARES_FLAG_STAYOPEN;
+  int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS);
   gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create");
   if (status != ARES_SUCCESS) {
     char* err_msg;
@@ -164,8 +163,9 @@ void grpc_ares_ev_driver_shutdown(grpc_ares_ev_driver* ev_driver) {
   ev_driver->shutting_down = true;
   fd_node* fn = ev_driver->fds;
   while (fn != nullptr) {
-    grpc_fd_shutdown(fn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                 "grpc_ares_ev_driver_shutdown"));
+    gpr_mu_lock(&fn->mu);
+    fd_node_shutdown_locked(fn, "grpc_ares_ev_driver_shutdown");
+    gpr_mu_unlock(&fn->mu);
     fn = fn->next;
   }
   gpr_mu_unlock(&ev_driver->mu);
@@ -202,14 +202,7 @@ static void on_readable_cb(void* arg, grpc_error* error) {
   gpr_mu_lock(&fdn->mu);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
   fdn->readable_registered = false;
-  if (fdn->shutting_down && !fdn->writable_registered) {
-    gpr_mu_unlock(&fdn->mu);
-    fd_node_destroy(fdn);
-    grpc_ares_ev_driver_unref(ev_driver);
-    return;
-  }
   gpr_mu_unlock(&fdn->mu);
-
   gpr_log(GPR_DEBUG, "readable on %d", fd);
   if (error == GRPC_ERROR_NONE) {
     do {
@@ -236,14 +229,7 @@ static void on_writable_cb(void* arg, grpc_error* error) {
   gpr_mu_lock(&fdn->mu);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
   fdn->writable_registered = false;
-  if (fdn->shutting_down && !fdn->readable_registered) {
-    gpr_mu_unlock(&fdn->mu);
-    fd_node_destroy(fdn);
-    grpc_ares_ev_driver_unref(ev_driver);
-    return;
-  }
   gpr_mu_unlock(&fdn->mu);
-
   gpr_log(GPR_DEBUG, "writable on %d", fd);
   if (error == GRPC_ERROR_NONE) {
     ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, fd);
@@ -284,11 +270,11 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
           gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i);
           fdn = static_cast<fd_node*>(gpr_malloc(sizeof(fd_node)));
           gpr_log(GPR_DEBUG, "new fd: %d", socks[i]);
-          fdn->fd = grpc_fd_create(socks[i], fd_name);
+          fdn->fd = grpc_fd_create(socks[i], fd_name, false);
           fdn->ev_driver = ev_driver;
           fdn->readable_registered = false;
           fdn->writable_registered = false;
-          fdn->shutting_down = false;
+          fdn->already_shutdown = false;
           gpr_mu_init(&fdn->mu);
           GRPC_CLOSURE_INIT(&fdn->read_closure, on_readable_cb, fdn,
                             grpc_schedule_on_exec_ctx);
@@ -329,7 +315,16 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
   while (ev_driver->fds != nullptr) {
     fd_node* cur = ev_driver->fds;
     ev_driver->fds = ev_driver->fds->next;
-    fd_node_shutdown(cur);
+    gpr_mu_lock(&cur->mu);
+    fd_node_shutdown_locked(cur, "c-ares fd shutdown");
+    if (!cur->readable_registered && !cur->writable_registered) {
+      gpr_mu_unlock(&cur->mu);
+      fd_node_destroy(cur);
+    } else {
+      cur->next = new_list;
+      new_list = cur;
+      gpr_mu_unlock(&cur->mu);
+    }
   }
   ev_driver->fds = new_list;
   // If the ev driver has no working fd, all the tasks are done.

+ 2 - 3
src/core/ext/filters/deadline/deadline_filter.cc

@@ -293,11 +293,10 @@ static void client_start_transport_stream_op_batch(
 static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
-  // Get deadline from metadata and start the timer if needed.
   start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
   // Invoke the next callback.
-  calld->next_recv_initial_metadata_ready->cb(
-      calld->next_recv_initial_metadata_ready->cb_arg, error);
+  GRPC_CLOSURE_RUN(calld->next_recv_initial_metadata_ready,
+                   GRPC_ERROR_REF(error));
 }
 
 // Method for starting a call op for server filter.

+ 1 - 3
src/core/ext/filters/load_reporting/server_load_reporting_filter.cc

@@ -82,9 +82,7 @@ static void on_initial_md_ready(void* user_data, grpc_error* err) {
   } else {
     GRPC_ERROR_REF(err);
   }
-  calld->ops_recv_initial_metadata_ready->cb(
-      calld->ops_recv_initial_metadata_ready->cb_arg, err);
-  GRPC_ERROR_UNREF(err);
+  GRPC_CLOSURE_RUN(calld->ops_recv_initial_metadata_ready, err);
 }
 
 /* Constructor for call_data */

+ 1 - 1
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc

@@ -50,7 +50,7 @@ grpc_channel* grpc_insecure_channel_create_from_fd(
   GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
 
   grpc_endpoint* client = grpc_tcp_client_create_from_fd(
-      grpc_fd_create(fd, "client"), args, "fd-client");
+      grpc_fd_create(fd, "client", false), args, "fd-client");
 
   grpc_transport* transport =
       grpc_create_chttp2_transport(final_args, client, true);

+ 3 - 2
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc

@@ -43,8 +43,9 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
   char* name;
   gpr_asprintf(&name, "fd:%d", fd);
 
-  grpc_endpoint* server_endpoint = grpc_tcp_create(
-      grpc_fd_create(fd, name), grpc_server_get_channel_args(server), name);
+  grpc_endpoint* server_endpoint =
+      grpc_tcp_create(grpc_fd_create(fd, name, false),
+                      grpc_server_get_channel_args(server), name);
 
   gpr_free(name);
 

+ 2 - 0
src/core/lib/gprpp/inlined_vector.h

@@ -99,6 +99,8 @@ class InlinedVector {
   void push_back(T&& value) { emplace_back(std::move(value)); }
 
   size_t size() const { return size_; }
+  bool empty() const { return size_ == 0; }
+
   size_t capacity() const { return capacity_; }
 
   void clear() {

+ 12 - 12
src/core/lib/iomgr/call_combiner.h

@@ -137,24 +137,24 @@ class CallCombinerClosureList {
   // yielding the call combiner.  If the list is empty, then the call
   // combiner will be yielded immediately.
   void RunClosures(grpc_call_combiner* call_combiner) {
+    if (closures_.empty()) {
+      GRPC_CALL_COMBINER_STOP(call_combiner, "no closures to schedule");
+      return;
+    }
     for (size_t i = 1; i < closures_.size(); ++i) {
       auto& closure = closures_[i];
       GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error,
                                closure.reason);
     }
-    if (closures_.size() > 0) {
-      if (grpc_call_combiner_trace.enabled()) {
-        gpr_log(GPR_INFO,
-                "CallCombinerClosureList executing closure while already "
-                "holding call_combiner %p: closure=%p error=%s reason=%s",
-                call_combiner, closures_[0].closure,
-                grpc_error_string(closures_[0].error), closures_[0].reason);
-      }
-      // This will release the call combiner.
-      GRPC_CLOSURE_SCHED(closures_[0].closure, closures_[0].error);
-    } else {
-      GRPC_CALL_COMBINER_STOP(call_combiner, "no closures to schedule");
+    if (grpc_call_combiner_trace.enabled()) {
+      gpr_log(GPR_INFO,
+              "CallCombinerClosureList executing closure while already "
+              "holding call_combiner %p: closure=%p error=%s reason=%s",
+              call_combiner, closures_[0].closure,
+              grpc_error_string(closures_[0].error), closures_[0].reason);
     }
+    // This will release the call combiner.
+    GRPC_CLOSURE_SCHED(closures_[0].closure, closures_[0].error);
     closures_.clear();
   }
 

+ 3 - 1
src/core/lib/iomgr/cfstream_handle.cc

@@ -116,7 +116,9 @@ CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream,
   open_event_.InitEvent();
   read_event_.InitEvent();
   write_event_.InitEvent();
-  CFStreamClientContext ctx = {0, static_cast<void*>(this), nil, nil, nil};
+  CFStreamClientContext ctx = {0, static_cast<void*>(this),
+                               CFStreamHandle::Retain, CFStreamHandle::Release,
+                               nil};
   CFReadStreamSetClient(
       read_stream,
       kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable |

+ 2 - 2
src/core/lib/iomgr/endpoint_pair_posix.cc

@@ -59,11 +59,11 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char* name,
   grpc_core::ExecCtx exec_ctx;
 
   gpr_asprintf(&final_name, "%s:client", name);
-  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), args,
+  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name, false), args,
                              "socketpair-server");
   gpr_free(final_name);
   gpr_asprintf(&final_name, "%s:server", name);
-  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), args,
+  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name, false), args,
                              "socketpair-client");
   gpr_free(final_name);
 

+ 12 - 0
src/core/lib/iomgr/error.cc

@@ -312,6 +312,12 @@ static void internal_add_error(grpc_error** err, grpc_error* new_err) {
 // It is very common to include and extra int and string in an error
 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
 
+static bool g_error_creation_allowed = true;
+
+void grpc_disable_error_creation() { g_error_creation_allowed = false; }
+
+void grpc_enable_error_creation() { g_error_creation_allowed = true; }
+
 grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
                               grpc_error** referencing,
                               size_t num_referencing) {
@@ -326,6 +332,12 @@ grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
     return GRPC_ERROR_OOM;
   }
 #ifndef NDEBUG
+  if (!g_error_creation_allowed) {
+    gpr_log(GPR_ERROR,
+            "Error creation occurred when error creation was disabled [%s:%d]",
+            file, line);
+    abort();
+  }
   if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
   }

+ 5 - 0
src/core/lib/iomgr/error.h

@@ -123,6 +123,11 @@ typedef enum {
 #define GRPC_ERROR_OOM ((grpc_error*)2)
 #define GRPC_ERROR_CANCELLED ((grpc_error*)4)
 
+// debug only toggles that allow for a sanity to check that ensures we will
+// never create any errors in the per-RPC hotpath.
+void grpc_disable_error_creation();
+void grpc_enable_error_creation();
+
 const char* grpc_error_string(grpc_error* error);
 
 /// Create an error - but use GRPC_ERROR_CREATE instead

+ 36 - 9
src/core/lib/iomgr/ev_epoll1_linux.cc

@@ -136,6 +136,7 @@ struct grpc_fd {
 
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
+  grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
 
   struct grpc_fd* freelist_next;
 
@@ -272,7 +273,7 @@ static void fd_global_shutdown(void) {
   gpr_mu_destroy(&fd_freelist_mu);
 }
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
   grpc_fd* new_fd = nullptr;
 
   gpr_mu_lock(&fd_freelist_mu);
@@ -286,11 +287,12 @@ static grpc_fd* fd_create(int fd, const char* name) {
     new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
+    new_fd->error_closure.Init();
   }
-
   new_fd->fd = fd;
   new_fd->read_closure->InitEvent();
   new_fd->write_closure->InitEvent();
+  new_fd->error_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = nullptr;
@@ -307,7 +309,13 @@ static grpc_fd* fd_create(int fd, const char* name) {
 
   struct epoll_event ev;
   ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
-  ev.data.ptr = new_fd;
+  /* Use the least significant bit of ev.data.ptr to store track_err. We expect
+   * the addresses to be word aligned. We need to store track_err to avoid
+   * synchronization issues when accessing it after receiving an event.
+   * Accessing fd would be a data race there because the fd might have been
+   * returned to the free list at that point. */
+  ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(new_fd) |
+                                        (track_err ? 1 : 0));
   if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
     gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
   }
@@ -327,6 +335,7 @@ static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why,
       shutdown(fd->fd, SHUT_RDWR);
     }
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
+    fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
   }
   GRPC_ERROR_UNREF(why);
 }
@@ -337,7 +346,7 @@ static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
 }
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
+                      const char* reason) {
   grpc_error* error = GRPC_ERROR_NONE;
   bool is_release_fd = (release_fd != nullptr);
 
@@ -350,7 +359,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
      descriptor fd->fd (but we still own the grpc_fd structure). */
   if (is_release_fd) {
     *release_fd = fd->fd;
-  } else if (!already_closed) {
+  } else {
     close(fd->fd);
   }
 
@@ -359,6 +368,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
   grpc_iomgr_unregister_object(&fd->iomgr_object);
   fd->read_closure->DestroyEvent();
   fd->write_closure->DestroyEvent();
+  fd->error_closure->DestroyEvent();
 
   gpr_mu_lock(&fd_freelist_mu);
   fd->freelist_next = fd_freelist;
@@ -383,6 +393,10 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   fd->write_closure->NotifyOn(closure);
 }
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  fd->error_closure->NotifyOn(closure);
+}
+
 static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
   fd->read_closure->SetReady();
   /* Use release store to match with acquire load in fd_get_read_notifier */
@@ -391,6 +405,8 @@ static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 
+static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
+
 /*******************************************************************************
  * Pollset Definitions
  */
@@ -611,16 +627,25 @@ static grpc_error* process_epoll_events(grpc_pollset* pollset) {
       append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
                    err_desc);
     } else {
-      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
-      bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
+      grpc_fd* fd = reinterpret_cast<grpc_fd*>(
+          reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1));
+      bool track_err =
+          reinterpret_cast<intptr_t>(data_ptr) & static_cast<intptr_t>(1);
+      bool cancel = (ev->events & EPOLLHUP) != 0;
+      bool error = (ev->events & EPOLLERR) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
+      bool err_fallback = error && !track_err;
+
+      if (error && !err_fallback) {
+        fd_has_errors(fd);
+      }
 
-      if (read_ev || cancel) {
+      if (read_ev || cancel || err_fallback) {
         fd_become_readable(fd, pollset);
       }
 
-      if (write_ev || cancel) {
+      if (write_ev || cancel || err_fallback) {
         fd_become_writable(fd);
       }
     }
@@ -1183,6 +1208,7 @@ static void shutdown_engine(void) {
 
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
+    true,
 
     fd_create,
     fd_wrapped_fd,
@@ -1190,6 +1216,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
 

+ 45 - 10
src/core/lib/iomgr/ev_epollex_linux.cc

@@ -175,6 +175,7 @@ struct grpc_fd {
 
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
+  grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
 
   struct grpc_fd* freelist_next;
   grpc_closure* on_done_closure;
@@ -184,6 +185,9 @@ struct grpc_fd {
   gpr_atm read_notifier_pollset;
 
   grpc_iomgr_object iomgr_object;
+
+  /* Do we need to track EPOLLERR events separately? */
+  bool track_err;
 };
 
 static void fd_global_init(void);
@@ -309,6 +313,7 @@ static void fd_destroy(void* arg, grpc_error* error) {
 
   fd->read_closure->DestroyEvent();
   fd->write_closure->DestroyEvent();
+  fd->error_closure->DestroyEvent();
 
   gpr_mu_unlock(&fd_freelist_mu);
 }
@@ -348,7 +353,7 @@ static void fd_global_shutdown(void) {
   gpr_mu_destroy(&fd_freelist_mu);
 }
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
   grpc_fd* new_fd = nullptr;
 
   gpr_mu_lock(&fd_freelist_mu);
@@ -362,6 +367,7 @@ static grpc_fd* fd_create(int fd, const char* name) {
     new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
+    new_fd->error_closure.Init();
   }
 
   gpr_mu_init(&new_fd->pollable_mu);
@@ -369,9 +375,11 @@ static grpc_fd* fd_create(int fd, const char* name) {
   new_fd->pollable_obj = nullptr;
   gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
   new_fd->fd = fd;
+  new_fd->track_err = track_err;
   new_fd->salt = gpr_atm_no_barrier_fetch_add(&g_fd_salt, 1);
   new_fd->read_closure->InitEvent();
   new_fd->write_closure->InitEvent();
+  new_fd->error_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = nullptr;
@@ -395,8 +403,8 @@ static int fd_wrapped_fd(grpc_fd* fd) {
 }
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
-  bool is_fd_closed = already_closed;
+                      const char* reason) {
+  bool is_fd_closed = false;
 
   gpr_mu_lock(&fd->orphan_mu);
 
@@ -406,7 +414,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
      descriptor fd->fd (but we still own the grpc_fd structure). */
   if (release_fd != nullptr) {
     *release_fd = fd->fd;
-  } else if (!is_fd_closed) {
+  } else {
     close(fd->fd);
     is_fd_closed = true;
   }
@@ -438,8 +446,14 @@ static bool fd_is_shutdown(grpc_fd* fd) {
 /* Might be called multiple times */
 static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
-    shutdown(fd->fd, SHUT_RDWR);
+    if (shutdown(fd->fd, SHUT_RDWR)) {
+      if (errno != ENOTCONN) {
+        gpr_log(GPR_ERROR, "Error shutting down fd %d. errno: %d",
+                grpc_fd_wrapped_fd(fd), errno);
+      }
+    }
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
+    fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
   }
   GRPC_ERROR_UNREF(why);
 }
@@ -452,6 +466,10 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   fd->write_closure->NotifyOn(closure);
 }
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  fd->error_closure->NotifyOn(closure);
+}
+
 /*******************************************************************************
  * Pollable Definitions
  */
@@ -579,7 +597,12 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
   struct epoll_event ev_fd;
   ev_fd.events =
       static_cast<uint32_t>(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE);
-  ev_fd.data.ptr = fd;
+  /* Use the second least significant bit of ev_fd.data.ptr to store track_err
+   * to avoid synchronization issues when accessing it after receiving an event.
+   * Accessing fd would be a data race there because the fd might have been
+   * returned to the free list at that point. */
+  ev_fd.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fd) |
+                                           (fd->track_err ? 2 : 0));
   GRPC_STATS_INC_SYSCALL_EPOLL_CTL();
   if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd->fd, &ev_fd) != 0) {
     switch (errno) {
@@ -780,6 +803,8 @@ static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 
+static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
+
 static grpc_error* fd_get_or_become_pollable(grpc_fd* fd, pollable** p) {
   gpr_mu_lock(&fd->pollable_mu);
   grpc_error* error = GRPC_ERROR_NONE;
@@ -848,20 +873,28 @@ static grpc_error* pollable_process_events(grpc_pollset* pollset,
                                          (intptr_t)data_ptr)),
                    err_desc);
     } else {
-      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
-      bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
+      grpc_fd* fd =
+          reinterpret_cast<grpc_fd*>(reinterpret_cast<intptr_t>(data_ptr) & ~2);
+      bool track_err = reinterpret_cast<intptr_t>(data_ptr) & 2;
+      bool cancel = (ev->events & EPOLLHUP) != 0;
+      bool error = (ev->events & EPOLLERR) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
+      bool err_fallback = error && !track_err;
+
       if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "PS:%p got fd %p: cancel=%d read=%d "
                 "write=%d",
                 pollset, fd, cancel, read_ev, write_ev);
       }
-      if (read_ev || cancel) {
+      if (error && !err_fallback) {
+        fd_has_errors(fd);
+      }
+      if (read_ev || cancel || err_fallback) {
         fd_become_readable(fd, pollset);
       }
-      if (write_ev || cancel) {
+      if (write_ev || cancel || err_fallback) {
         fd_become_writable(fd);
       }
     }
@@ -1503,6 +1536,7 @@ static void shutdown_engine(void) {
 
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
+    true,
 
     fd_create,
     fd_wrapped_fd,
@@ -1510,6 +1544,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
 

+ 47 - 21
src/core/lib/iomgr/ev_epollsig_linux.cc

@@ -132,6 +132,7 @@ struct grpc_fd {
 
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
+  grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
 
   struct grpc_fd* freelist_next;
   grpc_closure* on_done_closure;
@@ -141,6 +142,9 @@ struct grpc_fd {
   gpr_atm read_notifier_pollset;
 
   grpc_iomgr_object iomgr_object;
+
+  /* Do we need to track EPOLLERR events separately? */
+  bool track_err;
 };
 
 /* Reference counting for fds */
@@ -352,7 +356,10 @@ static void polling_island_add_fds_locked(polling_island* pi, grpc_fd** fds,
 
   for (i = 0; i < fd_count; i++) {
     ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
-    ev.data.ptr = fds[i];
+    /* Use the least significant bit of ev.data.ptr to store track_err to avoid
+     * synchronization issues when accessing it after receiving an event */
+    ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fds[i]) |
+                                          (fds[i]->track_err ? 1 : 0));
     err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev);
 
     if (err < 0) {
@@ -435,7 +442,6 @@ static void polling_island_remove_all_fds_locked(polling_island* pi,
 
 /* The caller is expected to hold pi->mu lock before calling this function */
 static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
-                                            bool is_fd_closed,
                                             grpc_error** error) {
   int err;
   size_t i;
@@ -444,16 +450,14 @@ static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
 
   /* If fd is already closed, then it would have been automatically been removed
      from the epoll set */
-  if (!is_fd_closed) {
-    err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr);
-    if (err < 0 && errno != ENOENT) {
-      gpr_asprintf(
-          &err_msg,
-          "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)",
-          pi->epoll_fd, fd->fd, errno, strerror(errno));
-      append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
-      gpr_free(err_msg);
-    }
+  err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr);
+  if (err < 0 && errno != ENOENT) {
+    gpr_asprintf(
+        &err_msg,
+        "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)",
+        pi->epoll_fd, fd->fd, errno, strerror(errno));
+    append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
+    gpr_free(err_msg);
   }
 
   for (i = 0; i < pi->fd_cnt; i++) {
@@ -769,6 +773,7 @@ static void unref_by(grpc_fd* fd, int n) {
 
     fd->read_closure->DestroyEvent();
     fd->write_closure->DestroyEvent();
+    fd->error_closure->DestroyEvent();
 
     gpr_mu_unlock(&fd_freelist_mu);
   } else {
@@ -806,7 +811,7 @@ static void fd_global_shutdown(void) {
   gpr_mu_destroy(&fd_freelist_mu);
 }
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
   grpc_fd* new_fd = nullptr;
 
   gpr_mu_lock(&fd_freelist_mu);
@@ -821,6 +826,7 @@ static grpc_fd* fd_create(int fd, const char* name) {
     gpr_mu_init(&new_fd->po.mu);
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
+    new_fd->error_closure.Init();
   }
 
   /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
@@ -837,6 +843,8 @@ static grpc_fd* fd_create(int fd, const char* name) {
   new_fd->orphaned = false;
   new_fd->read_closure->InitEvent();
   new_fd->write_closure->InitEvent();
+  new_fd->error_closure->InitEvent();
+  new_fd->track_err = track_err;
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = nullptr;
@@ -863,7 +871,7 @@ static int fd_wrapped_fd(grpc_fd* fd) {
 }
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
+                      const char* reason) {
   grpc_error* error = GRPC_ERROR_NONE;
   polling_island* unref_pi = nullptr;
 
@@ -884,7 +892,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
        before doing this.) */
   if (fd->po.pi != nullptr) {
     polling_island* pi_latest = polling_island_lock(fd->po.pi);
-    polling_island_remove_fd_locked(pi_latest, fd, already_closed, &error);
+    polling_island_remove_fd_locked(pi_latest, fd, &error);
     gpr_mu_unlock(&pi_latest->mu);
 
     unref_pi = fd->po.pi;
@@ -933,6 +941,7 @@ static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
     shutdown(fd->fd, SHUT_RDWR);
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
+    fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
   }
   GRPC_ERROR_UNREF(why);
 }
@@ -945,6 +954,10 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   fd->write_closure->NotifyOn(closure);
 }
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  fd->error_closure->NotifyOn(closure);
+}
+
 /*******************************************************************************
  * Pollset Definitions
  */
@@ -1116,6 +1129,8 @@ static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 
+static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
+
 static void pollset_release_polling_island(grpc_pollset* ps,
                                            const char* reason) {
   if (ps->po.pi != nullptr) {
@@ -1254,14 +1269,23 @@ static void pollset_work_and_unlock(grpc_pollset* pollset,
          to the function pollset_work_and_unlock() will pick up the correct
          epoll_fd */
     } else {
-      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
-      int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
-      int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
-      int write_ev = ep_ev[i].events & EPOLLOUT;
-      if (read_ev || cancel) {
+      grpc_fd* fd = reinterpret_cast<grpc_fd*>(
+          reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1));
+      bool track_err =
+          reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1);
+      bool cancel = (ep_ev[i].events & EPOLLHUP) != 0;
+      bool error = (ep_ev[i].events & EPOLLERR) != 0;
+      bool read_ev = (ep_ev[i].events & (EPOLLIN | EPOLLPRI)) != 0;
+      bool write_ev = (ep_ev[i].events & EPOLLOUT) != 0;
+      bool err_fallback = error && !track_err;
+
+      if (error && !err_fallback) {
+        fd_has_errors(fd);
+      }
+      if (read_ev || cancel || err_fallback) {
         fd_become_readable(fd, pollset);
       }
-      if (write_ev || cancel) {
+      if (write_ev || cancel || err_fallback) {
         fd_become_writable(fd);
       }
     }
@@ -1634,6 +1658,7 @@ static void shutdown_engine(void) {
 
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
+    true,
 
     fd_create,
     fd_wrapped_fd,
@@ -1641,6 +1666,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
 

+ 10 - 4
src/core/lib/iomgr/ev_poll_posix.cc

@@ -330,7 +330,8 @@ static void unref_by(grpc_fd* fd, int n) {
   }
 }
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
+  GPR_DEBUG_ASSERT(track_err == false);
   grpc_fd* r = static_cast<grpc_fd*>(gpr_malloc(sizeof(*r)));
   gpr_mu_init(&r->mu);
   gpr_atm_rel_store(&r->refst, 1);
@@ -424,14 +425,12 @@ static int fd_wrapped_fd(grpc_fd* fd) {
 }
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
+                      const char* reason) {
   fd->on_done_closure = on_done;
   fd->released = release_fd != nullptr;
   if (release_fd != nullptr) {
     *release_fd = fd->fd;
     fd->released = true;
-  } else if (already_closed) {
-    fd->released = true;
   }
   gpr_mu_lock(&fd->mu);
   REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
@@ -553,6 +552,11 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   gpr_mu_unlock(&fd->mu);
 }
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  gpr_log(GPR_ERROR, "Polling engine does not support tracking errors.");
+  abort();
+}
+
 static uint32_t fd_begin_poll(grpc_fd* fd, grpc_pollset* pollset,
                               grpc_pollset_worker* worker, uint32_t read_mask,
                               uint32_t write_mask, grpc_fd_watcher* watcher) {
@@ -1710,6 +1714,7 @@ static void shutdown_engine(void) {
 
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
+    false,
 
     fd_create,
     fd_wrapped_fd,
@@ -1717,6 +1722,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
 

+ 17 - 9
src/core/lib/iomgr/ev_posix.cc

@@ -193,10 +193,15 @@ void grpc_event_engine_shutdown(void) {
   g_event_engine = nullptr;
 }
 
-grpc_fd* grpc_fd_create(int fd, const char* name) {
-  GRPC_POLLING_API_TRACE("fd_create(%d, %s)", fd, name);
-  GRPC_FD_TRACE("fd_create(%d, %s)", fd, name);
-  return g_event_engine->fd_create(fd, name);
+bool grpc_event_engine_can_track_errors(void) {
+  return g_event_engine->can_track_err;
+}
+
+grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err) {
+  GRPC_POLLING_API_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
+  GRPC_FD_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
+  GPR_DEBUG_ASSERT(!track_err || g_event_engine->can_track_err);
+  return g_event_engine->fd_create(fd, name, track_err);
 }
 
 int grpc_fd_wrapped_fd(grpc_fd* fd) {
@@ -204,13 +209,12 @@ int grpc_fd_wrapped_fd(grpc_fd* fd) {
 }
 
 void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                    bool already_closed, const char* reason) {
-  GRPC_POLLING_API_TRACE("fd_orphan(%d, %p, %p, %d, %s)",
-                         grpc_fd_wrapped_fd(fd), on_done, release_fd,
-                         already_closed, reason);
+                    const char* reason) {
+  GRPC_POLLING_API_TRACE("fd_orphan(%d, %p, %p, %s)", grpc_fd_wrapped_fd(fd),
+                         on_done, release_fd, reason);
   GRPC_FD_TRACE("grpc_fd_orphan, fd:%d closed", grpc_fd_wrapped_fd(fd));
 
-  g_event_engine->fd_orphan(fd, on_done, release_fd, already_closed, reason);
+  g_event_engine->fd_orphan(fd, on_done, release_fd, reason);
 }
 
 void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why) {
@@ -231,6 +235,10 @@ void grpc_fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   g_event_engine->fd_notify_on_write(fd, closure);
 }
 
+void grpc_fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  g_event_engine->fd_notify_on_error(fd, closure);
+}
+
 static size_t pollset_size(void) { return g_event_engine->pollset_size; }
 
 static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {

+ 20 - 4
src/core/lib/iomgr/ev_posix.h

@@ -41,14 +41,16 @@ typedef struct grpc_fd grpc_fd;
 
 typedef struct grpc_event_engine_vtable {
   size_t pollset_size;
+  bool can_track_err;
 
-  grpc_fd* (*fd_create)(int fd, const char* name);
+  grpc_fd* (*fd_create)(int fd, const char* name, bool track_err);
   int (*fd_wrapped_fd)(grpc_fd* fd);
   void (*fd_orphan)(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                    bool already_closed, const char* reason);
+                    const char* reason);
   void (*fd_shutdown)(grpc_fd* fd, grpc_error* why);
   void (*fd_notify_on_read)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_write)(grpc_fd* fd, grpc_closure* closure);
+  void (*fd_notify_on_error)(grpc_fd* fd, grpc_closure* closure);
   bool (*fd_is_shutdown)(grpc_fd* fd);
   grpc_pollset* (*fd_get_read_notifier_pollset)(grpc_fd* fd);
 
@@ -84,10 +86,20 @@ void grpc_event_engine_shutdown(void);
 /* Return the name of the poll strategy */
 const char* grpc_get_poll_strategy_name();
 
+/* Returns true if polling engine can track errors separately, false otherwise.
+ * If this is true, fd can be created with track_err set. After this, error
+ * events will be reported using fd_notify_on_error. If it is not set, errors
+ * will continue to be reported through fd_notify_on_read and
+ * fd_notify_on_write.
+ */
+bool grpc_event_engine_can_track_errors();
+
 /* Create a wrapped file descriptor.
    Requires fd is a non-blocking file descriptor.
+   \a track_err if true means that error events would be tracked separately
+   using grpc_fd_notify_on_error. Currently, valid only for linux systems.
    This takes ownership of closing fd. */
-grpc_fd* grpc_fd_create(int fd, const char* name);
+grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err);
 
 /* Return the wrapped fd, or -1 if it has been released or closed. */
 int grpc_fd_wrapped_fd(grpc_fd* fd);
@@ -100,7 +112,7 @@ int grpc_fd_wrapped_fd(grpc_fd* fd);
    notify_on_write.
    MUST NOT be called with a pollset lock taken */
 void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                    bool already_closed, const char* reason);
+                    const char* reason);
 
 /* Has grpc_fd_shutdown been called on an fd? */
 bool grpc_fd_is_shutdown(grpc_fd* fd);
@@ -126,6 +138,10 @@ void grpc_fd_notify_on_read(grpc_fd* fd, grpc_closure* closure);
 /* Exactly the same semantics as above, except based on writable events.  */
 void grpc_fd_notify_on_write(grpc_fd* fd, grpc_closure* closure);
 
+/* Exactly the same semantics as above, except based on error events. track_err
+ * needs to have been set on grpc_fd_create */
+void grpc_fd_notify_on_error(grpc_fd* fd, grpc_closure* closure);
+
 /* Return the read notifier pollset from the fd */
 grpc_pollset* grpc_fd_get_read_notifier_pollset(grpc_fd* fd);
 

+ 7 - 7
src/core/lib/iomgr/tcp_client_cfstream.cc

@@ -52,7 +52,7 @@ typedef struct CFStreamConnect {
 
   CFReadStreamRef read_stream;
   CFWriteStreamRef write_stream;
-  CFStreamHandle* stream_sync;
+  CFStreamHandle* stream_handle;
 
   grpc_timer alarm;
   grpc_closure on_alarm;
@@ -71,7 +71,7 @@ typedef struct CFStreamConnect {
 
 static void CFStreamConnectCleanup(CFStreamConnect* connect) {
   grpc_resource_quota_unref_internal(connect->resource_quota);
-  CFSTREAM_HANDLE_UNREF(connect->stream_sync, "async connect clean up");
+  CFSTREAM_HANDLE_UNREF(connect->stream_handle, "async connect clean up");
   CFRelease(connect->read_stream);
   CFRelease(connect->write_stream);
   gpr_mu_destroy(&connect->mu);
@@ -131,7 +131,7 @@ static void OnOpen(void* arg, grpc_error* error) {
       if (error == GRPC_ERROR_NONE) {
         *endpoint = grpc_cfstream_endpoint_create(
             connect->read_stream, connect->write_stream, connect->addr_name,
-            connect->resource_quota, connect->stream_sync);
+            connect->resource_quota, connect->stream_handle);
       }
     } else {
       GRPC_ERROR_REF(error);
@@ -170,8 +170,8 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep,
   gpr_mu_init(&connect->mu);
 
   if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
-            connect->addr_name);
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %p, %s: asynchronously connecting",
+            connect, connect->addr_name);
   }
 
   grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL);
@@ -197,11 +197,11 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep,
   CFRelease(host);
   connect->read_stream = read_stream;
   connect->write_stream = write_stream;
-  connect->stream_sync =
+  connect->stream_handle =
       CFStreamHandle::CreateStreamHandle(read_stream, write_stream);
   GRPC_CLOSURE_INIT(&connect->on_open, OnOpen, static_cast<void*>(connect),
                     grpc_schedule_on_exec_ctx);
-  connect->stream_sync->NotifyOnOpen(&connect->on_open);
+  connect->stream_handle->NotifyOnOpen(&connect->on_open);
   GRPC_CLOSURE_INIT(&connect->on_alarm, OnAlarm, connect,
                     grpc_schedule_on_exec_ctx);
   gpr_mu_lock(&connect->mu);

+ 3 - 5
src/core/lib/iomgr/tcp_client_posix.cc

@@ -211,8 +211,7 @@ static void on_writable(void* acp, grpc_error* error) {
 finish:
   if (fd != nullptr) {
     grpc_pollset_set_del_fd(ac->interested_parties, fd);
-    grpc_fd_orphan(fd, nullptr, nullptr, false /* already_closed */,
-                   "tcp_client_orphan");
+    grpc_fd_orphan(fd, nullptr, nullptr, "tcp_client_orphan");
     fd = nullptr;
   }
   done = (--ac->refs == 0);
@@ -280,7 +279,7 @@ grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
   }
   addr_str = grpc_sockaddr_to_uri(mapped_addr);
   gpr_asprintf(&name, "tcp-client:%s", addr_str);
-  *fdobj = grpc_fd_create(fd, name);
+  *fdobj = grpc_fd_create(fd, name, false);
   gpr_free(name);
   gpr_free(addr_str);
   return GRPC_ERROR_NONE;
@@ -305,8 +304,7 @@ void grpc_tcp_client_create_from_prepared_fd(
     return;
   }
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
-    grpc_fd_orphan(fdobj, nullptr, nullptr, false /* already_closed */,
-                   "tcp_client_connect_error");
+    grpc_fd_orphan(fdobj, nullptr, nullptr, "tcp_client_connect_error");
     GRPC_CLOSURE_SCHED(closure, GRPC_OS_ERROR(errno, "connect"));
     return;
   }

+ 1 - 1
src/core/lib/iomgr/tcp_posix.cc

@@ -297,7 +297,7 @@ static void tcp_shutdown(grpc_endpoint* ep, grpc_error* why) {
 
 static void tcp_free(grpc_tcp* tcp) {
   grpc_fd_orphan(tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
-                 false /* already_closed */, "tcp_unref_orphan");
+                 "tcp_unref_orphan");
   grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
   grpc_resource_user_unref(tcp->resource_user);
   gpr_free(tcp->peer_string);

+ 3 - 3
src/core/lib/iomgr/tcp_server_posix.cc

@@ -150,7 +150,7 @@ static void deactivated_all_ports(grpc_tcp_server* s) {
       GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s,
                         grpc_schedule_on_exec_ctx);
       grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, nullptr,
-                     false /* already_closed */, "tcp_listener_shutdown");
+                     "tcp_listener_shutdown");
     }
     gpr_mu_unlock(&s->mu);
   } else {
@@ -226,7 +226,7 @@ static void on_read(void* arg, grpc_error* err) {
       gpr_log(GPR_INFO, "SERVER_CONNECT: incoming connection: %s", addr_str);
     }
 
-    grpc_fd* fdobj = grpc_fd_create(fd, name);
+    grpc_fd* fdobj = grpc_fd_create(fd, name, false);
 
     read_notifier_pollset =
         sp->server->pollsets[static_cast<size_t>(gpr_atm_no_barrier_fetch_add(
@@ -362,7 +362,7 @@ static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) {
     listener->sibling = sp;
     sp->server = listener->server;
     sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
+    sp->emfd = grpc_fd_create(fd, name, false);
     memcpy(&sp->addr, &listener->addr, sizeof(grpc_resolved_address));
     sp->port = port;
     sp->port_index = listener->port_index;

+ 1 - 1
src/core/lib/iomgr/tcp_server_utils_posix_common.cc

@@ -105,7 +105,7 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s, int fd,
     s->tail = sp;
     sp->server = s;
     sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
+    sp->emfd = grpc_fd_create(fd, name, false);
     memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
     sp->port = port;
     sp->port_index = port_index;

+ 2 - 3
src/core/lib/iomgr/udp_server.cc

@@ -152,7 +152,7 @@ GrpcUdpListener::GrpcUdpListener(grpc_udp_server* server, int fd,
   grpc_sockaddr_to_string(&addr_str, addr, 1);
   gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
   gpr_free(addr_str);
-  emfd_ = grpc_fd_create(fd, name);
+  emfd_ = grpc_fd_create(fd, name, false);
   memcpy(&addr_, addr, sizeof(grpc_resolved_address));
   GPR_ASSERT(emfd_);
   gpr_free(name);
@@ -300,8 +300,7 @@ void GrpcUdpListener::OrphanFd() {
                     grpc_schedule_on_exec_ctx);
   /* Because at this point, all listening sockets have been shutdown already, no
    * need to call OnFdAboutToOrphan() to notify the handler again. */
-  grpc_fd_orphan(emfd_, &destroyed_closure_, nullptr,
-                 false /* already_closed */, "udp_listener_shutdown");
+  grpc_fd_orphan(emfd_, &destroyed_closure_, nullptr, "udp_listener_shutdown");
 }
 
 void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {

+ 14 - 4
src/core/lib/surface/call.cc

@@ -227,8 +227,17 @@ struct grpc_call {
 grpc_core::TraceFlag grpc_call_error_trace(false, "call_error");
 grpc_core::TraceFlag grpc_compression_trace(false, "compression");
 
-#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack*)((call) + 1))
-#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call*)(call_stack)) - 1)
+/* Given a size, round up to the next multiple of sizeof(void*) */
+#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
+  (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
+
+#define CALL_STACK_FROM_CALL(call)   \
+  (grpc_call_stack*)((char*)(call) + \
+                     ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)))
+#define CALL_FROM_CALL_STACK(call_stack) \
+  (grpc_call*)(((char*)(call_stack)) -   \
+               ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)))
+
 #define CALL_ELEM_FROM_CALL(call, idx) \
   grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
 #define CALL_FROM_TOP_ELEM(top_elem) \
@@ -291,8 +300,9 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
   size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
   GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size);
   gpr_arena* arena = gpr_arena_create(initial_size);
-  call = static_cast<grpc_call*>(gpr_arena_alloc(
-      arena, sizeof(grpc_call) + channel_stack->call_stack_size));
+  call = static_cast<grpc_call*>(
+      gpr_arena_alloc(arena, ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) +
+                                 channel_stack->call_stack_size));
   gpr_ref_init(&call->ext_ref, 1);
   call->arena = arena;
   grpc_call_combiner_init(&call->call_combiner);

+ 1 - 1
src/csharp/Grpc.Core.Testing/TestCalls.cs

@@ -65,7 +65,7 @@ namespace Grpc.Core.Testing
         /// Creates a test double for <c>AsyncDuplexStreamingCall</c>. Only for testing.
         /// Note: experimental API that can change or be removed without any prior notice.
         /// </summary>
-        public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TResponse, TRequest>(
+        public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(
             IClientStreamWriter<TRequest> requestStream, IAsyncStreamReader<TResponse> responseStream,
             Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc,
             Func<Metadata> getTrailersFunc, Action disposeAction)

+ 2 - 0
src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj

@@ -13,11 +13,13 @@
 
   <ItemGroup>
     <ProjectReference Include="../Grpc.Examples/Grpc.Examples.csproj" />
+    <ProjectReference Include="../Grpc.Core.Testing/Grpc.Core.Testing.csproj" />
   </ItemGroup>
 
   <ItemGroup>
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
+    <PackageReference Include="Moq" Version="4.8.2" />
   </ItemGroup>
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

+ 101 - 0
src/csharp/Grpc.Examples.Tests/MathClientMockableTest.cs

@@ -0,0 +1,101 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Testing;
+using NUnit.Framework;
+
+namespace Math.Tests
+{
+    /// <summary>
+    /// Demonstrates how to mock method stubs for all method types in a generated client.
+    /// </summary>
+    public class MathClientMockableTest
+    {
+        [Test]
+        public void ClientBaseBlockingUnaryCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            
+            var expected = new DivReply();
+            mockClient.Setup(m => m.Div(Moq.It.IsAny<DivArgs>(), null, null, CancellationToken.None)).Returns(expected);
+            Assert.AreSame(expected, mockClient.Object.Div(new DivArgs()));
+        }
+
+        [Test]
+        public void ClientBaseBlockingUnaryCallWithCallOptionsCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+
+            var expected = new DivReply();
+            mockClient.Setup(m => m.Div(Moq.It.IsAny<DivArgs>(), Moq.It.IsAny<CallOptions>())).Returns(expected);
+            Assert.AreSame(expected, mockClient.Object.Div(new DivArgs(), new CallOptions()));
+        }
+
+        [Test]
+        public void ClientBaseAsyncUnaryCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncUnaryCall<DivReply>(Task.FromResult(new DivReply()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.DivAsync(Moq.It.IsAny<DivArgs>(), null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.DivAsync(new DivArgs()));
+        }
+
+        [Test]
+        public void ClientBaseClientStreamingCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            var mockRequestStream = new Moq.Mock<IClientStreamWriter<Num>>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncClientStreamingCall<Num, Num>(mockRequestStream.Object, Task.FromResult(new Num()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.Sum(null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.Sum());
+        }
+
+        [Test]
+        public void ClientBaseServerStreamingCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            var mockResponseStream = new Moq.Mock<IAsyncStreamReader<Num>>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncServerStreamingCall<Num>(mockResponseStream.Object, Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.Fib(Moq.It.IsAny<FibArgs>(), null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.Fib(new FibArgs()));
+        }
+
+        [Test]
+        public void ClientBaseDuplexStreamingCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            var mockRequestStream = new Moq.Mock<IClientStreamWriter<DivArgs>>();
+            var mockResponseStream = new Moq.Mock<IAsyncStreamReader<DivReply>>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncDuplexStreamingCall<DivArgs, DivReply>(mockRequestStream.Object, mockResponseStream.Object, Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.DivMany(null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.DivMany());
+        }
+    }
+}

+ 47 - 0
src/csharp/Grpc.Examples.Tests/MathServiceImplTestabilityTest.cs

@@ -0,0 +1,47 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Testing;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Math.Tests
+{
+    /// <summary>
+    /// Demonstrates how to unit test implementations of generated server stubs.
+    /// </summary>
+    public class MathServiceImplTestabilityTest
+    {
+        [Test]
+        public async Task ServerCallImplIsTestable()
+        {
+            var mathImpl = new MathServiceImpl();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestServerCallContext to create an instance of server call context.
+            // This allows testing even those server-side implementations that rely on the contents of ServerCallContext.
+            var fakeServerCallContext = TestServerCallContext.Create("fooMethod", null, DateTime.UtcNow.AddHours(1), new Metadata(), CancellationToken.None, "127.0.0.1", null, null, (metadata) => TaskUtils.CompletedTask, () => new WriteOptions(), (writeOptions) => { });
+            var response = await mathImpl.Div(new DivArgs { Dividend = 10, Divisor = 2 }, fakeServerCallContext);
+            Assert.AreEqual(5, response.Quotient);
+            Assert.AreEqual(0, response.Remainder);
+        }
+    }
+}

+ 12 - 12
src/csharp/Grpc.Examples/MathGrpc.cs

@@ -27,38 +27,38 @@ namespace Math {
   {
     static readonly string __ServiceName = "math.Math";
 
-    static readonly grpc::Marshaller<global::Math.DivArgs> __Marshaller_DivArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Math.DivReply> __Marshaller_DivReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Math.FibArgs> __Marshaller_FibArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Math.Num> __Marshaller_Num = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.DivArgs> __Marshaller_math_DivArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.DivReply> __Marshaller_math_DivReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.FibArgs> __Marshaller_math_FibArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.Num> __Marshaller_math_Num = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Math.DivArgs, global::Math.DivReply> __Method_Div = new grpc::Method<global::Math.DivArgs, global::Math.DivReply>(
         grpc::MethodType.Unary,
         __ServiceName,
         "Div",
-        __Marshaller_DivArgs,
-        __Marshaller_DivReply);
+        __Marshaller_math_DivArgs,
+        __Marshaller_math_DivReply);
 
     static readonly grpc::Method<global::Math.DivArgs, global::Math.DivReply> __Method_DivMany = new grpc::Method<global::Math.DivArgs, global::Math.DivReply>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "DivMany",
-        __Marshaller_DivArgs,
-        __Marshaller_DivReply);
+        __Marshaller_math_DivArgs,
+        __Marshaller_math_DivReply);
 
     static readonly grpc::Method<global::Math.FibArgs, global::Math.Num> __Method_Fib = new grpc::Method<global::Math.FibArgs, global::Math.Num>(
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         "Fib",
-        __Marshaller_FibArgs,
-        __Marshaller_Num);
+        __Marshaller_math_FibArgs,
+        __Marshaller_math_Num);
 
     static readonly grpc::Method<global::Math.Num, global::Math.Num> __Method_Sum = new grpc::Method<global::Math.Num, global::Math.Num>(
         grpc::MethodType.ClientStreaming,
         __ServiceName,
         "Sum",
-        __Marshaller_Num,
-        __Marshaller_Num);
+        __Marshaller_math_Num,
+        __Marshaller_math_Num);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 4 - 4
src/csharp/Grpc.HealthCheck/HealthGrpc.cs

@@ -30,15 +30,15 @@ namespace Grpc.Health.V1 {
   {
     static readonly string __ServiceName = "grpc.health.v1.Health";
 
-    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckRequest> __Marshaller_HealthCheckRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckResponse> __Marshaller_HealthCheckResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckRequest> __Marshaller_grpc_health_v1_HealthCheckRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckResponse> __Marshaller_grpc_health_v1_HealthCheckResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckResponse.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse> __Method_Check = new grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse>(
         grpc::MethodType.Unary,
         __ServiceName,
         "Check",
-        __Marshaller_HealthCheckRequest,
-        __Marshaller_HealthCheckResponse);
+        __Marshaller_grpc_health_v1_HealthCheckRequest,
+        __Marshaller_grpc_health_v1_HealthCheckResponse);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 12 - 12
src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs

@@ -29,43 +29,43 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.BenchmarkService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_grpc_testing_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_grpc_testing_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.Unary,
         __ServiceName,
         "UnaryCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "StreamingCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingFromClient = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.ClientStreaming,
         __ServiceName,
         "StreamingFromClient",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingFromServer = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         "StreamingFromServer",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingBothWays = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "StreamingBothWays",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 0 - 23
src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs

@@ -33,29 +33,6 @@ namespace Grpc.IntegrationTesting
     {
         TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
 
-        [Test]
-        public void ExpandedParamOverloadCanBeMocked()
-        {
-            var expected = new SimpleResponse();
-
-            var mockClient = new Moq.Mock<TestService.TestServiceClient>();
-            // mocking is relatively clumsy because one needs to specify value for all the optional params.
-            mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
-
-            Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest()));
-        }
-
-        [Test]
-        public void CallOptionsOverloadCanBeMocked()
-        {
-            var expected = new SimpleResponse();
-
-            var mockClient = new Moq.Mock<TestService.TestServiceClient>();
-            mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), Moq.It.IsAny<CallOptions>())).Returns(expected);
-
-            Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest(), new CallOptions()));
-        }
-
         [Test]
         public void DefaultMethodStubThrows_UnaryCall()
         {

+ 0 - 1
src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj

@@ -19,7 +19,6 @@
   <ItemGroup>
     <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
     <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
-    <PackageReference Include="Moq" Version="4.8.2" />
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>

+ 7 - 7
src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs

@@ -33,23 +33,23 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.MetricsService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.EmptyMessage> __Marshaller_EmptyMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.EmptyMessage.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeResponse> __Marshaller_GaugeResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeRequest> __Marshaller_GaugeRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.EmptyMessage> __Marshaller_grpc_testing_EmptyMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.EmptyMessage.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeResponse> __Marshaller_grpc_testing_GaugeResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeRequest> __Marshaller_grpc_testing_GaugeRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeRequest.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse> __Method_GetAllGauges = new grpc::Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse>(
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         "GetAllGauges",
-        __Marshaller_EmptyMessage,
-        __Marshaller_GaugeResponse);
+        __Marshaller_grpc_testing_EmptyMessage,
+        __Marshaller_grpc_testing_GaugeResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse> __Method_GetGauge = new grpc::Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse>(
         grpc::MethodType.Unary,
         __ServiceName,
         "GetGauge",
-        __Marshaller_GaugeRequest,
-        __Marshaller_GaugeResponse);
+        __Marshaller_grpc_testing_GaugeRequest,
+        __Marshaller_grpc_testing_GaugeResponse);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 4 - 4
src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs

@@ -29,15 +29,15 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.ReportQpsScenarioService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.ScenarioResult> __Marshaller_ScenarioResult = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ScenarioResult.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ScenarioResult> __Marshaller_grpc_testing_ScenarioResult = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ScenarioResult.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_grpc_testing_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.ScenarioResult, global::Grpc.Testing.Void> __Method_ReportScenario = new grpc::Method<global::Grpc.Testing.ScenarioResult, global::Grpc.Testing.Void>(
         grpc::MethodType.Unary,
         __ServiceName,
         "ReportScenario",
-        __Marshaller_ScenarioResult,
-        __Marshaller_Void);
+        __Marshaller_grpc_testing_ScenarioResult,
+        __Marshaller_grpc_testing_Void);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 33 - 33
src/csharp/Grpc.IntegrationTesting/TestGrpc.cs

@@ -34,69 +34,69 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.TestService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallRequest> __Marshaller_StreamingOutputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallResponse> __Marshaller_StreamingOutputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallRequest> __Marshaller_StreamingInputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallResponse> __Marshaller_StreamingInputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_grpc_testing_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_grpc_testing_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallRequest> __Marshaller_grpc_testing_StreamingOutputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallResponse> __Marshaller_grpc_testing_StreamingOutputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallRequest> __Marshaller_grpc_testing_StreamingInputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallResponse> __Marshaller_grpc_testing_StreamingInputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_EmptyCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         __ServiceName,
         "EmptyCall",
-        __Marshaller_Empty,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.Unary,
         __ServiceName,
         "UnaryCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_CacheableUnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.Unary,
         __ServiceName,
         "CacheableUnaryCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         "StreamingOutputCall",
-        __Marshaller_StreamingOutputCallRequest,
-        __Marshaller_StreamingOutputCallResponse);
+        __Marshaller_grpc_testing_StreamingOutputCallRequest,
+        __Marshaller_grpc_testing_StreamingOutputCallResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> __Method_StreamingInputCall = new grpc::Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse>(
         grpc::MethodType.ClientStreaming,
         __ServiceName,
         "StreamingInputCall",
-        __Marshaller_StreamingInputCallRequest,
-        __Marshaller_StreamingInputCallResponse);
+        __Marshaller_grpc_testing_StreamingInputCallRequest,
+        __Marshaller_grpc_testing_StreamingInputCallResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "FullDuplexCall",
-        __Marshaller_StreamingOutputCallRequest,
-        __Marshaller_StreamingOutputCallResponse);
+        __Marshaller_grpc_testing_StreamingOutputCallRequest,
+        __Marshaller_grpc_testing_StreamingOutputCallResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "HalfDuplexCall",
-        __Marshaller_StreamingOutputCallRequest,
-        __Marshaller_StreamingOutputCallResponse);
+        __Marshaller_grpc_testing_StreamingOutputCallRequest,
+        __Marshaller_grpc_testing_StreamingOutputCallResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         __ServiceName,
         "UnimplementedCall",
-        __Marshaller_Empty,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
@@ -548,14 +548,14 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.UnimplementedService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         __ServiceName,
         "UnimplementedCall",
-        __Marshaller_Empty,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
@@ -669,23 +669,23 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.ReconnectService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectParams> __Marshaller_ReconnectParams = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectParams.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_ReconnectInfo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectParams> __Marshaller_grpc_testing_ReconnectParams = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectParams.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_grpc_testing_ReconnectInfo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty> __Method_Start = new grpc::Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         __ServiceName,
         "Start",
-        __Marshaller_ReconnectParams,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_ReconnectParams,
+        __Marshaller_grpc_testing_Empty);
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
         grpc::MethodType.Unary,
         __ServiceName,
         "Stop",
-        __Marshaller_Empty,
-        __Marshaller_ReconnectInfo);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_ReconnectInfo);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 15 - 15
src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs

@@ -29,41 +29,41 @@ namespace Grpc.Testing {
   {
     static readonly string __ServiceName = "grpc.testing.WorkerService";
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_ServerArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_ServerStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_ClientArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_ClientStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.CoreRequest> __Marshaller_CoreRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.CoreResponse> __Marshaller_CoreResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_grpc_testing_ServerArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_grpc_testing_ServerStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_grpc_testing_ClientArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_grpc_testing_ClientStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.CoreRequest> __Marshaller_grpc_testing_CoreRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.CoreResponse> __Marshaller_grpc_testing_CoreResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_grpc_testing_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new grpc::Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "RunServer",
-        __Marshaller_ServerArgs,
-        __Marshaller_ServerStatus);
+        __Marshaller_grpc_testing_ServerArgs,
+        __Marshaller_grpc_testing_ServerStatus);
 
     static readonly grpc::Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new grpc::Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "RunClient",
-        __Marshaller_ClientArgs,
-        __Marshaller_ClientStatus);
+        __Marshaller_grpc_testing_ClientArgs,
+        __Marshaller_grpc_testing_ClientStatus);
 
     static readonly grpc::Method<global::Grpc.Testing.CoreRequest, global::Grpc.Testing.CoreResponse> __Method_CoreCount = new grpc::Method<global::Grpc.Testing.CoreRequest, global::Grpc.Testing.CoreResponse>(
         grpc::MethodType.Unary,
         __ServiceName,
         "CoreCount",
-        __Marshaller_CoreRequest,
-        __Marshaller_CoreResponse);
+        __Marshaller_grpc_testing_CoreRequest,
+        __Marshaller_grpc_testing_CoreResponse);
 
     static readonly grpc::Method<global::Grpc.Testing.Void, global::Grpc.Testing.Void> __Method_QuitWorker = new grpc::Method<global::Grpc.Testing.Void, global::Grpc.Testing.Void>(
         grpc::MethodType.Unary,
         __ServiceName,
         "QuitWorker",
-        __Marshaller_Void,
-        __Marshaller_Void);
+        __Marshaller_grpc_testing_Void,
+        __Marshaller_grpc_testing_Void);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 4 - 4
src/csharp/Grpc.Reflection/ReflectionGrpc.cs

@@ -29,15 +29,15 @@ namespace Grpc.Reflection.V1Alpha {
   {
     static readonly string __ServiceName = "grpc.reflection.v1alpha.ServerReflection";
 
-    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> __Marshaller_ServerReflectionRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Marshaller_ServerReflectionResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> __Marshaller_grpc_reflection_v1alpha_ServerReflectionRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Marshaller_grpc_reflection_v1alpha_ServerReflectionResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionResponse.Parser.ParseFrom);
 
     static readonly grpc::Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Method_ServerReflectionInfo = new grpc::Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse>(
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         "ServerReflectionInfo",
-        __Marshaller_ServerReflectionRequest,
-        __Marshaller_ServerReflectionResponse);
+        __Marshaller_grpc_reflection_v1alpha_ServerReflectionRequest,
+        __Marshaller_grpc_reflection_v1alpha_ServerReflectionResponse);
 
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 3 - 1
src/csharp/tests.json

@@ -41,7 +41,9 @@
     "Grpc.Core.Tests.UserAgentStringTest"
   ],
   "Grpc.Examples.Tests": [
-    "Math.Tests.MathClientServerTest"
+    "Math.Tests.MathClientMockableTest",
+    "Math.Tests.MathClientServerTest",
+    "Math.Tests.MathServiceImplTestabilityTest"
   ],
   "Grpc.HealthCheck.Tests": [
     "Grpc.HealthCheck.Tests.HealthClientServerTest",

+ 4 - 1
src/objective-c/GRPCClient/GRPCCall.m

@@ -206,8 +206,9 @@ static NSString *const kBearerPrefix = @"Bearer ";
   } else {
     [_responseWriteable enqueueSuccessfulCompletion];
   }
-
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor unregisterObserver:self];
+#endif
 
   // If the call isn't retained anywhere else, it can be deallocated now.
   _retainSelf = nil;
@@ -462,7 +463,9 @@ static NSString *const kBearerPrefix = @"Bearer ";
   [self sendHeaders:_requestHeaders];
   [self invokeCall];
 
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
+#endif
 }
 
 - (void)startWithWriteable:(id<GRXWriteable>)writeable {

+ 16 - 7
src/objective-c/GRPCClient/private/GRPCHost.m

@@ -49,7 +49,9 @@ static NSMutableDictionary *kHostCache;
   if (_channelCreds != nil) {
     grpc_channel_credentials_release(_channelCreds);
   }
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor unregisterObserver:self];
+#endif
 }
 
 // Default initializer.
@@ -84,7 +86,9 @@ static NSMutableDictionary *kHostCache;
       kHostCache[address] = self;
       _compressAlgorithm = GRPC_COMPRESS_NONE;
     }
+#ifndef GRPC_CFSTREAM
     [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
+#endif
   }
   return self;
 }
@@ -125,6 +129,14 @@ static NSMutableDictionary *kHostCache;
                         completionQueue:queue];
 }
 
+- (NSData *)nullTerminatedDataWithString:(NSString *)string {
+  // dataUsingEncoding: does not return a null-terminated string.
+  NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+  NSMutableData *nullTerminated = [NSMutableData dataWithData:data];
+  [nullTerminated appendBytes:"\0" length:1];
+  return nullTerminated;
+}
+
 - (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
             withPrivateKey:(nullable NSString *)pemPrivateKey
              withCertChain:(nullable NSString *)pemCertChain
@@ -146,13 +158,12 @@ static NSMutableDictionary *kHostCache;
       kDefaultRootsError = error;
       return;
     }
-    kDefaultRootsASCII =
-        [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+    kDefaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8];
   });
 
   NSData *rootsASCII;
   if (pemRootCerts != nil) {
-    rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+    rootsASCII = [self nullTerminatedDataWithString:pemRootCerts];
   } else {
     if (kDefaultRootsASCII == nil) {
       if (errorPtr) {
@@ -175,10 +186,8 @@ static NSMutableDictionary *kHostCache;
     creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
   } else {
     grpc_ssl_pem_key_cert_pair key_cert_pair;
-    NSData *privateKeyASCII =
-        [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
-    NSData *certChainASCII =
-        [pemCertChain dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+    NSData *privateKeyASCII = [self nullTerminatedDataWithString:pemPrivateKey];
+    NSData *certChainASCII = [self nullTerminatedDataWithString:pemCertChain];
     key_cert_pair.private_key = privateKeyASCII.bytes;
     key_cert_pair.cert_chain = certChainASCII.bytes;
     creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);

+ 1 - 16
src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj

@@ -99,7 +99,6 @@
 				5EC49F8D2043E46B00ED189A /* Sources */,
 				5EC49F8E2043E46B00ED189A /* Frameworks */,
 				5EC49F8F2043E46B00ED189A /* Resources */,
-				9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */,
 				735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */,
 			);
 			buildRules = (
@@ -194,21 +193,6 @@
 			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
-		9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-			);
-			name = "[CP] Embed Pods Frameworks";
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-frameworks.sh\"\n";
-			showEnvVarsInLog = 0;
-		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -284,6 +268,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
+					"GRPC_CFSTREAM=1",
 				);
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;

+ 2 - 0
src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m

@@ -35,7 +35,9 @@ NSString *host = @"grpc-test.sandbox.googleapis.com";
 - (void)viewDidLoad {
   [super viewDidLoad];
 
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor registerObserver:self selector:@selector(reachabilityChanged:)];
+#endif
 }
 
 - (void)reachabilityChanged:(NSNotification *)note {

+ 3 - 3
src/objective-c/tests/Connectivity/Podfile

@@ -5,9 +5,9 @@ platform :ios, '8.0'
 GRPC_LOCAL_SRC = '../../../..'
 
 target 'ConnectivityTestingApp' do
-  pod 'gRPC', :path => GRPC_LOCAL_SRC
-  pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
-  pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC
+  pod 'gRPC/CFStream', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-Core/CFStream-Implementation', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-ProtoRPC/CFStream', :path => GRPC_LOCAL_SRC
   pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
   pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf"
   pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"

+ 2 - 1
src/objective-c/tests/GRPCClientTests.m

@@ -525,7 +525,8 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
 - (void)testErrorCode {
   int port = [self findFreePort];
   NSString *const kDummyAddress = [NSString stringWithFormat:@"localhost:%d", port];
-  __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
+  __weak XCTestExpectation *completion =
+      [self expectationWithDescription:@"Received correct error code."];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress
                                              path:kEmptyCallMethod.HTTPPath

+ 2 - 1
src/php/README.md

@@ -9,7 +9,8 @@ gRPC PHP installation instructions for Google Cloud Platform is in
 
 ## Environment
 
-###Prerequisite:
+### Prerequisite:
+
 * `php` 5.5 or above, 7.0 or above
 * `pecl`
 * `composer`

+ 0 - 4
src/proto/grpc/testing/messages.proto

@@ -27,7 +27,6 @@ message BoolValue {
   bool value = 1;
 }
 
-// DEPRECATED, don't use. To be removed shortly.
 // The type of payload that should be returned.
 enum PayloadType {
   // Compressable text format.
@@ -36,7 +35,6 @@ enum PayloadType {
 
 // A block of data, to simply increase gRPC message size.
 message Payload {
-  // DEPRECATED, don't use. To be removed shortly.
   // The type of data in body.
   PayloadType type = 1;
   // Primary contents of payload.
@@ -52,7 +50,6 @@ message EchoStatus {
 
 // Unary request.
 message SimpleRequest {
-  // DEPRECATED, don't use. To be removed shortly.
   // Desired payload type in the response from the server.
   // If response_type is RANDOM, server randomly chooses one from other formats.
   PayloadType response_type = 1;
@@ -131,7 +128,6 @@ message ResponseParameters {
 
 // Server-streaming request.
 message StreamingOutputCallRequest {
-  // DEPRECATED, don't use. To be removed shortly.
   // Desired payload type in the response from the server.
   // If response_type is RANDOM, the payload from each response in the stream
   // might be of different types. This is to simulate a mixed type of payload

+ 10 - 8
src/python/grpcio/grpc/__init__.py

@@ -1482,7 +1482,7 @@ def ssl_server_credentials(private_key_certificate_chain_pairs,
       A ServerCredentials for use with an SSL-enabled Server. Typically, this
       object is an argument to add_secure_port() method during server setup.
     """
-    if len(private_key_certificate_chain_pairs) == 0:
+    if not private_key_certificate_chain_pairs:
         raise ValueError(
             'At least one private key-certificate chain pair is required!')
     elif require_client_auth and root_certificates is None:
@@ -1512,15 +1512,15 @@ def ssl_server_certificate_configuration(private_key_certificate_chain_pairs,
       A ServerCertificateConfiguration that can be returned in the certificate
         configuration fetching callback.
     """
-    if len(private_key_certificate_chain_pairs) == 0:
-        raise ValueError(
-            'At least one private key-certificate chain pair is required!')
-    else:
+    if private_key_certificate_chain_pairs:
         return ServerCertificateConfiguration(
             _cygrpc.server_certificate_config_ssl(root_certificates, [
                 _cygrpc.SslPemKeyCertPair(key, pem)
                 for key, pem in private_key_certificate_chain_pairs
             ]))
+    else:
+        raise ValueError(
+            'At least one private key-certificate chain pair is required!')
 
 
 def dynamic_ssl_server_credentials(initial_certificate_configuration,
@@ -1656,9 +1656,11 @@ def server(thread_pool,
       A Server object.
     """
     from grpc import _server  # pylint: disable=cyclic-import
-    return _server.Server(thread_pool, () if handlers is None else handlers, ()
-                          if interceptors is None else interceptors, () if
-                          options is None else options, maximum_concurrent_rpcs)
+    return _server.create_server(thread_pool, ()
+                                 if handlers is None else handlers, ()
+                                 if interceptors is None else interceptors, ()
+                                 if options is None else options,
+                                 maximum_concurrent_rpcs)
 
 
 ###################################  __all__  #################################

+ 2 - 5
src/python/grpcio/grpc/_channel.py

@@ -192,7 +192,7 @@ def _consume_request_iterator(request_iterator, state, call, request_serializer,
             with state.condition:
                 if state.code is None and not state.cancelled:
                     if serialized_request is None:
-                        code = grpc.StatusCode.INTERNAL  # pylint: disable=redefined-variable-type
+                        code = grpc.StatusCode.INTERNAL
                         details = 'Exception serializing request!'
                         call.cancel(
                             _common.STATUS_CODE_TO_CYGRPC_STATUS_CODE[code],
@@ -813,10 +813,7 @@ def _poll_connectivity(state, channel, initial_try_to_connect):
                     _common.CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
                         connectivity])
                 if not state.delivering:
-                    # NOTE(nathaniel): The field is only ever used as a
-                    # sequence so it's fine that both lists and tuples are
-                    # assigned to it.
-                    callbacks = _deliveries(state)  # pylint: disable=redefined-variable-type
+                    callbacks = _deliveries(state)
                     if callbacks:
                         _spawn_delivery(state, callbacks)
 

+ 0 - 0
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd → src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd.pxi


+ 0 - 0
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx → src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi


+ 1 - 1
src/python/grpcio/grpc/_cython/cygrpc.pxd

@@ -29,4 +29,4 @@ include "_cygrpc/server.pxd.pxi"
 include "_cygrpc/tag.pxd.pxi"
 include "_cygrpc/time.pxd.pxi"
 
-include "_cygrpc/grpc_gevent.pxd"
+include "_cygrpc/grpc_gevent.pxd.pxi"

+ 1 - 1
src/python/grpcio/grpc/_cython/cygrpc.pyx

@@ -36,7 +36,7 @@ include "_cygrpc/server.pyx.pxi"
 include "_cygrpc/tag.pyx.pxi"
 include "_cygrpc/time.pyx.pxi"
 
-include "_cygrpc/grpc_gevent.pyx"
+include "_cygrpc/grpc_gevent.pyx.pxi"
 
 #
 # initialize gRPC

+ 13 - 4
src/python/grpcio/grpc/_interceptor.py

@@ -100,6 +100,12 @@ class _LocalFailure(grpc.RpcError, grpc.Future, grpc.Call):
     def cancelled(self):
         return False
 
+    def is_active(self):
+        return False
+
+    def time_remaining(self):
+        return None
+
     def running(self):
         return False
 
@@ -115,6 +121,9 @@ class _LocalFailure(grpc.RpcError, grpc.Future, grpc.Call):
     def traceback(self, ignored_timeout=None):
         return self._traceback
 
+    def add_callback(self, callback):
+        return False
+
     def add_done_callback(self, fn):
         fn(self)
 
@@ -288,11 +297,11 @@ class _Channel(grpc.Channel):
         self._channel = channel
         self._interceptor = interceptor
 
-    def subscribe(self, *args, **kwargs):
-        self._channel.subscribe(*args, **kwargs)
+    def subscribe(self, callback, try_to_connect=False):
+        self._channel.subscribe(callback, try_to_connect=try_to_connect)
 
-    def unsubscribe(self, *args, **kwargs):
-        self._channel.unsubscribe(*args, **kwargs)
+    def unsubscribe(self, callback):
+        self._channel.unsubscribe(callback)
 
     def unary_unary(self,
                     method,

+ 20 - 1
src/python/grpcio/grpc/_server.py

@@ -330,6 +330,8 @@ class _RequestIterator(object):
             self._state.request = None
             return request
 
+        raise AssertionError()  # should never run
+
     def _next(self):
         with self._state.condition:
             self._raise_or_start_receive_message()
@@ -787,7 +789,16 @@ def _start(state):
         thread.start()
 
 
-class Server(grpc.Server):
+def _validate_generic_rpc_handlers(generic_rpc_handlers):
+    for generic_rpc_handler in generic_rpc_handlers:
+        service_attribute = getattr(generic_rpc_handler, 'service', None)
+        if service_attribute is None:
+            raise AttributeError(
+                '"{}" must conform to grpc.GenericRpcHandler type but does '
+                'not have "service" method!'.format(generic_rpc_handler))
+
+
+class _Server(grpc.Server):
 
     # pylint: disable=too-many-arguments
     def __init__(self, thread_pool, generic_handlers, interceptors, options,
@@ -800,6 +811,7 @@ class Server(grpc.Server):
                                    thread_pool, maximum_concurrent_rpcs)
 
     def add_generic_rpc_handlers(self, generic_rpc_handlers):
+        _validate_generic_rpc_handlers(generic_rpc_handlers)
         _add_generic_handlers(self._state, generic_rpc_handlers)
 
     def add_insecure_port(self, address):
@@ -817,3 +829,10 @@ class Server(grpc.Server):
 
     def __del__(self):
         _stop(self._state, None)
+
+
+def create_server(thread_pool, generic_rpc_handlers, interceptors, options,
+                  maximum_concurrent_rpcs):
+    _validate_generic_rpc_handlers(generic_rpc_handlers)
+    return _Server(thread_pool, generic_rpc_handlers, interceptors, options,
+                   maximum_concurrent_rpcs)

+ 2 - 0
src/python/grpcio/grpc/_utilities.py

@@ -116,6 +116,8 @@ class _ChannelReadyFuture(grpc.Future):
             callable_util.call_logging_exceptions(
                 done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
 
+        return True
+
     def cancelled(self):
         with self._condition:
             return self._cancelled

+ 1 - 0
src/python/grpcio/grpc/beta/_server_adaptations.py

@@ -305,6 +305,7 @@ def _simple_method_handler(implementation, request_deserializer,
                                         response_serializer, None, None, None,
                                         _adapt_stream_stream_event(
                                             implementation.stream_stream_event))
+    raise ValueError()
 
 
 def _flatten_method_pair_map(method_pair_map):

+ 2 - 0
src/python/grpcio/grpc/beta/utilities.py

@@ -85,6 +85,8 @@ class _ChannelReadyFuture(future.Future):
             callable_util.call_logging_exceptions(
                 done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
 
+        return True
+
     def cancelled(self):
         with self._condition:
             return self._cancelled

+ 4 - 4
src/python/grpcio/grpc/framework/foundation/stream_util.py

@@ -47,10 +47,10 @@ class IterableConsumer(stream.Consumer):
         self._values = []
         self._active = True
 
-    def consume(self, stock_reply):
+    def consume(self, value):
         with self._condition:
             if self._active:
-                self._values.append(stock_reply)
+                self._values.append(value)
                 self._condition.notify()
 
     def terminate(self):
@@ -58,10 +58,10 @@ class IterableConsumer(stream.Consumer):
             self._active = False
             self._condition.notify()
 
-    def consume_and_terminate(self, stock_reply):
+    def consume_and_terminate(self, value):
         with self._condition:
             if self._active:
-                self._values.append(stock_reply)
+                self._values.append(value)
                 self._active = False
                 self._condition.notify()
 

+ 1 - 1
src/python/grpcio_testing/grpc_testing/__init__.py

@@ -14,9 +14,9 @@
 """Objects for use in testing gRPC Python-using application code."""
 
 import abc
+import six
 
 from google.protobuf import descriptor
-import six
 
 import grpc
 

+ 2 - 2
src/python/grpcio_testing/grpc_testing/_server/_handler.py

@@ -105,10 +105,10 @@ class _Handler(Handler):
                 self._expiration_future.cancel()
             self._condition.notify_all()
 
-    def add_termination_callback(self, termination_callback):
+    def add_termination_callback(self, callback):
         with self._condition:
             if self._code is None:
-                self._termination_callbacks.append(termination_callback)
+                self._termination_callbacks.append(callback)
                 return True
             else:
                 return False

+ 6 - 5
src/python/grpcio_tests/tests/_loader.py

@@ -48,12 +48,13 @@ class Loader(object):
         # 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:
+        imported_modules = tuple(
+            importlib.import_module(name) for name in names)
+        for imported_module in imported_modules:
+            self.visit_module(imported_module)
+        for imported_module in imported_modules:
             try:
-                package_paths = module.__path__
+                package_paths = imported_module.__path__
             except AttributeError:
                 continue
             self.walk_packages(package_paths)

+ 15 - 26
src/python/grpcio_tests/tests/_result.py

@@ -144,10 +144,6 @@ class AugmentedResult(unittest.TestResult):
         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)
@@ -155,19 +151,19 @@ class AugmentedResult(unittest.TestResult):
         self.cases[case_id] = CaseResult(
             id=case_id, name=test.id(), kind=CaseResult.Kind.RUNNING)
 
-    def addError(self, test, error):
+    def addError(self, test, err):
         """See unittest.TestResult.addError."""
-        super(AugmentedResult, self).addError(test, error)
+        super(AugmentedResult, self).addError(test, err)
         case_id = self.id_map(test)
         self.cases[case_id] = self.cases[case_id].updated(
-            kind=CaseResult.Kind.ERROR, traceback=error)
+            kind=CaseResult.Kind.ERROR, traceback=err)
 
-    def addFailure(self, test, error):
+    def addFailure(self, test, err):
         """See unittest.TestResult.addFailure."""
-        super(AugmentedResult, self).addFailure(test, error)
+        super(AugmentedResult, self).addFailure(test, err)
         case_id = self.id_map(test)
         self.cases[case_id] = self.cases[case_id].updated(
-            kind=CaseResult.Kind.FAILURE, traceback=error)
+            kind=CaseResult.Kind.FAILURE, traceback=err)
 
     def addSuccess(self, test):
         """See unittest.TestResult.addSuccess."""
@@ -183,12 +179,12 @@ class AugmentedResult(unittest.TestResult):
         self.cases[case_id] = self.cases[case_id].updated(
             kind=CaseResult.Kind.SKIP, skip_reason=reason)
 
-    def addExpectedFailure(self, test, error):
+    def addExpectedFailure(self, test, err):
         """See unittest.TestResult.addExpectedFailure."""
-        super(AugmentedResult, self).addExpectedFailure(test, error)
+        super(AugmentedResult, self).addExpectedFailure(test, err)
         case_id = self.id_map(test)
         self.cases[case_id] = self.cases[case_id].updated(
-            kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=error)
+            kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=err)
 
     def addUnexpectedSuccess(self, test):
         """See unittest.TestResult.addUnexpectedSuccess."""
@@ -249,13 +245,6 @@ class CoverageResult(AugmentedResult):
         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(object):
     """Namespaced constants for terminal color magic numbers."""
@@ -295,16 +284,16 @@ class TerminalResult(CoverageResult):
         self.out.write(summary(self))
         self.out.flush()
 
-    def addError(self, test, error):
+    def addError(self, test, err):
         """See unittest.TestResult.addError."""
-        super(TerminalResult, self).addError(test, error)
+        super(TerminalResult, self).addError(test, err)
         self.out.write(
             _Colors.FAIL + 'ERROR         {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
 
-    def addFailure(self, test, error):
+    def addFailure(self, test, err):
         """See unittest.TestResult.addFailure."""
-        super(TerminalResult, self).addFailure(test, error)
+        super(TerminalResult, self).addFailure(test, err)
         self.out.write(
             _Colors.FAIL + 'FAILURE       {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
@@ -323,9 +312,9 @@ class TerminalResult(CoverageResult):
             _Colors.INFO + 'SKIP          {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
 
-    def addExpectedFailure(self, test, error):
+    def addExpectedFailure(self, test, err):
         """See unittest.TestResult.addExpectedFailure."""
-        super(TerminalResult, self).addExpectedFailure(test, error)
+        super(TerminalResult, self).addExpectedFailure(test, err)
         self.out.write(
             _Colors.INFO + 'FAILURE_OK    {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()

+ 2 - 2
src/python/grpcio_tests/tests/interop/methods.py

@@ -144,8 +144,8 @@ def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope,
 def _empty_unary(stub):
     response = stub.EmptyCall(empty_pb2.Empty())
     if not isinstance(response, empty_pb2.Empty):
-        raise TypeError('response is of type "%s", not empty_pb2.Empty!',
-                        type(response))
+        raise TypeError(
+            'response is of type "%s", not empty_pb2.Empty!' % type(response))
 
 
 def _large_unary(stub):

+ 1 - 0
src/python/grpcio_tests/tests/tests.json

@@ -53,6 +53,7 @@
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestCertConfigReuse",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithClientAuth",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithoutClientAuth",
+  "unit._server_test.ServerTest",
   "unit._session_cache_test.SSLSessionCacheTest",
   "unit.beta._beta_features_test.BetaFeaturesTest",
   "unit.beta._beta_features_test.ContextManagementAndLifecycleTest",

+ 0 - 13
src/python/grpcio_tests/tests/unit/_junkdrawer/__init__.py

@@ -1,13 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.

+ 0 - 164
src/python/grpcio_tests/tests/unit/_junkdrawer/stock_pb2.py

@@ -1,164 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# TODO(nathaniel): Remove this from source control after having made
-# generation from the stock.proto source part of GRPC's build-and-test
-# process.
-
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: stock.proto
-
-import sys
-_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode('latin1'))
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-    name='stock.proto',
-    package='stock',
-    serialized_pb=_b(
-        '\n\x0bstock.proto\x12\x05stock\">\n\x0cStockRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x1e\n\x13num_trades_to_watch\x18\x02 \x01(\x05:\x01\x30\"+\n\nStockReply\x12\r\n\x05price\x18\x01 \x01(\x02\x12\x0e\n\x06symbol\x18\x02 \x01(\t2\x96\x02\n\x05Stock\x12=\n\x11GetLastTradePrice\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00\x12I\n\x19GetLastTradePriceMultiple\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00(\x01\x30\x01\x12?\n\x11WatchFutureTrades\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00\x30\x01\x12\x42\n\x14GetHighestTradePrice\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00(\x01'
-    ))
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-_STOCKREQUEST = _descriptor.Descriptor(
-    name='StockRequest',
-    full_name='stock.StockRequest',
-    filename=None,
-    file=DESCRIPTOR,
-    containing_type=None,
-    fields=[
-        _descriptor.FieldDescriptor(
-            name='symbol',
-            full_name='stock.StockRequest.symbol',
-            index=0,
-            number=1,
-            type=9,
-            cpp_type=9,
-            label=1,
-            has_default_value=False,
-            default_value=_b("").decode('utf-8'),
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-        _descriptor.FieldDescriptor(
-            name='num_trades_to_watch',
-            full_name='stock.StockRequest.num_trades_to_watch',
-            index=1,
-            number=2,
-            type=5,
-            cpp_type=1,
-            label=1,
-            has_default_value=True,
-            default_value=0,
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-    ],
-    extensions=[],
-    nested_types=[],
-    enum_types=[],
-    options=None,
-    is_extendable=False,
-    extension_ranges=[],
-    oneofs=[],
-    serialized_start=22,
-    serialized_end=84,)
-
-_STOCKREPLY = _descriptor.Descriptor(
-    name='StockReply',
-    full_name='stock.StockReply',
-    filename=None,
-    file=DESCRIPTOR,
-    containing_type=None,
-    fields=[
-        _descriptor.FieldDescriptor(
-            name='price',
-            full_name='stock.StockReply.price',
-            index=0,
-            number=1,
-            type=2,
-            cpp_type=6,
-            label=1,
-            has_default_value=False,
-            default_value=0,
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-        _descriptor.FieldDescriptor(
-            name='symbol',
-            full_name='stock.StockReply.symbol',
-            index=1,
-            number=2,
-            type=9,
-            cpp_type=9,
-            label=1,
-            has_default_value=False,
-            default_value=_b("").decode('utf-8'),
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-    ],
-    extensions=[],
-    nested_types=[],
-    enum_types=[],
-    options=None,
-    is_extendable=False,
-    extension_ranges=[],
-    oneofs=[],
-    serialized_start=86,
-    serialized_end=129,)
-
-DESCRIPTOR.message_types_by_name['StockRequest'] = _STOCKREQUEST
-DESCRIPTOR.message_types_by_name['StockReply'] = _STOCKREPLY
-
-StockRequest = _reflection.GeneratedProtocolMessageType(
-    'StockRequest',
-    (_message.Message,),
-    dict(
-        DESCRIPTOR=_STOCKREQUEST,
-        __module__='stock_pb2'
-        # @@protoc_insertion_point(class_scope:stock.StockRequest)
-    ))
-_sym_db.RegisterMessage(StockRequest)
-
-StockReply = _reflection.GeneratedProtocolMessageType(
-    'StockReply',
-    (_message.Message,),
-    dict(
-        DESCRIPTOR=_STOCKREPLY,
-        __module__='stock_pb2'
-        # @@protoc_insertion_point(class_scope:stock.StockReply)
-    ))
-_sym_db.RegisterMessage(StockReply)
-
-# @@protoc_insertion_point(module_scope)

+ 52 - 0
src/python/grpcio_tests/tests/unit/_server_test.py

@@ -0,0 +1,52 @@
+# Copyright 2018 The gRPC Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from concurrent import futures
+import unittest
+
+import grpc
+
+
+class _ActualGenericRpcHandler(grpc.GenericRpcHandler):
+
+    def service(self, handler_call_details):
+        return None
+
+
+class ServerTest(unittest.TestCase):
+
+    def test_not_a_generic_rpc_handler_at_construction(self):
+        with self.assertRaises(AttributeError) as exception_context:
+            grpc.server(
+                futures.ThreadPoolExecutor(max_workers=5),
+                handlers=[
+                    _ActualGenericRpcHandler(),
+                    object(),
+                ])
+        self.assertIn('grpc.GenericRpcHandler',
+                      str(exception_context.exception))
+
+    def test_not_a_generic_rpc_handler_after_construction(self):
+        server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
+        with self.assertRaises(AttributeError) as exception_context:
+            server.add_generic_rpc_handlers([
+                _ActualGenericRpcHandler(),
+                object(),
+            ])
+        self.assertIn('grpc.GenericRpcHandler',
+                      str(exception_context.exception))
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)

+ 3 - 3
templates/test/cpp/naming/resolver_component_tests_defs.include

@@ -58,7 +58,7 @@ def wait_until_dns_server_is_up(args,
     test_runner_log('Health check: attempt to connect to DNS server over TCP.')
     tcp_connect_subprocess = subprocess.Popen([
         args.tcp_connect_bin_path,
-        '--server_host', '::1',
+        '--server_host', '127.0.0.1',
         '--server_port', str(args.dns_server_port),
         '--timeout', str(1)])
     tcp_connect_subprocess.communicate()
@@ -68,7 +68,7 @@ def wait_until_dns_server_is_up(args,
       dns_resolver_subprocess = subprocess.Popen([
           args.dns_resolver_bin_path,
           '--qname', 'health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp',
-          '--server_host', '::1',
+          '--server_host', '127.0.0.1',
           '--server_port', str(args.dns_server_port)],
           stdout=subprocess.PIPE)
       dns_resolver_stdout, _ = dns_resolver_subprocess.communicate()
@@ -125,7 +125,7 @@ current_test_subprocess = subprocess.Popen([\
 
 \
   % endfor
-  '--local_dns_server_address', '[::1]:%d' % args.dns_server_port])\
+  '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port])\
 
 current_test_subprocess.communicate()\
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 3359
test/core/avl/avl_test.cc


+ 8 - 0
test/core/end2end/end2end_nosec_tests.cc

@@ -100,6 +100,8 @@ extern void negative_deadline(grpc_end2end_test_config config);
 extern void negative_deadline_pre_init(void);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change_pre_init(void);
+extern void no_error_on_hotpath(grpc_end2end_test_config config);
+extern void no_error_on_hotpath_pre_init(void);
 extern void no_logging(grpc_end2end_test_config config);
 extern void no_logging_pre_init(void);
 extern void no_op(grpc_end2end_test_config config);
@@ -222,6 +224,7 @@ void grpc_end2end_tests_pre_init(void) {
   max_message_length_pre_init();
   negative_deadline_pre_init();
   network_status_change_pre_init();
+  no_error_on_hotpath_pre_init();
   no_logging_pre_init();
   no_op_pre_init();
   payload_pre_init();
@@ -307,6 +310,7 @@ void grpc_end2end_tests(int argc, char **argv,
     max_message_length(config);
     negative_deadline(config);
     network_status_change(config);
+    no_error_on_hotpath(config);
     no_logging(config);
     no_op(config);
     payload(config);
@@ -492,6 +496,10 @@ void grpc_end2end_tests(int argc, char **argv,
       network_status_change(config);
       continue;
     }
+    if (0 == strcmp("no_error_on_hotpath", argv[i])) {
+      no_error_on_hotpath(config);
+      continue;
+    }
     if (0 == strcmp("no_logging", argv[i])) {
       no_logging(config);
       continue;

+ 8 - 0
test/core/end2end/end2end_tests.cc

@@ -102,6 +102,8 @@ extern void negative_deadline(grpc_end2end_test_config config);
 extern void negative_deadline_pre_init(void);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change_pre_init(void);
+extern void no_error_on_hotpath(grpc_end2end_test_config config);
+extern void no_error_on_hotpath_pre_init(void);
 extern void no_logging(grpc_end2end_test_config config);
 extern void no_logging_pre_init(void);
 extern void no_op(grpc_end2end_test_config config);
@@ -225,6 +227,7 @@ void grpc_end2end_tests_pre_init(void) {
   max_message_length_pre_init();
   negative_deadline_pre_init();
   network_status_change_pre_init();
+  no_error_on_hotpath_pre_init();
   no_logging_pre_init();
   no_op_pre_init();
   payload_pre_init();
@@ -311,6 +314,7 @@ void grpc_end2end_tests(int argc, char **argv,
     max_message_length(config);
     negative_deadline(config);
     network_status_change(config);
+    no_error_on_hotpath(config);
     no_logging(config);
     no_op(config);
     payload(config);
@@ -500,6 +504,10 @@ void grpc_end2end_tests(int argc, char **argv,
       network_status_change(config);
       continue;
     }
+    if (0 == strcmp("no_error_on_hotpath", argv[i])) {
+      no_error_on_hotpath(config);
+      continue;
+    }
     if (0 == strcmp("no_logging", argv[i])) {
       no_logging(config);
       continue;

+ 1 - 0
test/core/end2end/gen_build_yaml.py

@@ -138,6 +138,7 @@ END2END_TESTS = {
     'max_message_length': default_test_options._replace(cpu_cost=LOWCPU),
     'negative_deadline': default_test_options,
     'network_status_change': default_test_options._replace(cpu_cost=LOWCPU),
+    'no_error_on_hotpath': default_test_options._replace(proxyable=False),
     'no_logging': default_test_options._replace(traceable=False),
     'no_op': default_test_options,
     'payload': default_test_options,

+ 1 - 0
test/core/end2end/generate_tests.bzl

@@ -134,6 +134,7 @@ END2END_TESTS = {
     'max_message_length': test_options(),
     'negative_deadline': test_options(),
     'network_status_change': test_options(),
+    'no_error_on_hotpath': test_options(proxyable=False),
     'no_logging': test_options(traceable=False),
     'no_op': test_options(),
     'payload': test_options(),

+ 246 - 0
test/core/end2end/tests/no_error_on_hotpath.cc

@@ -0,0 +1,246 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/error.h"
+#include "test/core/end2end/cq_verifier.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
+  grpc_call* c;
+  grpc_call* s;
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               grpc_slice_from_static_string("/foo"), nullptr,
+                               deadline, nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  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_OK;
+  op->data.send_status_from_server.status_details = nullptr;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(GRPC_SLICE_LENGTH(details) == 0);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 0);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+}
+
+static void test_no_error_on_hotpath_one_request(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  f = begin_test(config, "test_invoke_simple_request_with_no_error_logging",
+                 nullptr, nullptr);
+  // First RPC is not considered the hotpath, since there are lots of things to
+  // set up.
+  simple_request_body(config, f);
+  grpc_disable_error_creation();
+  simple_request_body(config, f);
+  grpc_enable_error_creation();
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_no_error_on_hotpath_10_requests(
+    grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_no_error_on_hotpath_in_one_request", nullptr, nullptr);
+  // First RPC is not considered the hotpath, since there are lots of things to
+  // set up.
+  simple_request_body(config, f);
+  grpc_disable_error_creation();
+  for (i = 0; i < 10; i++) {
+    simple_request_body(config, f);
+  }
+  grpc_enable_error_creation();
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void no_error_on_hotpath(grpc_end2end_test_config config) {
+  test_no_error_on_hotpath_one_request(config);
+  test_no_error_on_hotpath_10_requests(config);
+}
+
+void no_error_on_hotpath_pre_init(void) {}

+ 2 - 0
test/core/gprpp/inlined_vector_test.cc

@@ -27,10 +27,12 @@ namespace testing {
 TEST(InlinedVectorTest, CreateAndIterate) {
   const int kNumElements = 9;
   InlinedVector<int, 2> v;
+  EXPECT_TRUE(v.empty());
   for (int i = 0; i < kNumElements; ++i) {
     v.push_back(i);
   }
   EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
+  EXPECT_FALSE(v.empty());
   for (int i = 0; i < kNumElements; ++i) {
     EXPECT_EQ(i, v[i]);
     EXPECT_EQ(i, &v[i] - &v[0]);  // Ensure contiguous allocation.

+ 1 - 0
test/core/iomgr/BUILD

@@ -227,6 +227,7 @@ grpc_cc_test(
         "//test/core/util:gpr_test_util",
         "//test/core/util:grpc_test_util",
     ],
+    tags = ["manual"],    # TODO(adelez): Remove once this works on Foundry.
 )
 
 grpc_cc_test(

+ 4 - 6
test/core/iomgr/ev_epollsig_linux_test.cc

@@ -66,7 +66,7 @@ static void test_fd_init(test_fd* tfds, int* fds, int num_fds) {
 
   for (i = 0; i < num_fds; i++) {
     tfds[i].inner_fd = fds[i];
-    tfds[i].fd = grpc_fd_create(fds[i], "test_fd");
+    tfds[i].fd = grpc_fd_create(fds[i], "test_fd", false);
   }
 }
 
@@ -79,8 +79,7 @@ static void test_fd_cleanup(test_fd* tfds, int num_fds) {
                      GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup"));
     grpc_core::ExecCtx::Get()->Flush();
 
-    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, false /* already_closed */,
-                   "test_fd_cleanup");
+    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
     grpc_core::ExecCtx::Get()->Flush();
 
     GPR_ASSERT(release_fd == tfds[i].inner_fd);
@@ -267,7 +266,7 @@ static void test_threading(void) {
   grpc_wakeup_fd fd;
   GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd)));
   shared.wakeup_fd = &fd;
-  shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup");
+  shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup", false);
   shared.wakeups = 0;
   {
     grpc_core::ExecCtx exec_ctx;
@@ -287,8 +286,7 @@ static void test_threading(void) {
   {
     grpc_core::ExecCtx exec_ctx;
     grpc_fd_shutdown(shared.wakeup_desc, GRPC_ERROR_CANCELLED);
-    grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr,
-                   false /* already_closed */, "done");
+    grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr, "done");
     grpc_pollset_shutdown(shared.pollset,
                           GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset,
                                               grpc_schedule_on_exec_ctx));

+ 8 - 8
test/core/iomgr/fd_posix_test.cc

@@ -115,7 +115,7 @@ static void session_shutdown_cb(void* arg, /*session */
                                 bool success) {
   session* se = static_cast<session*>(arg);
   server* sv = se->sv;
-  grpc_fd_orphan(se->em_fd, nullptr, nullptr, false /* already_closed */, "a");
+  grpc_fd_orphan(se->em_fd, nullptr, nullptr, "a");
   gpr_free(se);
   /* Start to shutdown listen fd. */
   grpc_fd_shutdown(sv->em_fd,
@@ -171,7 +171,7 @@ static void session_read_cb(void* arg, /*session */
 static void listen_shutdown_cb(void* arg /*server */, int success) {
   server* sv = static_cast<server*>(arg);
 
-  grpc_fd_orphan(sv->em_fd, nullptr, nullptr, false /* already_closed */, "b");
+  grpc_fd_orphan(sv->em_fd, nullptr, nullptr, "b");
 
   gpr_mu_lock(g_mu);
   sv->done = 1;
@@ -204,7 +204,7 @@ static void listen_cb(void* arg, /*=sv_arg*/
   fcntl(fd, F_SETFL, flags | O_NONBLOCK);
   se = static_cast<session*>(gpr_malloc(sizeof(*se)));
   se->sv = sv;
-  se->em_fd = grpc_fd_create(fd, "listener");
+  se->em_fd = grpc_fd_create(fd, "listener", false);
   grpc_pollset_add_fd(g_pollset, se->em_fd);
   GRPC_CLOSURE_INIT(&se->session_read_closure, session_read_cb, se,
                     grpc_schedule_on_exec_ctx);
@@ -233,7 +233,7 @@ static int server_start(server* sv) {
   port = ntohs(sin.sin_port);
   GPR_ASSERT(listen(fd, MAX_NUM_FD) == 0);
 
-  sv->em_fd = grpc_fd_create(fd, "server");
+  sv->em_fd = grpc_fd_create(fd, "server", false);
   grpc_pollset_add_fd(g_pollset, sv->em_fd);
   /* Register to be interested in reading from listen_fd. */
   GRPC_CLOSURE_INIT(&sv->listen_closure, listen_cb, sv,
@@ -289,7 +289,7 @@ static void client_init(client* cl) {
 /* Called when a client upload session is ready to shutdown. */
 static void client_session_shutdown_cb(void* arg /*client */, int success) {
   client* cl = static_cast<client*>(arg);
-  grpc_fd_orphan(cl->em_fd, nullptr, nullptr, false /* already_closed */, "c");
+  grpc_fd_orphan(cl->em_fd, nullptr, nullptr, "c");
   cl->done = 1;
   GPR_ASSERT(
       GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, nullptr)));
@@ -353,7 +353,7 @@ static void client_start(client* cl, int port) {
     }
   }
 
-  cl->em_fd = grpc_fd_create(fd, "client");
+  cl->em_fd = grpc_fd_create(fd, "client", false);
   grpc_pollset_add_fd(g_pollset, cl->em_fd);
 
   client_session_write(cl, GRPC_ERROR_NONE);
@@ -454,7 +454,7 @@ static void test_grpc_fd_change(void) {
   flags = fcntl(sv[1], F_GETFL, 0);
   GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
 
-  em_fd = grpc_fd_create(sv[0], "test_grpc_fd_change");
+  em_fd = grpc_fd_create(sv[0], "test_grpc_fd_change", false);
   grpc_pollset_add_fd(g_pollset, em_fd);
 
   /* Register the first callback, then make its FD readable */
@@ -502,7 +502,7 @@ static void test_grpc_fd_change(void) {
   GPR_ASSERT(b.cb_that_ran == second_read_callback);
   gpr_mu_unlock(g_mu);
 
-  grpc_fd_orphan(em_fd, nullptr, nullptr, false /* already_closed */, "d");
+  grpc_fd_orphan(em_fd, nullptr, nullptr, "d");
 
   destroy_change_data(&a);
   destroy_change_data(&b);

+ 2 - 3
test/core/iomgr/pollset_set_test.cc

@@ -118,7 +118,7 @@ static void init_test_fds(test_fd* tfds, const int num_fds) {
   for (int i = 0; i < num_fds; i++) {
     GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_init(&tfds[i].wakeup_fd));
     tfds[i].fd = grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&tfds[i].wakeup_fd),
-                                "test_fd");
+                                "test_fd", false);
     reset_test_fd(&tfds[i]);
   }
 }
@@ -136,8 +136,7 @@ static void cleanup_test_fds(test_fd* tfds, const int num_fds) {
      * grpc_wakeup_fd and we would like to destroy it ourselves (by calling
      * grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the
      * underlying fd, call it with a non-NULL 'release_fd' parameter */
-    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, false /* already_closed */,
-                   "test_fd_cleanup");
+    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
     grpc_core::ExecCtx::Get()->Flush();
 
     grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd);

+ 12 - 8
test/core/iomgr/tcp_posix_test.cc

@@ -176,7 +176,8 @@ static void read_test(size_t num_bytes, size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER,
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), &args, "test");
+  ep =
+      grpc_tcp_create(grpc_fd_create(sv[1], "read_test", false), &args, "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -226,7 +227,8 @@ static void large_read_test(size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER;
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), &args, "test");
+  ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test", false), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
   written_bytes = fill_socket(sv[0]);
@@ -365,7 +367,8 @@ static void write_test(size_t num_bytes, size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER,
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), &args, "test");
+  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test", false), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
   state.ep = ep;
@@ -433,7 +436,8 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER;
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), &args, "test");
+  ep =
+      grpc_tcp_create(grpc_fd_create(sv[1], "read_test", false), &args, "test");
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
@@ -522,10 +526,10 @@ static grpc_endpoint_test_fixture create_fixture_tcp_socketpair(
   a[0].type = GRPC_ARG_INTEGER;
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  f.client_ep =
-      grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"), &args, "test");
-  f.server_ep =
-      grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"), &args, "test");
+  f.client_ep = grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client", false),
+                                &args, "test");
+  f.server_ep = grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server", false),
+                                &args, "test");
   grpc_resource_quota_unref_internal(resource_quota);
   grpc_endpoint_add_to_pollset(f.client_ep, g_pollset);
   grpc_endpoint_add_to_pollset(f.server_ep, g_pollset);

+ 19 - 6
test/core/transport/status_conversion_test.cc

@@ -33,12 +33,7 @@
 #define HTTP2_STATUS_TO_GRPC_STATUS(a, b) \
   GPR_ASSERT(grpc_http2_status_to_grpc_status(a) == (b))
 
-int main(int argc, char** argv) {
-  int i;
-
-  grpc_test_init(argc, argv);
-  grpc_init();
-
+static void test_grpc_status_to_http2_error() {
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_OK, GRPC_HTTP2_NO_ERROR);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_CANCELLED, GRPC_HTTP2_CANCEL);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNKNOWN, GRPC_HTTP2_INTERNAL_ERROR);
@@ -65,7 +60,9 @@ int main(int argc, char** argv) {
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNAVAILABLE,
                              GRPC_HTTP2_REFUSED_STREAM);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_DATA_LOSS, GRPC_HTTP2_INTERNAL_ERROR);
+}
 
+static void test_grpc_status_to_http2_status() {
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_OK, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_CANCELLED, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNKNOWN, 200);
@@ -83,7 +80,9 @@ int main(int argc, char** argv) {
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_INTERNAL, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNAVAILABLE, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_DATA_LOSS, 200);
+}
 
+static void test_http2_error_to_grpc_status() {
   const grpc_millis before_deadline = GRPC_MILLIS_INF_FUTURE;
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_NO_ERROR, before_deadline,
                              GRPC_STATUS_INTERNAL);
@@ -144,7 +143,9 @@ int main(int argc, char** argv) {
                              GRPC_STATUS_RESOURCE_EXHAUSTED);
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_INADEQUATE_SECURITY, after_deadline,
                              GRPC_STATUS_PERMISSION_DENIED);
+}
 
+static void test_http2_status_to_grpc_status() {
   HTTP2_STATUS_TO_GRPC_STATUS(200, GRPC_STATUS_OK);
   HTTP2_STATUS_TO_GRPC_STATUS(400, GRPC_STATUS_INVALID_ARGUMENT);
   HTTP2_STATUS_TO_GRPC_STATUS(401, GRPC_STATUS_UNAUTHENTICATED);
@@ -157,6 +158,18 @@ int main(int argc, char** argv) {
   HTTP2_STATUS_TO_GRPC_STATUS(500, GRPC_STATUS_UNKNOWN);
   HTTP2_STATUS_TO_GRPC_STATUS(503, GRPC_STATUS_UNAVAILABLE);
   HTTP2_STATUS_TO_GRPC_STATUS(504, GRPC_STATUS_DEADLINE_EXCEEDED);
+}
+
+int main(int argc, char** argv) {
+  int i;
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  test_grpc_status_to_http2_error();
+  test_grpc_status_to_http2_status();
+  test_http2_error_to_grpc_status();
+  test_http2_status_to_grpc_status();
 
   /* check all status values can be converted */
   for (i = 0; i <= 999; i++) {

+ 5 - 0
test/cpp/end2end/end2end_test.cc

@@ -1207,10 +1207,15 @@ TEST_P(End2endTest, ExpectErrorTest) {
   ResetStub();
 
   std::vector<ErrorStatus> expected_status;
+  expected_status.emplace_back();
+  expected_status.back().set_code(13);  // INTERNAL
+  // No Error message or details
+
   expected_status.emplace_back();
   expected_status.back().set_code(13);  // INTERNAL
   expected_status.back().set_error_message("text error message");
   expected_status.back().set_binary_error_details("text error details");
+
   expected_status.emplace_back();
   expected_status.back().set_code(13);  // INTERNAL
   expected_status.back().set_error_message("text error message");

+ 4 - 4
test/cpp/microbenchmarks/bm_pollset.cc

@@ -141,12 +141,12 @@ static void BM_PollAddFd(benchmark::State& state) {
   grpc_wakeup_fd wakeup_fd;
   GPR_ASSERT(
       GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&wakeup_fd)));
-  grpc_fd* fd = grpc_fd_create(wakeup_fd.read_fd, "xxx");
+  grpc_fd* fd = grpc_fd_create(wakeup_fd.read_fd, "xxx", false);
   while (state.KeepRunning()) {
     grpc_pollset_add_fd(ps, fd);
     grpc_core::ExecCtx::Get()->Flush();
   }
-  grpc_fd_orphan(fd, nullptr, nullptr, false /* already_closed */, "xxx");
+  grpc_fd_orphan(fd, nullptr, nullptr, "xxx");
   grpc_closure shutdown_ps_closure;
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,
                     grpc_schedule_on_exec_ctx);
@@ -222,7 +222,7 @@ static void BM_SingleThreadPollOneFd(benchmark::State& state) {
   grpc_core::ExecCtx exec_ctx;
   grpc_wakeup_fd wakeup_fd;
   GRPC_ERROR_UNREF(grpc_wakeup_fd_init(&wakeup_fd));
-  grpc_fd* wakeup = grpc_fd_create(wakeup_fd.read_fd, "wakeup_read");
+  grpc_fd* wakeup = grpc_fd_create(wakeup_fd.read_fd, "wakeup_read", false);
   grpc_pollset_add_fd(ps, wakeup);
   bool done = false;
   Closure* continue_closure = MakeClosure(
@@ -242,7 +242,7 @@ static void BM_SingleThreadPollOneFd(benchmark::State& state) {
   while (!done) {
     GRPC_ERROR_UNREF(grpc_pollset_work(ps, nullptr, GRPC_MILLIS_INF_FUTURE));
   }
-  grpc_fd_orphan(wakeup, nullptr, nullptr, false /* already_closed */, "done");
+  grpc_fd_orphan(wakeup, nullptr, nullptr, "done");
   wakeup_fd.read_fd = 0;
   grpc_closure shutdown_ps_closure;
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.