Merge branch 'master' into cq_mpsc_based

pull/10662/head
Sree Kuchibhotla 8 years ago
commit a72d79b1fc
  1. 53
      BUILD
  2. 26
      Makefile
  3. 4
      bazel/cc_grpc_library.bzl
  4. 11
      bazel/generate_cc.bzl
  5. 14
      bazel/grpc_build_system.bzl
  6. 5
      build.yaml
  7. 21
      doc/service_config.md
  8. 1
      grpc.def
  9. 4
      include/grpc++/impl/codegen/client_unary_call.h
  10. 36
      include/grpc++/impl/codegen/completion_queue.h
  11. 9
      include/grpc++/impl/codegen/core_codegen.h
  12. 6
      include/grpc++/impl/codegen/core_codegen_interface.h
  13. 12
      include/grpc++/impl/codegen/sync_stream.h
  14. 163
      include/grpc++/test/mock_stream.h
  15. 58
      include/grpc/grpc.h
  16. 49
      include/grpc/impl/codegen/grpc_types.h
  17. 176
      src/compiler/cpp_generator.cc
  18. 34
      src/compiler/cpp_generator.h
  19. 21
      src/compiler/cpp_plugin.cc
  20. 18
      src/core/ext/filters/client_channel/client_channel.c
  21. 8
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
  22. 2
      src/core/ext/transport/chttp2/server/chttp2_server.c
  23. 19
      src/core/lib/iomgr/udp_server.c
  24. 195
      src/core/lib/surface/completion_queue.c
  25. 6
      src/core/lib/surface/completion_queue.h
  26. 19
      src/core/lib/surface/server.c
  27. 12
      src/cpp/common/core_codegen.cc
  28. 28
      src/cpp/server/server_builder.cc
  29. 8
      src/node/ext/server_generic.cc
  30. 39
      src/proto/grpc/health/v1/BUILD
  31. 2
      src/proto/grpc/testing/BUILD
  32. 8
      src/proto/grpc/testing/compiler_test.proto
  33. 3
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  34. 11
      src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
  35. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  36. 3
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  37. 14
      templates/Makefile.template
  38. 2
      templates/tools/run_tests/generated/sources_and_headers.json.template
  39. 52
      test/core/end2end/fixtures/http_proxy_fixture.c
  40. 9
      test/core/end2end/tests/cancel_after_invoke.c
  41. 2
      test/cpp/codegen/BUILD
  42. 144
      test/cpp/codegen/compiler_test_golden
  43. 34
      test/cpp/codegen/compiler_test_mock_golden
  44. 31
      test/cpp/codegen/golden_file_test.cc
  45. 1
      test/cpp/end2end/BUILD
  46. 20
      test/cpp/end2end/async_end2end_test.cc
  47. 278
      test/cpp/end2end/mock_test.cc
  48. 5
      third_party/gtest.BUILD
  49. 83
      tools/run_tests/generated/sources_and_headers.json
  50. 2
      tools/run_tests/generated/tests.json
  51. 3
      vsprojects/vcxproj/test/mock_test/mock_test.vcxproj
  52. 14
      vsprojects/vcxproj/test/mock_test/mock_test.vcxproj.filters

53
BUILD

@ -54,33 +54,46 @@ grpc_cc_library(
], ],
) )
grpc_cc_library( grpc_cc_libraries(
name = "grpc", name_list = ["grpc", "grpc_unsecure",],
srcs = [ srcs = [
"src/core/lib/surface/init.c", "src/core/lib/surface/init.c",
],
additional_src_list = [
[
"src/core/plugin_registry/grpc_plugin_registry.c", "src/core/plugin_registry/grpc_plugin_registry.c",
], ],
[
"src/core/lib/surface/init_unsecure.c",
"src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
],
],
language = "c", language = "c",
standalone = True, standalone = True,
deps = [ deps = [
"census", "census",
"grpc_base", "grpc_base",
"grpc_lb_policy_grpclb_secure",
"grpc_lb_policy_pick_first", "grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin", "grpc_lb_policy_round_robin",
"grpc_load_reporting", "grpc_load_reporting",
"grpc_max_age_filter", "grpc_max_age_filter",
"grpc_resolver_dns_ares",
"grpc_resolver_dns_native", "grpc_resolver_dns_native",
"grpc_resolver_sockaddr", "grpc_resolver_sockaddr",
"grpc_secure",
"grpc_transport_chttp2_client_insecure", "grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_insecure", "grpc_transport_chttp2_server_insecure",
"grpc_transport_chttp2_server_secure",
"grpc_message_size_filter", "grpc_message_size_filter",
"grpc_deadline_filter", "grpc_deadline_filter",
], ],
additional_dep_list = [
[
"grpc_secure",
"grpc_resolver_dns_ares",
"grpc_lb_policy_grpclb_secure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_secure",
],
[],
],
) )
grpc_cc_library( grpc_cc_library(
@ -98,32 +111,6 @@ grpc_cc_library(
], ],
) )
grpc_cc_library(
name = "grpc_unsecure",
srcs = [
"src/core/lib/surface/init.c",
"src/core/lib/surface/init_unsecure.c",
"src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
],
language = "c",
standalone = True,
deps = [
"census",
"grpc_base",
"grpc_lb_policy_grpclb",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
"grpc_max_age_filter",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
"grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_server_insecure",
"grpc_message_size_filter",
"grpc_deadline_filter",
],
)
grpc_cc_library( grpc_cc_library(
name = "grpc++", name = "grpc++",
srcs = [ srcs = [

@ -418,7 +418,7 @@ AROPTS = $(GRPC_CROSS_AROPTS) # e.g., rc --target=elf32-little
USE_BUILT_PROTOC = false USE_BUILT_PROTOC = false
endif endif
GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc -Ithird_party/googletest/googlemock/include -Ithird_party/googletest/googlemock third_party/googletest/googlemock/src/gmock-all.cc
GTEST_LIB += -lgflags GTEST_LIB += -lgflags
ifeq ($(V),1) ifeq ($(V),1)
E = @: E = @:
@ -793,7 +793,7 @@ PROTOBUF_PKG_CONFIG = false
PC_REQUIRES_GRPCXX = PC_REQUIRES_GRPCXX =
PC_LIBS_GRPCXX = PC_LIBS_GRPCXX =
CPPFLAGS := -Ithird_party/googletest/googletest/include $(CPPFLAGS) CPPFLAGS := -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googlemock/include $(CPPFLAGS)
PROTOC_PLUGINS_ALL = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_php_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin PROTOC_PLUGINS_ALL = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_php_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG) PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG)
@ -2238,6 +2238,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: src/proto/grpc/health/v1/health.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: src/proto/grpc/health/v1/health.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2253,6 +2254,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2268,6 +2270,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: src/proto/grpc/reflection/v1alpha/reflection.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: src/proto/grpc/reflection/v1alpha/reflection.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2283,6 +2286,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/status/status.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/status/status.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/status/status.pb.cc: src/proto/grpc/status/status.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/status/status.pb.cc: src/proto/grpc/status/status.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2298,6 +2302,8 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2306,13 +2312,14 @@ $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/com
$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=generate_mock_code=true:$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif endif
ifeq ($(NO_PROTOC),true) ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/control.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/control.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/control.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2328,6 +2335,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2343,6 +2351,8 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2351,13 +2361,14 @@ $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $
$(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=generate_mock_code=true:$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif endif
ifeq ($(NO_PROTOC),true) ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2373,6 +2384,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/empty.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2388,6 +2400,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/messages.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2403,6 +2416,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2418,6 +2432,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2433,6 +2448,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/services.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/services.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2448,6 +2464,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/stats.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2463,6 +2480,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/test.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/test.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/test.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`

@ -2,7 +2,7 @@
load("//:bazel/generate_cc.bzl", "generate_cc") load("//:bazel/generate_cc.bzl", "generate_cc")
def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, use_external = False, **kwargs): def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mock, use_external = False, **kwargs):
"""Generates C++ grpc classes from a .proto file. """Generates C++ grpc classes from a .proto file.
Assumes the generated classes will be used in cc_api_version = 2. Assumes the generated classes will be used in cc_api_version = 2.
@ -17,6 +17,7 @@ def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, use_externa
"@com_google_protobuf//:well_known_protos" "@com_google_protobuf//:well_known_protos"
use_external: When True the grpc deps are prefixed with //external. This use_external: When True the grpc deps are prefixed with //external. This
allows grpc to be used as a dependency in other bazel projects. allows grpc to be used as a dependency in other bazel projects.
generate_mock: When true GMOCk code for client stub is generated.
**kwargs: rest of arguments, e.g., compatible_with and visibility. **kwargs: rest of arguments, e.g., compatible_with and visibility.
""" """
if len(srcs) > 1: if len(srcs) > 1:
@ -54,6 +55,7 @@ def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, use_externa
srcs = [proto_target], srcs = [proto_target],
plugin = plugin, plugin = plugin,
well_known_protos = well_known_protos, well_known_protos = well_known_protos,
generate_mock = generate_mock,
**kwargs **kwargs
) )

@ -12,6 +12,8 @@ def generate_cc_impl(ctx):
if ctx.executable.plugin: if ctx.executable.plugin:
outs += [proto.basename[:-len(".proto")] + ".grpc.pb.h" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".grpc.pb.h" for proto in protos]
outs += [proto.basename[:-len(".proto")] + ".grpc.pb.cc" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
if ctx.attr.generate_mock:
outs += [proto.basename[:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
else: else:
outs += [proto.basename[:-len(".proto")] + ".pb.h" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".pb.h" for proto in protos]
outs += [proto.basename[:-len(".proto")] + ".pb.cc" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".pb.cc" for proto in protos]
@ -23,7 +25,10 @@ def generate_cc_impl(ctx):
arguments = [] arguments = []
if ctx.executable.plugin: if ctx.executable.plugin:
arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path] arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
arguments += ["--PLUGIN_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] flags = list(ctx.attr.flags)
if ctx.attr.generate_mock:
flags.append("generate_mock_code=true")
arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
additional_input = [ctx.executable.plugin] additional_input = [ctx.executable.plugin]
else: else:
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
@ -71,6 +76,10 @@ generate_cc = rule(
"well_known_protos" : attr.label( "well_known_protos" : attr.label(
mandatory = False, mandatory = False,
), ),
"generate_mock" : attr.bool(
default = False,
mandatory = False,
),
"_protoc": attr.label( "_protoc": attr.label(
default = Label("//external:protocol_compiler"), default = Label("//external:protocol_compiler"),
executable = True, executable = True,

@ -49,14 +49,17 @@ def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [], external_deps
] ]
) )
def grpc_cc_libraries(name_list, additional_dep_list, srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language="C++"): def grpc_cc_libraries(name_list, additional_src_list = [], additional_dep_list = [], srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language="C++"):
for i in range(len(name_list)): names = len(name_list)
asl = additional_src_list + [[]]*(names - len(additional_src_list))
adl = additional_dep_list + [[]]*(names - len(additional_dep_list))
for i in range(names):
grpc_cc_library( grpc_cc_library(
name = name_list[i], name = name_list[i],
srcs = srcs, srcs = srcs + asl[i],
hdrs = hdrs, hdrs = hdrs,
public_hdrs = public_hdrs, public_hdrs = public_hdrs,
deps = deps + additional_dep_list[i], deps = deps + adl[i],
external_deps = external_deps, external_deps = external_deps,
standalone = standalone, standalone = standalone,
language = language language = language
@ -72,7 +75,7 @@ def grpc_proto_plugin(name, srcs = [], deps = []):
load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library") load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library")
def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None, def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None,
has_services = True, use_external = False): has_services = True, use_external = False, generate_mock = False):
cc_grpc_library( cc_grpc_library(
name = name, name = name,
srcs = srcs, srcs = srcs,
@ -80,5 +83,6 @@ def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None,
well_known_protos = well_known_protos, well_known_protos = well_known_protos,
proto_only = not has_services, proto_only = not has_services,
use_external = use_external, use_external = use_external,
generate_mock = generate_mock,
) )

@ -969,6 +969,7 @@ filegroups:
- name: grpc++_test - name: grpc++_test
language: c++ language: c++
public_headers: public_headers:
- include/grpc++/test/mock_stream.h
- include/grpc++/test/server_context_test_spouse.h - include/grpc++/test/server_context_test_spouse.h
deps: deps:
- grpc++ - grpc++
@ -3691,7 +3692,7 @@ targets:
- grpc - grpc
- gpr - gpr
args: args:
- --generated_file_path=gens/src/proto/grpc/testing/compiler_test.grpc.pb.h - --generated_file_path=gens/src/proto/grpc/testing/
- name: grpc_cli - name: grpc_cli
build: test build: test
run: false run: false
@ -3952,6 +3953,8 @@ targets:
gtest: true gtest: true
build: test build: test
language: c++ language: c++
headers:
- include/grpc++/test/mock_stream.h
src: src:
- test/cpp/end2end/mock_test.cc - test/cpp/end2end/mock_test.cc
deps: deps:

@ -13,12 +13,21 @@ The service config is a JSON string of the following form:
``` ```
{ {
// Load balancing policy name. // Load balancing policy name.
// Supported values are 'round_robin' and 'grpclb'. // Currently, the only selectable client-side policy provided with gRPC
// Optional; if unset, the default behavior is pick the first available // is 'round_robin', but third parties may add their own policies.
// backend. // This field is optional; if unset, the default behavior is to pick
// Note that if the resolver returns only balancer addresses and no // the first available backend.
// backend addresses, gRPC will always use the 'grpclb' policy, // If the policy name is set via the client API, that value overrides
// regardless of what this field is set to. // the value specified here.
//
// Note that if the resolver returns at least one balancer address (as
// opposed to backend addresses), gRPC will use grpclb (see
// https://github.com/grpc/grpc/blob/master/doc/load-balancing.md),
// regardless of what LB policy is requested either here or via the
// client API. However, if the resolver returns at least one backend
// address in addition to the balancer address(es), the client may fall
// back to the requested policy if it is unable to reach any of the
// grpclb load balancers.
'loadBalancingPolicy': string, 'loadBalancingPolicy': string,
// Per-method configuration. Optional. // Per-method configuration. Optional.

@ -89,7 +89,6 @@ EXPORTS
grpc_server_request_registered_call grpc_server_request_registered_call
grpc_server_create grpc_server_create
grpc_server_register_completion_queue grpc_server_register_completion_queue
grpc_server_register_non_listening_completion_queue
grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port
grpc_server_start grpc_server_start
grpc_server_shutdown_and_notify grpc_server_shutdown_and_notify

@ -52,7 +52,9 @@ template <class InputMessage, class OutputMessage>
Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, const InputMessage& request, ClientContext* context, const InputMessage& request,
OutputMessage* result) { OutputMessage* result) {
CompletionQueue cq(true); // Pluckable completion queue CompletionQueue cq(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}); // Pluckable completion queue
Call call(channel->CreateCall(method, context, &cq)); Call call(channel->CreateCall(method, context, &cq));
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>, CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,

@ -102,7 +102,9 @@ class CompletionQueue : private GrpcLibraryCodegen {
public: public:
/// Default constructor. Implicitly creates a \a grpc_completion_queue /// Default constructor. Implicitly creates a \a grpc_completion_queue
/// instance. /// instance.
CompletionQueue() : CompletionQueue(false) {} CompletionQueue()
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING}) {}
/// Wrap \a take, taking ownership of the instance. /// Wrap \a take, taking ownership of the instance.
/// ///
@ -182,6 +184,16 @@ class CompletionQueue : private GrpcLibraryCodegen {
}; };
void CompleteAvalanching(); void CompleteAvalanching();
protected:
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(const grpc_completion_queue_attributes& attributes) {
cq_ = g_core_codegen_interface->grpc_completion_queue_create(
g_core_codegen_interface->grpc_completion_queue_factory_lookup(
&attributes),
&attributes, NULL);
InitialAvalanching(); // reserve this for the future shutdown
}
private: private:
// Friend synchronous wrappers so that they can access Pluck(), which is // Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation. // a semi-private API geared towards the synchronous implementation.
@ -215,18 +227,6 @@ class CompletionQueue : private GrpcLibraryCodegen {
const InputMessage& request, const InputMessage& request,
OutputMessage* result); OutputMessage* result);
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(bool is_pluck) {
if (is_pluck) {
cq_ = g_core_codegen_interface->grpc_completion_queue_create_for_pluck(
nullptr);
} else {
cq_ = g_core_codegen_interface->grpc_completion_queue_create_for_next(
nullptr);
}
InitialAvalanching(); // reserve this for the future shutdown
}
NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
/// Wraps \a grpc_completion_queue_pluck. /// Wraps \a grpc_completion_queue_pluck.
@ -289,17 +289,19 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// by servers. Instantiated by \a ServerBuilder. /// by servers. Instantiated by \a ServerBuilder.
class ServerCompletionQueue : public CompletionQueue { class ServerCompletionQueue : public CompletionQueue {
public: public:
bool IsFrequentlyPolled() { return is_frequently_polled_; } bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
private: private:
bool is_frequently_polled_; grpc_cq_polling_type polling_type_;
friend class ServerBuilder; friend class ServerBuilder;
/// \param is_frequently_polled Informs the GRPC library about whether the /// \param is_frequently_polled Informs the GRPC library about whether the
/// server completion queue would be actively polled (by calling Next() or /// server completion queue would be actively polled (by calling Next() or
/// AsyncNext()). By default all server completion queues are assumed to be /// AsyncNext()). By default all server completion queues are assumed to be
/// frequently polled. /// frequently polled.
ServerCompletionQueue(bool is_frequently_polled = true) ServerCompletionQueue(grpc_cq_polling_type polling_type)
: is_frequently_polled_(is_frequently_polled) {} : CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type}),
polling_type_(polling_type) {}
}; };
} // namespace grpc } // namespace grpc

@ -44,8 +44,15 @@
namespace grpc { namespace grpc {
/// Implementation of the core codegen interface. /// Implementation of the core codegen interface.
class CoreCodegen : public CoreCodegenInterface { class CoreCodegen final : public CoreCodegenInterface {
private: private:
virtual const grpc_completion_queue_factory*
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) override;
virtual grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes,
void* reserved) override;
grpc_completion_queue* grpc_completion_queue_create_for_next( grpc_completion_queue* grpc_completion_queue_create_for_next(
void* reserved) override; void* reserved) override;
grpc_completion_queue* grpc_completion_queue_create_for_pluck( grpc_completion_queue* grpc_completion_queue_create_for_pluck(

@ -59,6 +59,12 @@ class CoreCodegenInterface {
virtual void assert_fail(const char* failed_assertion, const char* file, virtual void assert_fail(const char* failed_assertion, const char* file,
int line) = 0; int line) = 0;
virtual const grpc_completion_queue_factory*
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes, void* reserved) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create_for_next( virtual grpc_completion_queue* grpc_completion_queue_create_for_next(
void* reserved) = 0; void* reserved) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck( virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck(

@ -156,7 +156,9 @@ class ClientReader final : public ClientReaderInterface<R> {
ClientReader(ChannelInterface* channel, const RpcMethod& method, ClientReader(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, const W& request) ClientContext* context, const W& request)
: context_(context), : context_(context),
cq_(true), // Pluckable cq cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) { call_(channel->CreateCall(method, context, &cq_)) {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpClientSendClose> CallOpClientSendClose>
@ -230,7 +232,9 @@ class ClientWriter : public ClientWriterInterface<W> {
ClientWriter(ChannelInterface* channel, const RpcMethod& method, ClientWriter(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, R* response) ClientContext* context, R* response)
: context_(context), : context_(context),
cq_(true), // Pluckable cq cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) { call_(channel->CreateCall(method, context, &cq_)) {
finish_ops_.RecvMessage(response); finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage(); finish_ops_.AllowNoMessage();
@ -330,7 +334,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method, ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context) ClientContext* context)
: context_(context), : context_(context),
cq_(true), // Pluckable cq cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) { call_(channel->CreateCall(method, context, &cq_)) {
if (!context_->initial_metadata_corked_) { if (!context_->initial_metadata_corked_) {
CallOpSet<CallOpSendInitialMetadata> ops; CallOpSet<CallOpSendInitialMetadata> ops;

@ -0,0 +1,163 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPCXX_TEST_MOCK_STREAM_H
#define GRPCXX_TEST_MOCK_STREAM_H
#include <stdint.h>
#include <gmock/gmock.h>
#include <grpc++/impl/codegen/call.h>
#include <grpc++/support/async_stream.h>
#include <grpc++/support/async_unary_call.h>
#include <grpc++/support/sync_stream.h>
namespace grpc {
namespace testing {
template <class R>
class MockClientReader : public ClientReaderInterface<R> {
public:
MockClientReader() = default;
// ClientStreamingInterface
MOCK_METHOD0_T(Finish, Status());
// ReaderInterface
MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
MOCK_METHOD1_T(Read, bool(R*));
// ClientReaderInterface
MOCK_METHOD0_T(WaitForInitialMetadata, void());
};
template <class W>
class MockClientWriter : public ClientWriterInterface<W> {
public:
MockClientWriter() = default;
// ClientStreamingInterface
MOCK_METHOD0_T(Finish, Status());
// WriterInterface
MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
// ClientWriterInterface
MOCK_METHOD0_T(WritesDone, bool());
};
template <class W, class R>
class MockClientReaderWriter : public ClientReaderWriterInterface<W, R> {
public:
MockClientReaderWriter() = default;
// ClientStreamingInterface
MOCK_METHOD0_T(Finish, Status());
// ReaderInterface
MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
MOCK_METHOD1_T(Read, bool(R*));
// WriterInterface
MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
// ClientReaderWriterInterface
MOCK_METHOD0_T(WaitForInitialMetadata, void());
MOCK_METHOD0_T(WritesDone, bool());
};
// TODO: We do not support mocking an async RPC for now.
template <class R>
class MockClientAsyncResponseReader
: public ClientAsyncResponseReaderInterface<R> {
public:
MockClientAsyncResponseReader() = default;
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
};
template <class R>
class MockClientAsyncReader : public ClientAsyncReaderInterface<R> {
public:
MockClientAsyncReader() = default;
// ClientAsyncStreamingInterface
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD2_T(Finish, void(Status*, void*));
// AsyncReaderInterface
MOCK_METHOD2_T(Read, void(R*, void*));
};
template <class W>
class MockClientAsyncWriter : public ClientAsyncWriterInterface<W> {
public:
MockClientAsyncWriter() = default;
// ClientAsyncStreamingInterface
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD2_T(Finish, void(Status*, void*));
// AsyncWriterInterface
MOCK_METHOD2_T(Write, void(const W&, void*));
// ClientAsyncWriterInterface
MOCK_METHOD1_T(WritesDone, void(void*));
};
template <class W, class R>
class MockClientAsyncReaderWriter
: public ClientAsyncReaderWriterInterface<W, R> {
public:
MockClientAsyncReaderWriter() = default;
// ClientAsyncStreamingInterface
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD2_T(Finish, void(Status*, void*));
// AsyncWriterInterface
MOCK_METHOD2_T(Write, void(const W&, void*));
// AsyncReaderInterface
MOCK_METHOD2_T(Read, void(R*, void*));
// ClientAsyncReaderWriterInterface
MOCK_METHOD1_T(WritesDone, void(void*));
};
} // namespace testing
} // namespace grpc
#endif // GRPCXX_TEST_MOCK_STREAM_H

@ -93,55 +93,6 @@ GRPCAPI const char *grpc_version_string(void);
/** Return a string specifying what the 'g' in gRPC stands for */ /** Return a string specifying what the 'g' in gRPC stands for */
GRPCAPI const char *grpc_g_stands_for(void); GRPCAPI const char *grpc_g_stands_for(void);
/** Specifies the type of APIs to use to pop events from the completion queue */
typedef enum {
/** Events are popped out by calling grpc_completion_queue_next() API ONLY */
GRPC_CQ_NEXT = 1,
/** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
GRPC_CQ_PLUCK
} grpc_cq_completion_type;
/** Completion queues internally MAY maintain a set of file descriptors in a
structure called 'pollset'. This enum specifies if a completion queue has an
associated pollset and any restrictions on the type of file descriptors that
can be present in the pollset.
I/O progress can only be made when grpc_completion_queue_next() or
grpc_completion_queue_pluck() are called on the completion queue (unless the
grpc_cq_polling_type is GRPC_CQ_NON_POLLING) and hence it is very important
to actively call these APIs */
typedef enum {
/** The completion queue will have an associated pollset and there is no
restriction on the type of file descriptors the pollset may contain */
GRPC_CQ_DEFAULT_POLLING,
/** Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
not contain any 'listening file descriptors' (i.e file descriptors used to
listen to incoming channels) */
GRPC_CQ_NON_LISTENING,
/** The completion queue will not have an associated pollset. Note that
grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still
be called to pop events from the completion queue; it is not required to
call them actively to make I/O progress */
GRPC_CQ_NON_POLLING
} grpc_cq_polling_type;
#define GRPC_CQ_CURRENT_VERSION 1
typedef struct grpc_completion_queue_attributes {
/* The version number of this structure. More fields might be added to this
structure in future. */
int version; /* Set to GRPC_CQ_CURRENT_VERSION */
grpc_cq_completion_type cq_completion_type;
grpc_cq_polling_type cq_polling_type;
} grpc_completion_queue_attributes;
/** The completion queue factory structure is opaque to the callers of grpc */
typedef struct grpc_completion_queue_factory grpc_completion_queue_factory;
/** Returns the completion queue factory based on the attributes. MAY return a /** Returns the completion queue factory based on the attributes. MAY return a
NULL if no factory can be found */ NULL if no factory can be found */
GRPCAPI const grpc_completion_queue_factory * GRPCAPI const grpc_completion_queue_factory *
@ -427,15 +378,6 @@ GRPCAPI void grpc_server_register_completion_queue(grpc_server *server,
grpc_completion_queue *cq, grpc_completion_queue *cq,
void *reserved); void *reserved);
/** Register a non-listening completion queue with the server. This API is
similar to grpc_server_register_completion_queue except that the server will
not use this completion_queue to listen to any incoming channels.
Registering a non-listening completion queue will have negative performance
impact and hence this API is not recommended for production use cases. */
GRPCAPI void grpc_server_register_non_listening_completion_queue(
grpc_server *server, grpc_completion_queue *q, void *reserved);
/** Add a HTTP2 over plaintext over tcp listener. /** Add a HTTP2 over plaintext over tcp listener.
Returns bound port number on success, 0 on failure. Returns bound port number on success, 0 on failure.
REQUIRES: server not started */ REQUIRES: server not started */

@ -556,6 +556,55 @@ typedef struct {
typedef struct grpc_resource_quota grpc_resource_quota; typedef struct grpc_resource_quota grpc_resource_quota;
/** Completion queues internally MAY maintain a set of file descriptors in a
structure called 'pollset'. This enum specifies if a completion queue has an
associated pollset and any restrictions on the type of file descriptors that
can be present in the pollset.
I/O progress can only be made when grpc_completion_queue_next() or
grpc_completion_queue_pluck() are called on the completion queue (unless the
grpc_cq_polling_type is GRPC_CQ_NON_POLLING) and hence it is very important
to actively call these APIs */
typedef enum {
/** The completion queue will have an associated pollset and there is no
restriction on the type of file descriptors the pollset may contain */
GRPC_CQ_DEFAULT_POLLING,
/** Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
not contain any 'listening file descriptors' (i.e file descriptors used to
listen to incoming channels) */
GRPC_CQ_NON_LISTENING,
/** The completion queue will not have an associated pollset. Note that
grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still
be called to pop events from the completion queue; it is not required to
call them actively to make I/O progress */
GRPC_CQ_NON_POLLING
} grpc_cq_polling_type;
/** Specifies the type of APIs to use to pop events from the completion queue */
typedef enum {
/** Events are popped out by calling grpc_completion_queue_next() API ONLY */
GRPC_CQ_NEXT = 1,
/** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
GRPC_CQ_PLUCK
} grpc_cq_completion_type;
#define GRPC_CQ_CURRENT_VERSION 1
typedef struct grpc_completion_queue_attributes {
/* The version number of this structure. More fields might be added to this
structure in future. */
int version; /* Set to GRPC_CQ_CURRENT_VERSION */
grpc_cq_completion_type cq_completion_type;
grpc_cq_polling_type cq_polling_type;
} grpc_completion_queue_attributes;
/** The completion queue factory structure is opaque to the callers of grpc */
typedef struct grpc_completion_queue_factory grpc_completion_queue_factory;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -1408,4 +1408,180 @@ grpc::string GetSourceEpilogue(grpc_generator::File *file,
return temp; return temp;
} }
// TODO(mmukhi): Make sure we need parameters or not.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters & /*params*/) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
vars["filename"] = file->filename();
vars["filename_base"] = file->filename_without_ext();
vars["message_header_ext"] = message_header_ext();
vars["service_header_ext"] = service_header_ext();
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
printer->Print(vars,
"// If you make any local change, they will be lost.\n");
printer->Print(vars, "// source: $filename$\n\n");
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
printer->Print(vars, file->additional_headers().c_str());
printer->Print(vars, "\n");
}
return output;
}
// TODO(mmukhi): Add client-stream and completion-queue headers.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
static const char *headers_strs[] = {
"grpc++/impl/codegen/async_stream.h",
"grpc++/impl/codegen/sync_stream.h", "gmock/gmock.h",
};
std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
PrintIncludes(printer.get(), headers, params);
if (!file->package().empty()) {
std::vector<grpc::string> parts = file->package_parts();
for (auto part = parts.begin(); part != parts.end(); part++) {
vars["part"] = *part;
printer->Print(vars, "namespace $part$ {\n");
}
}
printer->Print(vars, "\n");
}
return output;
}
void PrintMockClientMethods(grpc_generator::Printer *printer,
const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
if (method->NoStreaming()) {
printer->Print(
*vars,
"MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response));\n");
printer->Print(*vars,
"MOCK_METHOD3(Async$Method$Raw, "
"::grpc::ClientAsyncResponseReaderInterface< $Response$>*"
"(::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq));\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
"MOCK_METHOD2($Method$Raw, "
"::grpc::ClientWriterInterface< $Request$>*"
"(::grpc::ClientContext* context, $Response$* response));\n");
printer->Print(*vars,
"MOCK_METHOD4(Async$Method$Raw, "
"::grpc::ClientAsyncWriterInterface< $Request$>*"
"(::grpc::ClientContext* context, $Response$* response, "
"::grpc::CompletionQueue* cq, void* tag));\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"MOCK_METHOD2($Method$Raw, "
"::grpc::ClientReaderInterface< $Response$>*"
"(::grpc::ClientContext* context, const $Request$& request));\n");
printer->Print(*vars,
"MOCK_METHOD4(Async$Method$Raw, "
"::grpc::ClientAsyncReaderInterface< $Response$>*"
"(::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag));\n");
} else if (method->BidiStreaming()) {
printer->Print(
*vars,
"MOCK_METHOD1($Method$Raw, "
"::grpc::ClientReaderWriterInterface< $Request$, $Response$>*"
"(::grpc::ClientContext* context));\n");
printer->Print(
*vars,
"MOCK_METHOD3(Async$Method$Raw, "
"::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*"
"(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, "
"void* tag));\n");
}
}
void PrintMockService(grpc_generator::Printer *printer,
const grpc_generator::Service *service,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars,
"class Mock$Service$Stub : public $Service$::StubInterface {\n"
" public:\n");
printer->Indent();
for (int i = 0; i < service->method_count(); ++i) {
PrintMockClientMethods(printer, service->method(i).get(), vars);
}
printer->Outdent();
printer->Print("};\n");
}
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
// Package string is empty or ends with a dot. It is used to fully qualify
// method names.
vars["Package"] = file->package();
if (!file->package().empty()) {
vars["Package"].append(".");
}
if (!params.services_namespace.empty()) {
vars["services_namespace"] = params.services_namespace;
printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
}
for (int i = 0; i < file->service_count(); i++) {
PrintMockService(printer.get(), file->service(i).get(), &vars);
printer->Print("\n");
}
if (!params.services_namespace.empty()) {
printer->Print(vars, "} // namespace $services_namespace$\n\n");
}
}
return output;
}
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters & /*params*/) {
grpc::string temp;
if (!file->package().empty()) {
std::vector<grpc::string> parts = file->package_parts();
for (auto part = parts.begin(); part != parts.end(); part++) {
temp.append("} // namespace ");
temp.append(*part);
temp.append("\n");
}
temp.append("\n");
}
return temp;
}
} // namespace grpc_cpp_generator } // namespace grpc_cpp_generator

@ -65,6 +65,8 @@ struct Parameters {
bool use_system_headers; bool use_system_headers;
// Prefix to any grpc include // Prefix to any grpc include
grpc::string grpc_search_path; grpc::string grpc_search_path;
// Generate GMOCK code to facilitate unit testing.
bool generate_mock_code;
}; };
// Return the prologue of the generated header file. // Return the prologue of the generated header file.
@ -99,6 +101,38 @@ grpc::string GetSourceServices(grpc_generator::File *file,
grpc::string GetSourceEpilogue(grpc_generator::File *file, grpc::string GetSourceEpilogue(grpc_generator::File *file,
const Parameters &params); const Parameters &params);
// Return the prologue of the generated mock file.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated mock file.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated mock file.
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of generated mock file.
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters &params);
// Return the prologue of the generated mock file.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated mock file.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated mock file.
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of generated mock file.
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters &params);
} // namespace grpc_cpp_generator } // namespace grpc_cpp_generator
#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H #endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H

@ -62,6 +62,7 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
grpc_cpp_generator::Parameters generator_parameters; grpc_cpp_generator::Parameters generator_parameters;
generator_parameters.use_system_headers = true; generator_parameters.use_system_headers = true;
generator_parameters.generate_mock_code = false;
ProtoBufFile pbfile(file); ProtoBufFile pbfile(file);
@ -85,6 +86,13 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
} }
} else if (param[0] == "grpc_search_path") { } else if (param[0] == "grpc_search_path") {
generator_parameters.grpc_search_path = param[1]; generator_parameters.grpc_search_path = param[1];
} else if (param[0] == "generate_mock_code") {
if (param[1] == "true") {
generator_parameters.generate_mock_code = true;
} else if (param[1] != "false") {
*error = grpc::string("Invalid parameter: ") + *parameter_string;
return false;
}
} else { } else {
*error = grpc::string("Unknown parameter: ") + *parameter_string; *error = grpc::string("Unknown parameter: ") + *parameter_string;
return false; return false;
@ -114,6 +122,19 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get()); grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get());
source_coded_out.WriteRaw(source_code.data(), source_code.size()); source_coded_out.WriteRaw(source_code.data(), source_code.size());
if (!generator_parameters.generate_mock_code) {
return true;
}
grpc::string mock_code =
grpc_cpp_generator::GetMockPrologue(&pbfile, generator_parameters) +
grpc_cpp_generator::GetMockIncludes(&pbfile, generator_parameters) +
grpc_cpp_generator::GetMockServices(&pbfile, generator_parameters) +
grpc_cpp_generator::GetMockEpilogue(&pbfile, generator_parameters);
std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> mock_output(
context->Open(file_name + "_mock.grpc.pb.h"));
grpc::protobuf::io::CodedOutputStream mock_coded_out(mock_output.get());
mock_coded_out.WriteRaw(mock_code.data(), mock_code.size());
return true; return true;
} }

@ -400,26 +400,24 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
lb_policy_name = channel_arg->value.string; lb_policy_name = channel_arg->value.string;
} }
// Special case: If all of the addresses are balancer addresses, // Special case: If at least one balancer address is present, we use
// assume that we should use the grpclb policy, regardless of what the // the grpclb policy, regardless of what the resolver actually specified.
// resolver actually specified.
channel_arg = channel_arg =
grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) { if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) {
grpc_lb_addresses *addresses = channel_arg->value.pointer.p; grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
bool found_backend_address = false; bool found_balancer_address = false;
for (size_t i = 0; i < addresses->num_addresses; ++i) { for (size_t i = 0; i < addresses->num_addresses; ++i) {
if (!addresses->addresses[i].is_balancer) { if (addresses->addresses[i].is_balancer) {
found_backend_address = true; found_balancer_address = true;
break; break;
} }
} }
if (!found_backend_address) { if (found_balancer_address) {
if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) { if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"resolver requested LB policy %s but provided only balancer " "resolver requested LB policy %s but provided at least one "
"addresses, no backend addresses -- forcing use of grpclb LB " "balancer address -- forcing use of grpclb LB policy",
"policy",
lb_policy_name); lb_policy_name);
} }
lb_policy_name = "grpclb"; lb_policy_name = "grpclb";

@ -831,10 +831,10 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
/* Count the number of gRPC-LB addresses. There must be at least one. /* Count the number of gRPC-LB addresses. There must be at least one.
* TODO(roth): For now, we ignore non-balancer addresses, but in the * TODO(roth): For now, we ignore non-balancer addresses, but in the
* future, we may change the behavior such that we fall back to using * future, we may change the behavior such that we fall back to using
* the non-balancer addresses if we cannot reach any balancers. At that * the non-balancer addresses if we cannot reach any balancers. In the
* time, this should be changed to allow a list with no balancer addresses, * fallback case, we should use the LB policy indicated by
* since the resolver might fail to return a balancer address even when * GRPC_ARG_LB_POLICY_NAME (although if that specifies grpclb or is
* this is the right LB policy to use. */ * unset, we should default to pick_first). */
const grpc_arg *arg = const grpc_arg *arg =
grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
if (arg == NULL || arg->type != GRPC_ARG_POINTER) { if (arg == NULL || arg->type != GRPC_ARG_POINTER) {

@ -80,7 +80,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_lock(&connection_state->server_state->mu); gpr_mu_lock(&connection_state->server_state->mu);
if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) { if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
const char *error_str = grpc_error_string(error); const char *error_str = grpc_error_string(error);
gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
if (error == GRPC_ERROR_NONE && args->endpoint != NULL) { if (error == GRPC_ERROR_NONE && args->endpoint != NULL) {
// We were shut down after handshaking completed successfully, so // We were shut down after handshaking completed successfully, so

@ -92,6 +92,11 @@ struct grpc_udp_listener {
struct grpc_udp_listener *next; struct grpc_udp_listener *next;
}; };
struct shutdown_fd_args {
grpc_fd *fd;
gpr_mu *server_mu;
};
/* the overall server */ /* the overall server */
struct grpc_udp_server { struct grpc_udp_server {
gpr_mu mu; gpr_mu mu;
@ -151,8 +156,13 @@ grpc_udp_server *grpc_udp_server_create(const grpc_channel_args *args) {
return s; return s;
} }
static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *fd, grpc_error *error) { static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *args,
grpc_fd_shutdown(exec_ctx, (grpc_fd *)fd, GRPC_ERROR_REF(error)); grpc_error *error) {
struct shutdown_fd_args *shutdown_args = (struct shutdown_fd_args *)args;
gpr_mu_lock(shutdown_args->server_mu);
grpc_fd_shutdown(exec_ctx, shutdown_args->fd, GRPC_ERROR_REF(error));
gpr_mu_unlock(shutdown_args->server_mu);
gpr_free(shutdown_args);
} }
static void dummy_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { static void dummy_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
@ -242,7 +252,10 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
if (s->active_ports) { if (s->active_ports) {
for (sp = s->head; sp; sp = sp->next) { for (sp = s->head; sp; sp = sp->next) {
GPR_ASSERT(sp->orphan_cb); GPR_ASSERT(sp->orphan_cb);
grpc_closure_init(&sp->orphan_fd_closure, shutdown_fd, sp->emfd, struct shutdown_fd_args *args = gpr_malloc(sizeof(*args));
args->fd = sp->emfd;
args->server_mu = &s->mu;
grpc_closure_init(&sp->orphan_fd_closure, shutdown_fd, args,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure, sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure,
sp->server->user_data); sp->server->user_data);

@ -61,6 +61,146 @@ typedef struct {
void *tag; void *tag;
} plucker; } plucker;
typedef struct {
bool can_get_pollset;
bool can_listen;
size_t (*size)(void);
void (*init)(grpc_pollset *pollset, gpr_mu **mu);
grpc_error *(*kick)(grpc_pollset *pollset,
grpc_pollset_worker *specific_worker);
grpc_error *(*work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker, gpr_timespec now,
gpr_timespec deadline);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_closure *closure);
void (*destroy)(grpc_pollset *pollset);
} cq_poller_vtable;
typedef struct non_polling_worker {
gpr_cv cv;
bool kicked;
struct non_polling_worker *next;
struct non_polling_worker *prev;
} non_polling_worker;
typedef struct {
gpr_mu mu;
non_polling_worker *root;
grpc_closure *shutdown;
} non_polling_poller;
static size_t non_polling_poller_size(void) {
return sizeof(non_polling_poller);
}
static void non_polling_poller_init(grpc_pollset *pollset, gpr_mu **mu) {
non_polling_poller *npp = (non_polling_poller *)pollset;
gpr_mu_init(&npp->mu);
*mu = &npp->mu;
}
static void non_polling_poller_destroy(grpc_pollset *pollset) {
non_polling_poller *npp = (non_polling_poller *)pollset;
gpr_mu_destroy(&npp->mu);
}
static grpc_error *non_polling_poller_work(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
grpc_pollset_worker **worker,
gpr_timespec now,
gpr_timespec deadline) {
non_polling_poller *npp = (non_polling_poller *)pollset;
if (npp->shutdown) return GRPC_ERROR_NONE;
non_polling_worker w;
gpr_cv_init(&w.cv);
if (worker != NULL) *worker = (grpc_pollset_worker *)&w;
if (npp->root == NULL) {
npp->root = w.next = w.prev = &w;
} else {
w.next = npp->root;
w.prev = w.next->prev;
w.next->prev = w.prev->next = &w;
}
w.kicked = false;
while (!npp->shutdown && !w.kicked && !gpr_cv_wait(&w.cv, &npp->mu, deadline))
;
if (&w == npp->root) {
npp->root = w.next;
if (&w == npp->root) {
if (npp->shutdown) {
grpc_closure_sched(exec_ctx, npp->shutdown, GRPC_ERROR_NONE);
}
npp->root = NULL;
}
}
w.next->prev = w.prev;
w.prev->next = w.next;
gpr_cv_destroy(&w.cv);
if (worker != NULL) *worker = NULL;
return GRPC_ERROR_NONE;
}
static grpc_error *non_polling_poller_kick(
grpc_pollset *pollset, grpc_pollset_worker *specific_worker) {
non_polling_poller *p = (non_polling_poller *)pollset;
if (specific_worker == NULL) specific_worker = (grpc_pollset_worker *)p->root;
if (specific_worker != NULL) {
non_polling_worker *w = (non_polling_worker *)specific_worker;
if (!w->kicked) {
w->kicked = true;
gpr_cv_signal(&w->cv);
}
}
return GRPC_ERROR_NONE;
}
static void non_polling_poller_shutdown(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
grpc_closure *closure) {
non_polling_poller *p = (non_polling_poller *)pollset;
GPR_ASSERT(closure != NULL);
p->shutdown = closure;
if (p->root == NULL) {
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
} else {
non_polling_worker *w = p->root;
do {
gpr_cv_signal(&w->cv);
w = w->next;
} while (w != p->root);
}
}
static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
/* GRPC_CQ_DEFAULT_POLLING */
{.can_get_pollset = true,
.can_listen = true,
.size = grpc_pollset_size,
.init = grpc_pollset_init,
.kick = grpc_pollset_kick,
.work = grpc_pollset_work,
.shutdown = grpc_pollset_shutdown,
.destroy = grpc_pollset_destroy},
/* GRPC_CQ_NON_LISTENING */
{.can_get_pollset = true,
.can_listen = false,
.size = grpc_pollset_size,
.init = grpc_pollset_init,
.kick = grpc_pollset_kick,
.work = grpc_pollset_work,
.shutdown = grpc_pollset_shutdown,
.destroy = grpc_pollset_destroy},
/* GRPC_CQ_NON_POLLING */
{.can_get_pollset = false,
.can_listen = false,
.size = non_polling_poller_size,
.init = non_polling_poller_init,
.kick = non_polling_poller_kick,
.work = non_polling_poller_work,
.shutdown = non_polling_poller_shutdown,
.destroy = non_polling_poller_destroy},
};
/* Queue that holds the cq_completion_events. This internally uses gpr_mpscq /* Queue that holds the cq_completion_events. This internally uses gpr_mpscq
* queue (a lockfree multiproducer single consumer queue). However this queue * queue (a lockfree multiproducer single consumer queue). However this queue
* supports multiple consumers too. As such, it uses the queue_mu to serialize * supports multiple consumers too. As such, it uses the queue_mu to serialize
@ -86,10 +226,10 @@ struct grpc_completion_queue {
gpr_mu *mu; gpr_mu *mu;
grpc_cq_completion_type completion_type; grpc_cq_completion_type completion_type;
grpc_cq_polling_type polling_type;
/** Completed events (Only relevant if the completion_type is NOT const cq_poller_vtable *poller_vtable;
* GRPC_CQ_NEXT) */
/** completed events */
grpc_cq_completion completed_head; grpc_cq_completion completed_head;
grpc_cq_completion *completed_tail; grpc_cq_completion *completed_tail;
@ -188,15 +328,18 @@ grpc_completion_queue *grpc_completion_queue_create_internal(
"polling_type=%d)", "polling_type=%d)",
2, (completion_type, polling_type)); 2, (completion_type, polling_type));
cc = gpr_zalloc(sizeof(grpc_completion_queue) + grpc_pollset_size()); const cq_poller_vtable *poller_vtable =
grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu); &g_poller_vtable_by_poller_type[polling_type];
cc = gpr_zalloc(sizeof(grpc_completion_queue) + poller_vtable->size());
poller_vtable->init(POLLSET_FROM_CQ(cc), &cc->mu);
#ifndef NDEBUG #ifndef NDEBUG
cc->outstanding_tags = NULL; cc->outstanding_tags = NULL;
cc->outstanding_tag_capacity = 0; cc->outstanding_tag_capacity = 0;
#endif #endif
cc->completion_type = completion_type; cc->completion_type = completion_type;
cc->polling_type = polling_type; cc->poller_vtable = poller_vtable;
/* Initial ref is dropped by grpc_completion_queue_shutdown */ /* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_ref_init(&cc->pending_events, 1); gpr_ref_init(&cc->pending_events, 1);
@ -257,7 +400,7 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) {
#endif #endif
if (gpr_unref(&cc->owning_refs)) { if (gpr_unref(&cc->owning_refs)) {
GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head); GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head);
grpc_pollset_destroy(POLLSET_FROM_CQ(cc)); cc->poller_vtable->destroy(POLLSET_FROM_CQ(cc));
cq_event_queue_destroy(&cc->queue); cq_event_queue_destroy(&cc->queue);
#ifndef NDEBUG #ifndef NDEBUG
gpr_free(cc->outstanding_tags); gpr_free(cc->outstanding_tags);
@ -331,7 +474,8 @@ void grpc_cq_end_op_for_next(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
int shutdown = gpr_unref(&cc->pending_events); int shutdown = gpr_unref(&cc->pending_events);
if (!shutdown) { if (!shutdown) {
gpr_mu_lock(cc->mu); gpr_mu_lock(cc->mu);
grpc_error *kick_error = grpc_pollset_kick(POLLSET_FROM_CQ(cc), NULL);
grpc_error *kick_error = cc->poller_vtable->kick(POLLSET_FROM_CQ(cc), NULL);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
if (kick_error != GRPC_ERROR_NONE) { if (kick_error != GRPC_ERROR_NONE) {
@ -347,7 +491,7 @@ void grpc_cq_end_op_for_next(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
gpr_atm_no_barrier_store(&cc->shutdown, 1); gpr_atm_no_barrier_store(&cc->shutdown, 1);
gpr_mu_lock(cc->mu); gpr_mu_lock(cc->mu);
grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), cc->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
&cc->pollset_shutdown_done); &cc->pollset_shutdown_done);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
} }
@ -387,7 +531,8 @@ void grpc_cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
} }
grpc_error *kick_error = grpc_error *kick_error =
grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker); cc->poller_vtable->kick(POLLSET_FROM_CQ(cc), pluck_worker);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
if (kick_error != GRPC_ERROR_NONE) { if (kick_error != GRPC_ERROR_NONE) {
@ -400,7 +545,7 @@ void grpc_cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(!gpr_atm_no_barrier_load(&cc->shutdown)); GPR_ASSERT(!gpr_atm_no_barrier_load(&cc->shutdown));
GPR_ASSERT(cc->shutdown_called); GPR_ASSERT(cc->shutdown_called);
gpr_atm_no_barrier_store(&cc->shutdown, 1); gpr_atm_no_barrier_store(&cc->shutdown, 1);
grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), cc->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
&cc->pollset_shutdown_done); &cc->pollset_shutdown_done);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
} }
@ -477,7 +622,6 @@ static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) {
return true; return true;
} }
} }
return !a->first_loop && return !a->first_loop &&
gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
} }
@ -534,6 +678,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
GRPC_CQ_INTERNAL_REF(cc, "next"); GRPC_CQ_INTERNAL_REF(cc, "next");
cq_is_finished_arg is_finished_arg = { cq_is_finished_arg is_finished_arg = {
.last_seen_things_queued_ever = .last_seen_things_queued_ever =
gpr_atm_no_barrier_load(&cc->things_queued_ever), gpr_atm_no_barrier_load(&cc->things_queued_ever),
@ -601,9 +746,9 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
dump_pending_tags(cc); dump_pending_tags(cc);
break; break;
} }
/* Check alarms - these are a global resource so we just ping
/* Check alarms - these are a global resource so we just ping each time each time through on every pollset.
through on every pollset. May update deadline to ensure timely wakeups.*/ May update deadline to ensure timely wakeups.
if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
GPR_TIMER_MARK("alarm_triggered", 0); GPR_TIMER_MARK("alarm_triggered", 0);
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
@ -612,8 +757,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
/* The main polling work happens in grpc_pollset_work */ /* The main polling work happens in grpc_pollset_work */
gpr_mu_lock(cc->mu); gpr_mu_lock(cc->mu);
grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), NULL, grpc_error *err = cc->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cc),
now, iteration_deadline); NULL, now, iteration_deadline);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
@ -805,8 +950,8 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(cc->mu); gpr_mu_lock(cc->mu);
} else { } else {
grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), grpc_error *err = cc->poller_vtable->work(
&worker, now, iteration_deadline); &exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, iteration_deadline);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
del_plucker(cc, tag, &worker); del_plucker(cc, tag, &worker);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
@ -850,7 +995,7 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
if (gpr_unref(&cc->pending_events)) { if (gpr_unref(&cc->pending_events)) {
GPR_ASSERT(!cc->shutdown); GPR_ASSERT(!cc->shutdown);
cc->shutdown = 1; cc->shutdown = 1;
grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), cc->poller_vtable->shutdown(&exec_ctx, POLLSET_FROM_CQ(cc),
&cc->pollset_shutdown_done); &cc->pollset_shutdown_done);
} }
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
@ -872,7 +1017,7 @@ void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
} }
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
return POLLSET_FROM_CQ(cc); return cc->poller_vtable->can_get_pollset ? POLLSET_FROM_CQ(cc) : NULL;
} }
grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps) { grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps) {
@ -893,4 +1038,10 @@ bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc) {
void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; }
int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; } bool grpc_cq_is_server_cq(grpc_completion_queue *cc) {
return cc->is_server_cq;
}
bool grpc_cq_can_listen(grpc_completion_queue *cc) {
return cc->poller_vtable->can_listen;
}

@ -96,13 +96,11 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps); grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps);
void grpc_cq_mark_non_listening_server_cq(grpc_completion_queue *cc);
bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc);
void grpc_cq_mark_server_cq(grpc_completion_queue *cc); void grpc_cq_mark_server_cq(grpc_completion_queue *cc);
int grpc_cq_is_server_cq(grpc_completion_queue *cc); bool grpc_cq_is_server_cq(grpc_completion_queue *cc);
bool grpc_cq_can_listen(grpc_completion_queue *cc);
grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc); grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc);
grpc_cq_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc);
grpc_completion_queue *grpc_completion_queue_create_internal( grpc_completion_queue *grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type); grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type);

@ -981,7 +981,7 @@ const grpc_channel_filter grpc_server_top_filter = {
static void register_completion_queue(grpc_server *server, static void register_completion_queue(grpc_server *server,
grpc_completion_queue *cq, grpc_completion_queue *cq,
bool is_non_listening, void *reserved) { void *reserved) {
size_t i, n; size_t i, n;
GPR_ASSERT(!reserved); GPR_ASSERT(!reserved);
for (i = 0; i < server->cq_count; i++) { for (i = 0; i < server->cq_count; i++) {
@ -990,10 +990,6 @@ static void register_completion_queue(grpc_server *server,
grpc_cq_mark_server_cq(cq); grpc_cq_mark_server_cq(cq);
if (is_non_listening) {
grpc_cq_mark_non_listening_server_cq(cq);
}
GRPC_CQ_INTERNAL_REF(cq, "server"); GRPC_CQ_INTERNAL_REF(cq, "server");
n = server->cq_count++; n = server->cq_count++;
server->cqs = gpr_realloc(server->cqs, server->cqs = gpr_realloc(server->cqs,
@ -1016,16 +1012,7 @@ void grpc_server_register_completion_queue(grpc_server *server,
calls grpc_completion_queue_pluck() on server completion queues */ calls grpc_completion_queue_pluck() on server completion queues */
} }
register_completion_queue(server, cq, false, reserved); register_completion_queue(server, cq, reserved);
}
void grpc_server_register_non_listening_completion_queue(
grpc_server *server, grpc_completion_queue *cq, void *reserved) {
GRPC_API_TRACE(
"grpc_server_register_non_listening_completion_queue(server=%p, cq=%p, "
"reserved=%p)",
3, (server, cq, reserved));
register_completion_queue(server, cq, true, reserved);
} }
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
@ -1121,7 +1108,7 @@ void grpc_server_start(grpc_server *server) {
server->requested_calls_per_cq = server->requested_calls_per_cq =
gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count); gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count);
for (i = 0; i < server->cq_count; i++) { for (i = 0; i < server->cq_count; i++) {
if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) { if (grpc_cq_can_listen(server->cqs[i])) {
server->pollsets[server->pollset_count++] = server->pollsets[server->pollset_count++] =
grpc_cq_pollset(server->cqs[i]); grpc_cq_pollset(server->cqs[i]);
} }

@ -54,6 +54,18 @@ struct grpc_byte_buffer;
namespace grpc { namespace grpc {
const grpc_completion_queue_factory*
CoreCodegen::grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) {
return ::grpc_completion_queue_factory_lookup(attributes);
}
grpc_completion_queue* CoreCodegen::grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes, void* reserved) {
return ::grpc_completion_queue_create(factory, attributes, reserved);
}
grpc_completion_queue* CoreCodegen::grpc_completion_queue_create_for_next( grpc_completion_queue* CoreCodegen::grpc_completion_queue_create_for_next(
void* reserved) { void* reserved) {
return ::grpc_completion_queue_create_for_next(reserved); return ::grpc_completion_queue_create_for_next(reserved);

@ -83,7 +83,8 @@ ServerBuilder::~ServerBuilder() {
std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue( std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
bool is_frequently_polled) { bool is_frequently_polled) {
ServerCompletionQueue* cq = new ServerCompletionQueue(is_frequently_polled); ServerCompletionQueue* cq = new ServerCompletionQueue(
is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING);
cqs_.push_back(cq); cqs_.push_back(cq);
return std::unique_ptr<ServerCompletionQueue>(cq); return std::unique_ptr<ServerCompletionQueue>(cq);
} }
@ -242,6 +243,16 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
sync_server_cqs(std::make_shared< sync_server_cqs(std::make_shared<
std::vector<std::unique_ptr<ServerCompletionQueue>>>()); std::vector<std::unique_ptr<ServerCompletionQueue>>>());
int num_frequently_polled_cqs = 0;
for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
if ((*it)->IsFrequentlyPolled()) {
num_frequently_polled_cqs++;
}
}
const bool is_hybrid_server =
has_sync_methods && num_frequently_polled_cqs > 0;
if (has_sync_methods) { if (has_sync_methods) {
// This is a Sync server // This is a Sync server
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
@ -251,9 +262,12 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
sync_server_settings_.max_pollers, sync_server_settings_.max_pollers,
sync_server_settings_.cq_timeout_msec); sync_server_settings_.cq_timeout_msec);
grpc_cq_polling_type polling_type =
is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING;
// Create completion queues to listen to incoming rpc requests // Create completion queues to listen to incoming rpc requests
for (int i = 0; i < sync_server_settings_.num_cqs; i++) { for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
sync_server_cqs->emplace_back(new ServerCompletionQueue()); sync_server_cqs->emplace_back(new ServerCompletionQueue(polling_type));
} }
} }
@ -269,12 +283,10 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
// server // server
// 2. cqs_: Completion queues added via AddCompletionQueue() call // 2. cqs_: Completion queues added via AddCompletionQueue() call
// All sync cqs (if any) are frequently polled by ThreadManager
int num_frequently_polled_cqs = sync_server_cqs->size();
for (auto it = sync_server_cqs->begin(); it != sync_server_cqs->end(); ++it) { for (auto it = sync_server_cqs->begin(); it != sync_server_cqs->end(); ++it) {
grpc_server_register_completion_queue(server->server_, (*it)->cq(), grpc_server_register_completion_queue(server->server_, (*it)->cq(),
nullptr); nullptr);
num_frequently_polled_cqs++;
} }
// cqs_ contains the completion queue added by calling the ServerBuilder's // cqs_ contains the completion queue added by calling the ServerBuilder's
@ -283,14 +295,8 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
// listening to incoming channels. Such completion queues must be registered // listening to incoming channels. Such completion queues must be registered
// as non-listening queues // as non-listening queues
for (auto it = cqs_.begin(); it != cqs_.end(); ++it) { for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
if ((*it)->IsFrequentlyPolled()) {
grpc_server_register_completion_queue(server->server_, (*it)->cq(), grpc_server_register_completion_queue(server->server_, (*it)->cq(),
nullptr); nullptr);
num_frequently_polled_cqs++;
} else {
grpc_server_register_non_listening_completion_queue(server->server_,
(*it)->cq(), nullptr);
}
} }
if (num_frequently_polled_cqs == 0) { if (num_frequently_polled_cqs == 0) {

@ -44,9 +44,11 @@ namespace grpc {
namespace node { namespace node {
Server::Server(grpc_server *server) : wrapped_server(server) { Server::Server(grpc_server *server) : wrapped_server(server) {
shutdown_queue = grpc_completion_queue_create_for_pluck(NULL); grpc_completion_queue_attributes attrs = {
grpc_server_register_non_listening_completion_queue(server, shutdown_queue, GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_NON_LISTENING};
NULL); shutdown_queue = grpc_completion_queue_create(
grpc_completion_queue_factory_lookup(&attrs), &attrs, NULL);
grpc_server_register_completion_queue(server, shutdown_queue, NULL);
} }
Server::~Server() { Server::~Server() {

@ -0,0 +1,39 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library(
name = "health_proto",
srcs = ["health.proto"],
)

@ -36,6 +36,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library( grpc_proto_library(
name = "compiler_test_proto", name = "compiler_test_proto",
srcs = ["compiler_test.proto"], srcs = ["compiler_test.proto"],
generate_mock = True,
) )
grpc_proto_library( grpc_proto_library(
@ -55,6 +56,7 @@ grpc_proto_library(
name = "echo_proto", name = "echo_proto",
srcs = ["echo.proto"], srcs = ["echo.proto"],
deps = ["echo_messages_proto"], deps = ["echo_messages_proto"],
generate_mock = True,
) )
grpc_proto_library( grpc_proto_library(

@ -59,6 +59,14 @@ service ServiceA {
// Method A2 leading comment 2 // Method A2 leading comment 2
rpc MethodA2(stream Request) returns (Response); rpc MethodA2(stream Request) returns (Response);
// MethodA2 trailing comment 1 // MethodA2 trailing comment 1
// Method A3 leading comment 1
rpc MethodA3(Request) returns (stream Response);
// Method A3 trailing comment 1
// Method A4 leading comment 1
rpc MethodA4(stream Request) returns (stream Response);
// Method A4 trailing comment 1
} }
// Ignored ServiceA trailing comment 1 // Ignored ServiceA trailing comment 1

@ -356,8 +356,6 @@ cdef extern from "grpc/grpc.h":
void grpc_server_register_completion_queue(grpc_server *server, void grpc_server_register_completion_queue(grpc_server *server,
grpc_completion_queue *cq, grpc_completion_queue *cq,
void *reserved) nogil void *reserved) nogil
void grpc_server_register_non_listening_completion_queue(
grpc_server *server, grpc_completion_queue *cq, void *reserved) nogil
int grpc_server_add_insecure_http2_port( int grpc_server_add_insecure_http2_port(
grpc_server *server, const char *addr) nogil grpc_server *server, const char *addr) nogil
void grpc_server_start(grpc_server *server) nogil void grpc_server_start(grpc_server *server) nogil
@ -502,4 +500,3 @@ cdef extern from "grpc/compression.h":
int grpc_compression_options_is_algorithm_enabled( int grpc_compression_options_is_algorithm_enabled(
const grpc_compression_options *opts, const grpc_compression_options *opts,
grpc_compression_algorithm algorithm) nogil grpc_compression_algorithm algorithm) nogil

@ -82,20 +82,11 @@ cdef class Server:
self.c_server, queue.c_completion_queue, NULL) self.c_server, queue.c_completion_queue, NULL)
self.registered_completion_queues.append(queue) self.registered_completion_queues.append(queue)
def register_non_listening_completion_queue(
self, CompletionQueue queue not None):
if self.is_started:
raise ValueError("cannot register completion queues after start")
with nogil:
grpc_server_register_non_listening_completion_queue(
self.c_server, queue.c_completion_queue, NULL)
self.registered_completion_queues.append(queue)
def start(self): def start(self):
if self.is_started: if self.is_started:
raise ValueError("the server has already started") raise ValueError("the server has already started")
self.backup_shutdown_queue = CompletionQueue() self.backup_shutdown_queue = CompletionQueue()
self.register_non_listening_completion_queue(self.backup_shutdown_queue) self.register_completion_queue(self.backup_shutdown_queue)
self.is_started = True self.is_started = True
with nogil: with nogil:
grpc_server_start(self.c_server) grpc_server_start(self.c_server)

@ -127,7 +127,6 @@ grpc_server_register_method_type grpc_server_register_method_import;
grpc_server_request_registered_call_type grpc_server_request_registered_call_import; grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
grpc_server_create_type grpc_server_create_import; grpc_server_create_type grpc_server_create_import;
grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import; grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
grpc_server_register_non_listening_completion_queue_type grpc_server_register_non_listening_completion_queue_import;
grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import; grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
grpc_server_start_type grpc_server_start_import; grpc_server_start_type grpc_server_start_import;
grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import; grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
@ -425,7 +424,6 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call"); grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call");
grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create"); grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create");
grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue"); grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue");
grpc_server_register_non_listening_completion_queue_import = (grpc_server_register_non_listening_completion_queue_type) GetProcAddress(library, "grpc_server_register_non_listening_completion_queue");
grpc_server_add_insecure_http2_port_import = (grpc_server_add_insecure_http2_port_type) GetProcAddress(library, "grpc_server_add_insecure_http2_port"); grpc_server_add_insecure_http2_port_import = (grpc_server_add_insecure_http2_port_type) GetProcAddress(library, "grpc_server_add_insecure_http2_port");
grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start"); grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start");
grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify"); grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify");

@ -332,9 +332,6 @@ extern grpc_server_create_type grpc_server_create_import;
typedef void(*grpc_server_register_completion_queue_type)(grpc_server *server, grpc_completion_queue *cq, void *reserved); typedef void(*grpc_server_register_completion_queue_type)(grpc_server *server, grpc_completion_queue *cq, void *reserved);
extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import; extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
#define grpc_server_register_completion_queue grpc_server_register_completion_queue_import #define grpc_server_register_completion_queue grpc_server_register_completion_queue_import
typedef void(*grpc_server_register_non_listening_completion_queue_type)(grpc_server *server, grpc_completion_queue *q, void *reserved);
extern grpc_server_register_non_listening_completion_queue_type grpc_server_register_non_listening_completion_queue_import;
#define grpc_server_register_non_listening_completion_queue grpc_server_register_non_listening_completion_queue_import
typedef int(*grpc_server_add_insecure_http2_port_type)(grpc_server *server, const char *addr); typedef int(*grpc_server_add_insecure_http2_port_type)(grpc_server *server, const char *addr);
extern grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import; extern grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
#define grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port_import #define grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port_import

@ -311,7 +311,7 @@
USE_BUILT_PROTOC = false USE_BUILT_PROTOC = false
endif endif
GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc -Ithird_party/googletest/googlemock/include -Ithird_party/googletest/googlemock third_party/googletest/googlemock/src/gmock-all.cc
GTEST_LIB += -lgflags GTEST_LIB += -lgflags
ifeq ($(V),1) ifeq ($(V),1)
E = @: E = @:
@ -716,7 +716,7 @@
PC_REQUIRES_GRPCXX = PC_REQUIRES_GRPCXX =
PC_LIBS_GRPCXX = PC_LIBS_GRPCXX =
CPPFLAGS := -Ithird_party/googletest/googletest/include $(CPPFLAGS) CPPFLAGS := -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googlemock/include $(CPPFLAGS)
PROTOC_PLUGINS_ALL =\ PROTOC_PLUGINS_ALL =\
% for tgt in targets: % for tgt in targets:
@ -1240,6 +1240,14 @@
$(GENDIR)/${p}.pb.cc: protoc_dep_error $(GENDIR)/${p}.pb.cc: protoc_dep_error
$(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error $(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error
else else
<%
pluginflags=""
%>
% if p in ["src/proto/grpc/testing/compiler_test", "src/proto/grpc/testing/echo"]:
<%
pluginflags="generate_mock_code=true:"
%>
% endif
$(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc' % q for q in proto_deps.get(p, []))} $(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc' % q for q in proto_deps.get(p, []))}
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -1248,7 +1256,7 @@
$(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))} $(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))}
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=${pluginflags}$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif endif
% endfor % endfor

@ -9,7 +9,7 @@
for f in src: for f in src:
name, ext = os.path.splitext(f) name, ext = os.path.splitext(f)
if ext == '.proto': if ext == '.proto':
out.extend(fmt % name for fmt in ['%s.grpc.pb.h', '%s.pb.h']) out.extend(fmt % name for fmt in ['%s.grpc.pb.h', '%s.pb.h', '%s_mock.grpc.pb.h'])
return out return out
def all_targets(targets, libs, filegroups): def all_targets(targets, libs, filegroups):

@ -59,6 +59,7 @@
#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/port.h" #include "test/core/util/port.h"
@ -69,7 +70,7 @@ struct grpc_end2end_http_proxy {
grpc_channel_args* channel_args; grpc_channel_args* channel_args;
gpr_mu* mu; gpr_mu* mu;
grpc_pollset* pollset; grpc_pollset* pollset;
gpr_atm shutdown; gpr_refcount users;
}; };
// //
@ -77,6 +78,8 @@ struct grpc_end2end_http_proxy {
// //
typedef struct proxy_connection { typedef struct proxy_connection {
grpc_end2end_http_proxy* proxy;
grpc_endpoint* client_endpoint; grpc_endpoint* client_endpoint;
grpc_endpoint* server_endpoint; grpc_endpoint* server_endpoint;
@ -103,13 +106,20 @@ typedef struct proxy_connection {
grpc_http_request http_request; grpc_http_request http_request;
} proxy_connection; } proxy_connection;
static void proxy_connection_ref(proxy_connection* conn, const char* reason) {
gpr_ref(&conn->refcount);
}
// Helper function to destroy the proxy connection. // Helper function to destroy the proxy connection.
static void proxy_connection_unref(grpc_exec_ctx* exec_ctx, static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
proxy_connection* conn) { proxy_connection* conn, const char* reason) {
if (gpr_unref(&conn->refcount)) { if (gpr_unref(&conn->refcount)) {
gpr_log(GPR_DEBUG, "endpoints: %p %p", conn->client_endpoint,
conn->server_endpoint);
grpc_endpoint_destroy(exec_ctx, conn->client_endpoint); grpc_endpoint_destroy(exec_ctx, conn->client_endpoint);
if (conn->server_endpoint != NULL) if (conn->server_endpoint != NULL) {
grpc_endpoint_destroy(exec_ctx, conn->server_endpoint); grpc_endpoint_destroy(exec_ctx, conn->server_endpoint);
}
grpc_pollset_set_destroy(exec_ctx, conn->pollset_set); grpc_pollset_set_destroy(exec_ctx, conn->pollset_set);
grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_read_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_read_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx, grpc_slice_buffer_destroy_internal(exec_ctx,
@ -121,6 +131,7 @@ static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
grpc_slice_buffer_destroy_internal(exec_ctx, &conn->server_write_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &conn->server_write_buffer);
grpc_http_parser_destroy(&conn->http_parser); grpc_http_parser_destroy(&conn->http_parser);
grpc_http_request_destroy(&conn->http_request); grpc_http_request_destroy(&conn->http_request);
gpr_unref(&conn->proxy->users);
gpr_free(conn); gpr_free(conn);
} }
} }
@ -139,7 +150,7 @@ static void proxy_connection_failed(grpc_exec_ctx* exec_ctx,
grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint, grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint,
GRPC_ERROR_REF(error)); GRPC_ERROR_REF(error));
} }
proxy_connection_unref(exec_ctx, conn); proxy_connection_unref(exec_ctx, conn, "conn_failed");
} }
// Callback for writing proxy data to the client. // Callback for writing proxy data to the client.
@ -163,7 +174,7 @@ static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
&conn->on_client_write_done); &conn->on_client_write_done);
} else { } else {
// No more writes. Unref the connection. // No more writes. Unref the connection.
proxy_connection_unref(exec_ctx, conn); proxy_connection_unref(exec_ctx, conn, "write_done");
} }
} }
@ -188,7 +199,7 @@ static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
&conn->on_server_write_done); &conn->on_server_write_done);
} else { } else {
// No more writes. Unref the connection. // No more writes. Unref the connection.
proxy_connection_unref(exec_ctx, conn); proxy_connection_unref(exec_ctx, conn, "server_write");
} }
} }
@ -214,7 +225,7 @@ static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
} else { } else {
grpc_slice_buffer_move_into(&conn->client_read_buffer, grpc_slice_buffer_move_into(&conn->client_read_buffer,
&conn->server_write_buffer); &conn->server_write_buffer);
gpr_ref(&conn->refcount); proxy_connection_ref(conn, "client_read");
grpc_endpoint_write(exec_ctx, conn->server_endpoint, grpc_endpoint_write(exec_ctx, conn->server_endpoint,
&conn->server_write_buffer, &conn->server_write_buffer,
&conn->on_server_write_done); &conn->on_server_write_done);
@ -246,7 +257,7 @@ static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
} else { } else {
grpc_slice_buffer_move_into(&conn->server_read_buffer, grpc_slice_buffer_move_into(&conn->server_read_buffer,
&conn->client_write_buffer); &conn->client_write_buffer);
gpr_ref(&conn->refcount); proxy_connection_ref(conn, "server_read");
grpc_endpoint_write(exec_ctx, conn->client_endpoint, grpc_endpoint_write(exec_ctx, conn->client_endpoint,
&conn->client_write_buffer, &conn->client_write_buffer,
&conn->on_client_write_done); &conn->on_client_write_done);
@ -270,7 +281,9 @@ static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
// Start reading from both client and server. One of the read // Start reading from both client and server. One of the read
// requests inherits our ref to conn, but we need to take a new ref // requests inherits our ref to conn, but we need to take a new ref
// for the other one. // for the other one.
gpr_ref(&conn->refcount); proxy_connection_ref(conn, "client_read");
proxy_connection_ref(conn, "server_read");
proxy_connection_unref(exec_ctx, conn, "write_response");
grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer,
&conn->on_client_read_done); &conn->on_client_read_done);
grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer, grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer,
@ -312,6 +325,8 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) { grpc_error* error) {
proxy_connection* conn = arg; proxy_connection* conn = arg;
gpr_log(GPR_DEBUG, "on_read_request_done: %p %s", conn,
grpc_error_string(error));
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
proxy_connection_failed(exec_ctx, conn, true /* is_client */, proxy_connection_failed(exec_ctx, conn, true /* is_client */,
"HTTP proxy read request", error); "HTTP proxy read request", error);
@ -376,12 +391,14 @@ static void on_accept(grpc_exec_ctx* exec_ctx, void* arg,
gpr_free(acceptor); gpr_free(acceptor);
grpc_end2end_http_proxy* proxy = arg; grpc_end2end_http_proxy* proxy = arg;
// Instantiate proxy_connection. // Instantiate proxy_connection.
proxy_connection* conn = gpr_malloc(sizeof(*conn)); proxy_connection* conn = gpr_zalloc(sizeof(*conn));
memset(conn, 0, sizeof(*conn)); gpr_ref(&proxy->users);
conn->client_endpoint = endpoint; conn->client_endpoint = endpoint;
conn->proxy = proxy;
gpr_ref_init(&conn->refcount, 1); gpr_ref_init(&conn->refcount, 1);
conn->pollset_set = grpc_pollset_set_create(); conn->pollset_set = grpc_pollset_set_create();
grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset); grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset);
grpc_endpoint_add_to_pollset_set(exec_ctx, endpoint, conn->pollset_set);
grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn, grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, conn, grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, conn,
@ -416,6 +433,7 @@ static void thread_main(void* arg) {
grpc_end2end_http_proxy* proxy = arg; grpc_end2end_http_proxy* proxy = arg;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
do { do {
gpr_ref(&proxy->users);
const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
const gpr_timespec deadline = const gpr_timespec deadline =
gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN)); gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN));
@ -426,7 +444,7 @@ static void thread_main(void* arg) {
grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline)); grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline));
gpr_mu_unlock(proxy->mu); gpr_mu_unlock(proxy->mu);
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
} while (!gpr_atm_acq_load(&proxy->shutdown)); } while (!gpr_unref(&proxy->users));
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
} }
@ -434,6 +452,7 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy)); grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy));
memset(proxy, 0, sizeof(*proxy)); memset(proxy, 0, sizeof(*proxy));
gpr_ref_init(&proxy->users, 1);
// Construct proxy address. // Construct proxy address.
const int proxy_port = grpc_pick_unused_port_or_die(); const int proxy_port = grpc_pick_unused_port_or_die();
gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port); gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port);
@ -474,17 +493,16 @@ static void destroy_pollset(grpc_exec_ctx* exec_ctx, void* arg,
} }
void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) { void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
gpr_atm_rel_store(&proxy->shutdown, 1); // Signal proxy thread to shutdown. gpr_unref(&proxy->users); // Signal proxy thread to shutdown.
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
gpr_thd_join(proxy->thd); gpr_thd_join(proxy->thd);
grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server); grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server);
grpc_tcp_server_unref(&exec_ctx, proxy->server); grpc_tcp_server_unref(&exec_ctx, proxy->server);
gpr_free(proxy->proxy_name); gpr_free(proxy->proxy_name);
grpc_channel_args_destroy(&exec_ctx, proxy->channel_args); grpc_channel_args_destroy(&exec_ctx, proxy->channel_args);
grpc_closure destroyed; grpc_pollset_shutdown(&exec_ctx, proxy->pollset,
grpc_closure_init(&destroyed, destroy_pollset, proxy->pollset, grpc_closure_create(destroy_pollset, proxy->pollset,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx));
grpc_pollset_shutdown(&exec_ctx, proxy->pollset, &destroyed);
gpr_free(proxy); gpr_free(proxy);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
} }

@ -49,11 +49,12 @@ static void *tag(intptr_t t) { return (void *)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char *test_name, const char *test_name,
cancellation_mode mode, cancellation_mode mode,
size_t test_ops,
grpc_channel_args *client_args, grpc_channel_args *client_args,
grpc_channel_args *server_args) { grpc_channel_args *server_args) {
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s/%s", test_name, config.name, gpr_log(GPR_INFO, "Running test: %s/%s/%s [%" PRIdPTR " ops]", test_name,
mode.name); config.name, mode.name, test_ops);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args); config.init_client(&f, client_args);
@ -108,8 +109,8 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config,
grpc_op ops[6]; grpc_op ops[6];
grpc_op *op; grpc_op *op;
grpc_call *c; grpc_call *c;
grpc_end2end_test_fixture f = grpc_end2end_test_fixture f = begin_test(config, "test_cancel_after_invoke",
begin_test(config, "test_cancel_after_invoke", mode, NULL, NULL); mode, test_ops, NULL, NULL);
cq_verifier *cqv = cq_verifier_create(f.cq); cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_metadata_array initial_metadata_recv; grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv; grpc_metadata_array trailing_metadata_recv;

@ -62,7 +62,7 @@ cc_test(
cc_test( cc_test(
name = "golden_file_test", name = "golden_file_test",
srcs = ["golden_file_test.cc"], srcs = ["golden_file_test.cc"],
args = ["--generated_file_path=$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.h"], args = ["--generated_file_path=$(GENDIR)/src/proto/grpc/testing/"],
data = [ data = [
":compiler_test_golden", ":compiler_test_golden",
"//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen", "//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen",

@ -89,10 +89,30 @@ class ServiceA final {
return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag)); return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag));
} }
// MethodA2 trailing comment 1 // MethodA2 trailing comment 1
// Method A3 leading comment 1
std::unique_ptr< ::grpc::ClientReaderInterface< ::grpc::testing::Response>> MethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request) {
return std::unique_ptr< ::grpc::ClientReaderInterface< ::grpc::testing::Response>>(MethodA3Raw(context, request));
}
std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>> AsyncMethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>>(AsyncMethodA3Raw(context, request, cq, tag));
}
// Method A3 trailing comment 1
// Method A4 leading comment 1
std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>> MethodA4(::grpc::ClientContext* context) {
return std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(MethodA4Raw(context));
}
std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>> AsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(AsyncMethodA4Raw(context, cq, tag));
}
// Method A4 trailing comment 1
private: private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientWriterInterface< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) = 0; virtual ::grpc::ClientWriterInterface< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) = 0;
virtual ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) = 0; virtual ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) = 0;
virtual ::grpc::ClientReaderInterface< ::grpc::testing::Response>* MethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request) = 0;
virtual ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>* AsyncMethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
virtual ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4Raw(::grpc::ClientContext* context) = 0;
virtual ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>* AsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) = 0;
}; };
class Stub final : public StubInterface { class Stub final : public StubInterface {
public: public:
@ -107,14 +127,32 @@ class ServiceA final {
std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>> AsyncMethodA2(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) { std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>> AsyncMethodA2(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag)); return std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag));
} }
std::unique_ptr< ::grpc::ClientReader< ::grpc::testing::Response>> MethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request) {
return std::unique_ptr< ::grpc::ClientReader< ::grpc::testing::Response>>(MethodA3Raw(context, request));
}
std::unique_ptr< ::grpc::ClientAsyncReader< ::grpc::testing::Response>> AsyncMethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReader< ::grpc::testing::Response>>(AsyncMethodA3Raw(context, request, cq, tag));
}
std::unique_ptr< ::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> MethodA4(::grpc::ClientContext* context) {
return std::unique_ptr< ::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(MethodA4Raw(context));
}
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> AsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(AsyncMethodA4Raw(context, cq, tag));
}
private: private:
std::shared_ptr< ::grpc::ChannelInterface> channel_; std::shared_ptr< ::grpc::ChannelInterface> channel_;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override; ::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override;
::grpc::ClientAsyncWriter< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) override; ::grpc::ClientAsyncWriter< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) override;
::grpc::ClientReader< ::grpc::testing::Response>* MethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request) override;
::grpc::ClientAsyncReader< ::grpc::testing::Response>* AsyncMethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) override;
::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4Raw(::grpc::ClientContext* context) override;
::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* AsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) override;
const ::grpc::RpcMethod rpcmethod_MethodA1_; const ::grpc::RpcMethod rpcmethod_MethodA1_;
const ::grpc::RpcMethod rpcmethod_MethodA2_; const ::grpc::RpcMethod rpcmethod_MethodA2_;
const ::grpc::RpcMethod rpcmethod_MethodA3_;
const ::grpc::RpcMethod rpcmethod_MethodA4_;
}; };
static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
@ -131,6 +169,12 @@ class ServiceA final {
// Method A2 leading comment 2 // Method A2 leading comment 2
virtual ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response); virtual ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response);
// MethodA2 trailing comment 1 // MethodA2 trailing comment 1
// Method A3 leading comment 1
virtual ::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer);
// Method A3 trailing comment 1
// Method A4 leading comment 1
virtual ::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream);
// Method A4 trailing comment 1
}; };
template <class BaseClass> template <class BaseClass>
class WithAsyncMethod_MethodA1 : public BaseClass { class WithAsyncMethod_MethodA1 : public BaseClass {
@ -172,7 +216,47 @@ class ServiceA final {
::grpc::Service::RequestAsyncClientStreaming(1, context, reader, new_call_cq, notification_cq, tag); ::grpc::Service::RequestAsyncClientStreaming(1, context, reader, new_call_cq, notification_cq, tag);
} }
}; };
typedef WithAsyncMethod_MethodA1<WithAsyncMethod_MethodA2<Service > > AsyncService; template <class BaseClass>
class WithAsyncMethod_MethodA3 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_MethodA3() {
::grpc::Service::MarkMethodAsync(2);
}
~WithAsyncMethod_MethodA3() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestMethodA3(::grpc::ServerContext* context, ::grpc::testing::Request* request, ::grpc::ServerAsyncWriter< ::grpc::testing::Response>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncServerStreaming(2, context, request, writer, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_MethodA4 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_MethodA4() {
::grpc::Service::MarkMethodAsync(3);
}
~WithAsyncMethod_MethodA4() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestMethodA4(::grpc::ServerContext* context, ::grpc::ServerAsyncReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncBidiStreaming(3, context, stream, new_call_cq, notification_cq, tag);
}
};
typedef WithAsyncMethod_MethodA1<WithAsyncMethod_MethodA2<WithAsyncMethod_MethodA3<WithAsyncMethod_MethodA4<Service > > > > AsyncService;
template <class BaseClass> template <class BaseClass>
class WithGenericMethod_MethodA1 : public BaseClass { class WithGenericMethod_MethodA1 : public BaseClass {
private: private:
@ -208,6 +292,40 @@ class ServiceA final {
} }
}; };
template <class BaseClass> template <class BaseClass>
class WithGenericMethod_MethodA3 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_MethodA3() {
::grpc::Service::MarkMethodGeneric(2);
}
~WithGenericMethod_MethodA3() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_MethodA4 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_MethodA4() {
::grpc::Service::MarkMethodGeneric(3);
}
~WithGenericMethod_MethodA4() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithStreamedUnaryMethod_MethodA1 : public BaseClass { class WithStreamedUnaryMethod_MethodA1 : public BaseClass {
private: private:
void BaseClassMustBeDerivedFromService(const Service *service) {} void BaseClassMustBeDerivedFromService(const Service *service) {}
@ -228,8 +346,28 @@ class ServiceA final {
virtual ::grpc::Status StreamedMethodA1(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::grpc::testing::Request,::grpc::testing::Response>* server_unary_streamer) = 0; virtual ::grpc::Status StreamedMethodA1(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::grpc::testing::Request,::grpc::testing::Response>* server_unary_streamer) = 0;
}; };
typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedUnaryService; typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedUnaryService;
typedef Service SplitStreamedService; template <class BaseClass>
typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedService; class WithSplitStreamingMethod_MethodA3 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithSplitStreamingMethod_MethodA3() {
::grpc::Service::MarkMethodStreamed(2,
new ::grpc::SplitServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithSplitStreamingMethod_MethodA3<BaseClass>::StreamedMethodA3, this, std::placeholders::_1, std::placeholders::_2)));
}
~WithSplitStreamingMethod_MethodA3() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with split streamed
virtual ::grpc::Status StreamedMethodA3(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< ::grpc::testing::Request,::grpc::testing::Response>* server_split_streamer) = 0;
};
typedef WithSplitStreamingMethod_MethodA3<Service > SplitStreamedService;
typedef WithStreamedUnaryMethod_MethodA1<WithSplitStreamingMethod_MethodA3<Service > > StreamedService;
}; };
// ServiceB leading comment 1 // ServiceB leading comment 1

@ -0,0 +1,34 @@
// Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost.
// source: src/proto/grpc/testing/compiler_test.proto
#include "src/proto/grpc/testing/compiler_test.pb.h"
#include "src/proto/grpc/testing/compiler_test.grpc.pb.h"
#include <grpc++/impl/codegen/async_stream.h>
#include <grpc++/impl/codegen/sync_stream.h>
#include <gmock/gmock.h>
namespace grpc {
namespace testing {
class MockServiceAStub : public ServiceA::StubInterface {
public:
MOCK_METHOD3(MethodA1, ::grpc::Status(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::testing::Response* response));
MOCK_METHOD3(AsyncMethodA1Raw, ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq));
MOCK_METHOD2(MethodA2Raw, ::grpc::ClientWriterInterface< ::grpc::testing::Request>*(::grpc::ClientContext* context, ::grpc::testing::Response* response));
MOCK_METHOD4(AsyncMethodA2Raw, ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>*(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag));
MOCK_METHOD2(MethodA3Raw, ::grpc::ClientReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request));
MOCK_METHOD4(AsyncMethodA3Raw, ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag));
MOCK_METHOD1(MethodA4Raw, ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>*(::grpc::ClientContext* context));
MOCK_METHOD3(AsyncMethodA4Raw, ::grpc::ClientAsyncReaderWriterInterface<::grpc::testing::Request, ::grpc::testing::Response>*(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag));
};
class MockServiceBStub : public ServiceB::StubInterface {
public:
MOCK_METHOD3(MethodB1, ::grpc::Status(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::testing::Response* response));
MOCK_METHOD3(AsyncMethodB1Raw, ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq));
};
} // namespace grpc
} // namespace testing

@ -37,16 +37,18 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
DEFINE_string(generated_file_path, "", DEFINE_string(
"path to the generated compiler_test.grpc.pb.h file"); generated_file_path, "",
"path to the directory containing generated files compiler_test.grpc.pb.h"
"and compiler_test_mock.grpc.pb.h");
const char kGoldenFilePath[] = "test/cpp/codegen/compiler_test_golden"; const char kGoldenFilePath[] = "test/cpp/codegen/compiler_test_golden";
const char kMockGoldenFilePath[] = "test/cpp/codegen/compiler_test_mock_golden";
TEST(GoldenFileTest, TestGeneratedFile) { void run_test(std::basic_string<char> generated_file,
ASSERT_FALSE(FLAGS_generated_file_path.empty()); std::basic_string<char> golden_file) {
std::ifstream generated(generated_file);
std::ifstream generated(FLAGS_generated_file_path); std::ifstream golden(golden_file);
std::ifstream golden(kGoldenFilePath);
ASSERT_TRUE(generated.good()); ASSERT_TRUE(generated.good());
ASSERT_TRUE(golden.good()); ASSERT_TRUE(golden.good());
@ -61,8 +63,23 @@ TEST(GoldenFileTest, TestGeneratedFile) {
golden.close(); golden.close();
} }
TEST(GoldenFileTest, TestGeneratedFile) {
run_test(FLAGS_generated_file_path + "compiler_test.grpc.pb.h",
kGoldenFilePath);
}
TEST(GoldenMockFileTest, TestGeneratedMockFile) {
run_test(FLAGS_generated_file_path + "compiler_test_mock.grpc.pb.h",
kMockGoldenFilePath);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
::google::ParseCommandLineFlags(&argc, &argv, true); ::google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_generated_file_path.empty()) {
FLAGS_generated_file_path = "gens/src/proto/grpc/testing/";
}
if (FLAGS_generated_file_path.back() != '/')
FLAGS_generated_file_path.append("/");
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

@ -51,6 +51,7 @@ cc_test(
"//src/proto/grpc/testing:echo_messages_proto", "//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing:echo_proto",
"//src/proto/grpc/testing/duplicate:echo_duplicate_proto", "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
"//src/proto/grpc/health/v1:health_proto",
"//test/core/util:gpr_test_util", "//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
"//test/cpp/util:test_util", "//test/cpp/util:test_util",

@ -38,6 +38,7 @@
#include <grpc++/channel.h> #include <grpc++/channel.h>
#include <grpc++/client_context.h> #include <grpc++/client_context.h>
#include <grpc++/create_channel.h> #include <grpc++/create_channel.h>
#include <grpc++/ext/health_check_service_server_builder_option.h>
#include <grpc++/server.h> #include <grpc++/server.h>
#include <grpc++/server_builder.h> #include <grpc++/server_builder.h>
#include <grpc++/server_context.h> #include <grpc++/server_context.h>
@ -49,6 +50,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "src/core/lib/iomgr/port.h" #include "src/core/lib/iomgr/port.h"
#include "src/proto/grpc/health/v1/health.grpc.pb.h"
#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h" #include "test/core/util/port.h"
@ -224,13 +226,15 @@ class ServerBuilderSyncPluginDisabler : public ::grpc::ServerBuilderOption {
class TestScenario { class TestScenario {
public: public:
TestScenario(bool non_block, const grpc::string& creds_type, TestScenario(bool non_block, const grpc::string& creds_type, bool hcs,
const grpc::string& content) const grpc::string& content)
: disable_blocking(non_block), : disable_blocking(non_block),
health_check_service(hcs),
credentials_type(creds_type), credentials_type(creds_type),
message_content(content) {} message_content(content) {}
void Log() const; void Log() const;
bool disable_blocking; bool disable_blocking;
bool health_check_service;
// Although the below grpc::string's are logically const, we can't declare // Although the below grpc::string's are logically const, we can't declare
// them const because of a limitation in the way old compilers (e.g., gcc-4.4) // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
// manage vector insertion using a copy constructor // manage vector insertion using a copy constructor
@ -243,6 +247,8 @@ static std::ostream& operator<<(std::ostream& out,
return out << "TestScenario{disable_blocking=" return out << "TestScenario{disable_blocking="
<< (scenario.disable_blocking ? "true" : "false") << (scenario.disable_blocking ? "true" : "false")
<< ", credentials='" << scenario.credentials_type << ", credentials='" << scenario.credentials_type
<< ", health_check_service="
<< (scenario.health_check_service ? "true" : "false")
<< "', message_size=" << scenario.message_content.size() << "}"; << "', message_size=" << scenario.message_content.size() << "}";
} }
@ -252,6 +258,8 @@ void TestScenario::Log() const {
gpr_log(GPR_DEBUG, "%s", out.str().c_str()); gpr_log(GPR_DEBUG, "%s", out.str().c_str());
} }
class HealthCheck : public health::v1::Health::Service {};
class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
protected: protected:
AsyncEnd2endTest() { GetParam().Log(); } AsyncEnd2endTest() { GetParam().Log(); }
@ -268,6 +276,9 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
GetParam().credentials_type); GetParam().credentials_type);
builder.AddListeningPort(server_address_.str(), server_creds); builder.AddListeningPort(server_address_.str(), server_creds);
builder.RegisterService(&service_); builder.RegisterService(&service_);
if (GetParam().health_check_service) {
builder.RegisterService(&health_check_);
}
cq_ = builder.AddCompletionQueue(); cq_ = builder.AddCompletionQueue();
// TODO(zyc): make a test option to choose wheather sync plugins should be // TODO(zyc): make a test option to choose wheather sync plugins should be
@ -340,6 +351,7 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::unique_ptr<Server> server_; std::unique_ptr<Server> server_;
grpc::testing::EchoTestService::AsyncService service_; grpc::testing::EchoTestService::AsyncService service_;
HealthCheck health_check_;
std::ostringstream server_address_; std::ostringstream server_address_;
int port_; int port_;
@ -1754,12 +1766,14 @@ std::vector<TestScenario> CreateTestScenarios(bool test_disable_blocking,
messages.push_back(big_msg); messages.push_back(big_msg);
} }
for (auto health_check_service : {false, true}) {
for (auto cred = credentials_types.begin(); cred != credentials_types.end(); for (auto cred = credentials_types.begin(); cred != credentials_types.end();
++cred) { ++cred) {
for (auto msg = messages.begin(); msg != messages.end(); msg++) { for (auto msg = messages.begin(); msg != messages.end(); msg++) {
scenarios.emplace_back(false, *cred, *msg); scenarios.emplace_back(false, *cred, health_check_service, *msg);
if (test_disable_blocking) { if (test_disable_blocking) {
scenarios.emplace_back(true, *cred, *msg); scenarios.emplace_back(true, *cred, health_check_service, *msg);
}
} }
} }
} }

@ -34,6 +34,7 @@
#include <climits> #include <climits>
#include <thread> #include <thread>
#include <gmock/gmock.h>
#include <grpc++/channel.h> #include <grpc++/channel.h>
#include <grpc++/client_context.h> #include <grpc++/client_context.h>
#include <grpc++/create_channel.h> #include <grpc++/create_channel.h>
@ -46,120 +47,35 @@
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <grpc++/test/mock_stream.h>
#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "src/proto/grpc/testing/echo_mock.grpc.pb.h"
#include "test/core/util/port.h" #include "test/core/util/port.h"
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
#include <iostream>
using namespace std;
using grpc::testing::EchoRequest; using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse; using grpc::testing::EchoResponse;
using grpc::testing::EchoTestService; using grpc::testing::EchoTestService;
using grpc::testing::MockClientReaderWriter;
using std::chrono::system_clock; using std::chrono::system_clock;
using ::testing::AtLeast;
using ::testing::SetArgPointee;
using ::testing::SaveArg;
using ::testing::_;
using ::testing::Return;
using ::testing::Invoke;
using ::testing::WithArg;
using ::testing::DoAll;
namespace grpc { namespace grpc {
namespace testing { namespace testing {
namespace { namespace {
template <class W, class R>
class MockClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
public:
void WaitForInitialMetadata() override {}
bool NextMessageSize(uint32_t* sz) override {
*sz = UINT_MAX;
return true;
}
bool Read(R* msg) override { return true; }
bool Write(const W& msg) override { return true; }
bool WritesDone() override { return true; }
Status Finish() override { return Status::OK; }
};
template <>
class MockClientReaderWriter<EchoRequest, EchoResponse> final
: public ClientReaderWriterInterface<EchoRequest, EchoResponse> {
public:
MockClientReaderWriter() : writes_done_(false) {}
void WaitForInitialMetadata() override {}
bool NextMessageSize(uint32_t* sz) override {
*sz = UINT_MAX;
return true;
}
bool Read(EchoResponse* msg) override {
if (writes_done_) return false;
msg->set_message(last_message_);
return true;
}
bool Write(const EchoRequest& msg, WriteOptions options) override {
gpr_log(GPR_INFO, "mock recv msg %s", msg.message().c_str());
last_message_ = msg.message();
return true;
}
bool WritesDone() override {
writes_done_ = true;
return true;
}
Status Finish() override { return Status::OK; }
private:
bool writes_done_;
grpc::string last_message_;
};
// Mocked stub.
class MockStub : public EchoTestService::StubInterface {
public:
MockStub() {}
~MockStub() {}
Status Echo(ClientContext* context, const EchoRequest& request,
EchoResponse* response) override {
response->set_message(request.message());
return Status::OK;
}
Status Unimplemented(ClientContext* context, const EchoRequest& request,
EchoResponse* response) override {
return Status::OK;
}
private:
ClientAsyncResponseReaderInterface<EchoResponse>* AsyncEchoRaw(
ClientContext* context, const EchoRequest& request,
CompletionQueue* cq) override {
return nullptr;
}
ClientWriterInterface<EchoRequest>* RequestStreamRaw(
ClientContext* context, EchoResponse* response) override {
return nullptr;
}
ClientAsyncWriterInterface<EchoRequest>* AsyncRequestStreamRaw(
ClientContext* context, EchoResponse* response, CompletionQueue* cq,
void* tag) override {
return nullptr;
}
ClientReaderInterface<EchoResponse>* ResponseStreamRaw(
ClientContext* context, const EchoRequest& request) override {
return nullptr;
}
ClientAsyncReaderInterface<EchoResponse>* AsyncResponseStreamRaw(
ClientContext* context, const EchoRequest& request, CompletionQueue* cq,
void* tag) override {
return nullptr;
}
ClientReaderWriterInterface<EchoRequest, EchoResponse>* BidiStreamRaw(
ClientContext* context) override {
return new MockClientReaderWriter<EchoRequest, EchoResponse>();
}
ClientAsyncReaderWriterInterface<EchoRequest, EchoResponse>*
AsyncBidiStreamRaw(ClientContext* context, CompletionQueue* cq,
void* tag) override {
return nullptr;
}
ClientAsyncResponseReaderInterface<EchoResponse>* AsyncUnimplementedRaw(
ClientContext* context, const EchoRequest& request,
CompletionQueue* cq) override {
return nullptr;
}
};
class FakeClient { class FakeClient {
public: public:
explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {} explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {}
@ -174,6 +90,55 @@ class FakeClient {
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
} }
void DoRequestStream() {
EchoRequest request;
EchoResponse response;
ClientContext context;
grpc::string msg("hello");
grpc::string exp(msg);
std::unique_ptr<ClientWriterInterface<EchoRequest>> cstream =
stub_->RequestStream(&context, &response);
request.set_message(msg);
EXPECT_TRUE(cstream->Write(request));
msg = ", world";
request.set_message(msg);
exp.append(msg);
EXPECT_TRUE(cstream->Write(request));
cstream->WritesDone();
Status s = cstream->Finish();
EXPECT_EQ(exp, response.message());
EXPECT_TRUE(s.ok());
}
void DoResponseStream() {
EchoRequest request;
EchoResponse response;
request.set_message("hello world");
ClientContext context;
std::unique_ptr<ClientReaderInterface<EchoResponse>> cstream =
stub_->ResponseStream(&context, request);
grpc::string exp = "";
EXPECT_TRUE(cstream->Read(&response));
exp.append(response.message() + " ");
EXPECT_TRUE(cstream->Read(&response));
exp.append(response.message());
EXPECT_FALSE(cstream->Read(&response));
EXPECT_EQ(request.message(), exp);
Status s = cstream->Finish();
EXPECT_TRUE(s.ok());
}
void DoBidiStream() { void DoBidiStream() {
EchoRequest request; EchoRequest request;
EchoResponse response; EchoResponse response;
@ -219,6 +184,30 @@ class TestServiceImpl : public EchoTestService::Service {
return Status::OK; return Status::OK;
} }
Status RequestStream(ServerContext* context,
ServerReader<EchoRequest>* reader,
EchoResponse* response) override {
EchoRequest request;
grpc::string resp("");
while (reader->Read(&request)) {
gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
resp.append(request.message());
}
response->set_message(resp);
return Status::OK;
}
Status ResponseStream(ServerContext* context, const EchoRequest* request,
ServerWriter<EchoResponse>* writer) override {
EchoResponse response;
vector<grpc::string> tokens = split(request->message());
for (grpc::string token : tokens) {
response.set_message(token);
writer->Write(response);
}
return Status::OK;
}
Status BidiStream( Status BidiStream(
ServerContext* context, ServerContext* context,
ServerReaderWriter<EchoResponse, EchoRequest>* stream) override { ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
@ -231,6 +220,25 @@ class TestServiceImpl : public EchoTestService::Service {
} }
return Status::OK; return Status::OK;
} }
private:
const vector<grpc::string> split(const grpc::string& input) {
grpc::string buff("");
vector<grpc::string> result;
for (auto n : input) {
if (n != ' ') {
buff += n;
continue;
}
if (buff == "") continue;
result.push_back(buff);
buff = "";
}
if (buff != "") result.push_back(buff);
return result;
}
}; };
class MockTest : public ::testing::Test { class MockTest : public ::testing::Test {
@ -267,16 +275,82 @@ TEST_F(MockTest, SimpleRpc) {
ResetStub(); ResetStub();
FakeClient client(stub_.get()); FakeClient client(stub_.get());
client.DoEcho(); client.DoEcho();
MockStub stub; MockEchoTestServiceStub stub;
EchoResponse resp;
resp.set_message("hello world");
EXPECT_CALL(stub, Echo(_, _, _))
.Times(AtLeast(1))
.WillOnce(DoAll(SetArgPointee<2>(resp), Return(Status::OK)));
client.ResetStub(&stub); client.ResetStub(&stub);
client.DoEcho(); client.DoEcho();
} }
TEST_F(MockTest, ClientStream) {
ResetStub();
FakeClient client(stub_.get());
client.DoRequestStream();
MockEchoTestServiceStub stub;
auto w = new MockClientWriter<EchoRequest>();
EchoResponse resp;
resp.set_message("hello, world");
EXPECT_CALL(*w, Write(_, _)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(*w, WritesDone());
EXPECT_CALL(*w, Finish()).WillOnce(Return(Status::OK));
EXPECT_CALL(stub, RequestStreamRaw(_, _))
.WillOnce(DoAll(SetArgPointee<1>(resp), Return(w)));
client.ResetStub(&stub);
client.DoRequestStream();
}
TEST_F(MockTest, ServerStream) {
ResetStub();
FakeClient client(stub_.get());
client.DoResponseStream();
MockEchoTestServiceStub stub;
auto r = new MockClientReader<EchoResponse>();
EchoResponse resp1;
resp1.set_message("hello");
EchoResponse resp2;
resp2.set_message("world");
EXPECT_CALL(*r, Read(_))
.WillOnce(DoAll(SetArgPointee<0>(resp1), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(resp2), Return(true)))
.WillOnce(Return(false));
EXPECT_CALL(*r, Finish()).WillOnce(Return(Status::OK));
EXPECT_CALL(stub, ResponseStreamRaw(_, _)).WillOnce(Return(r));
client.ResetStub(&stub);
client.DoResponseStream();
}
ACTION_P(copy, msg) { arg0->set_message(msg->message()); }
TEST_F(MockTest, BidiStream) { TEST_F(MockTest, BidiStream) {
ResetStub(); ResetStub();
FakeClient client(stub_.get()); FakeClient client(stub_.get());
client.DoBidiStream(); client.DoBidiStream();
MockStub stub; MockEchoTestServiceStub stub;
auto rw = new MockClientReaderWriter<EchoRequest, EchoResponse>();
EchoRequest msg;
EXPECT_CALL(*rw, Write(_, _))
.Times(3)
.WillRepeatedly(DoAll(SaveArg<0>(&msg), Return(true)));
EXPECT_CALL(*rw, Read(_))
.WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
.WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
.WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
.WillOnce(Return(false));
EXPECT_CALL(*rw, WritesDone());
EXPECT_CALL(*rw, Finish()).WillOnce(Return(Status::OK));
EXPECT_CALL(stub, BidiStreamRaw(_)).WillOnce(Return(rw));
client.ResetStub(&stub); client.ResetStub(&stub);
client.DoBidiStream(); client.DoBidiStream();
} }

@ -2,11 +2,14 @@ cc_library(
name = "gtest", name = "gtest",
srcs = [ srcs = [
"googletest/src/gtest-all.cc", "googletest/src/gtest-all.cc",
"googlemock/src/gmock-all.cc"
], ],
hdrs = glob(["googletest/include/**/*.h", "googletest/src/*.cc", "googletest/src/*.h"]), hdrs = glob(["googletest/include/**/*.h", "googletest/src/*.cc", "googletest/src/*.h", "googlemock/include/**/*.h", "googlemock/src/*.cc", "googlemock/src/*.h"]),
includes = [ includes = [
"googletest", "googletest",
"googletest/include", "googletest/include",
"googlemock",
"googlemock/include",
], ],
linkstatic = 1, linkstatic = 1,
visibility = [ visibility = [

@ -2871,14 +2871,19 @@
"headers": [ "headers": [
"src/proto/grpc/testing/control.grpc.pb.h", "src/proto/grpc/testing/control.grpc.pb.h",
"src/proto/grpc/testing/control.pb.h", "src/proto/grpc/testing/control.pb.h",
"src/proto/grpc/testing/control_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/payloads.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.pb.h",
"src/proto/grpc/testing/payloads.pb.h", "src/proto/grpc/testing/payloads.pb.h",
"src/proto/grpc/testing/payloads_mock.grpc.pb.h",
"src/proto/grpc/testing/services.grpc.pb.h", "src/proto/grpc/testing/services.grpc.pb.h",
"src/proto/grpc/testing/services.pb.h", "src/proto/grpc/testing/services.pb.h",
"src/proto/grpc/testing/services_mock.grpc.pb.h",
"src/proto/grpc/testing/stats.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.pb.h",
"src/proto/grpc/testing/stats.pb.h" "src/proto/grpc/testing/stats.pb.h",
"src/proto/grpc/testing/stats_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -2899,14 +2904,19 @@
"headers": [ "headers": [
"src/proto/grpc/testing/control.grpc.pb.h", "src/proto/grpc/testing/control.grpc.pb.h",
"src/proto/grpc/testing/control.pb.h", "src/proto/grpc/testing/control.pb.h",
"src/proto/grpc/testing/control_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/payloads.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.pb.h",
"src/proto/grpc/testing/payloads.pb.h", "src/proto/grpc/testing/payloads.pb.h",
"src/proto/grpc/testing/payloads_mock.grpc.pb.h",
"src/proto/grpc/testing/services.grpc.pb.h", "src/proto/grpc/testing/services.grpc.pb.h",
"src/proto/grpc/testing/services.pb.h", "src/proto/grpc/testing/services.pb.h",
"src/proto/grpc/testing/services_mock.grpc.pb.h",
"src/proto/grpc/testing/stats.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.pb.h",
"src/proto/grpc/testing/stats.pb.h" "src/proto/grpc/testing/stats.pb.h",
"src/proto/grpc/testing/stats_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3027,7 +3037,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h" "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3084,7 +3095,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/testing/compiler_test.grpc.pb.h", "src/proto/grpc/testing/compiler_test.grpc.pb.h",
"src/proto/grpc/testing/compiler_test.pb.h" "src/proto/grpc/testing/compiler_test.pb.h",
"src/proto/grpc/testing/compiler_test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3229,7 +3241,9 @@
"src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.grpc.pb.h",
"src/proto/grpc/testing/echo.pb.h", "src/proto/grpc/testing/echo.pb.h",
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h" "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3249,7 +3263,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/lb/v1/load_balancer.grpc.pb.h", "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
"src/proto/grpc/lb/v1/load_balancer.pb.h" "src/proto/grpc/lb/v1/load_balancer.pb.h",
"src/proto/grpc/lb/v1/load_balancer_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3271,7 +3286,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/lb/v1/load_balancer.grpc.pb.h", "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
"src/proto/grpc/lb/v1/load_balancer.pb.h" "src/proto/grpc/lb/v1/load_balancer.pb.h",
"src/proto/grpc/lb/v1/load_balancer_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3426,6 +3442,7 @@
"headers": [ "headers": [
"src/proto/grpc/testing/metrics.grpc.pb.h", "src/proto/grpc/testing/metrics.grpc.pb.h",
"src/proto/grpc/testing/metrics.pb.h", "src/proto/grpc/testing/metrics.pb.h",
"src/proto/grpc/testing/metrics_mock.grpc.pb.h",
"test/cpp/util/metrics_server.h" "test/cpp/util/metrics_server.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -3447,11 +3464,14 @@
"grpc++_test_util", "grpc++_test_util",
"grpc_test_util" "grpc_test_util"
], ],
"headers": [], "headers": [
"include/grpc++/test/mock_stream.h"
],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
"name": "mock_test", "name": "mock_test",
"src": [ "src": [
"include/grpc++/test/mock_stream.h",
"test/cpp/end2end/mock_test.cc" "test/cpp/end2end/mock_test.cc"
], ],
"third_party": false, "third_party": false,
@ -3610,10 +3630,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h" "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3639,10 +3662,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h" "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3743,7 +3769,9 @@
"src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.grpc.pb.h",
"src/proto/grpc/testing/echo.pb.h", "src/proto/grpc/testing/echo.pb.h",
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h" "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3880,12 +3908,16 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/metrics.grpc.pb.h", "src/proto/grpc/testing/metrics.grpc.pb.h",
"src/proto/grpc/testing/metrics.pb.h", "src/proto/grpc/testing/metrics.pb.h",
"src/proto/grpc/testing/metrics_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h", "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h",
"test/cpp/interop/client_helper.h", "test/cpp/interop/client_helper.h",
"test/cpp/interop/interop_client.h", "test/cpp/interop/interop_client.h",
"test/cpp/interop/stress_interop_client.h", "test/cpp/interop/stress_interop_client.h",
@ -5900,7 +5932,8 @@
"headers": [ "headers": [
"include/grpc++/support/error_details.h", "include/grpc++/support/error_details.h",
"src/proto/grpc/status/status.grpc.pb.h", "src/proto/grpc/status/status.grpc.pb.h",
"src/proto/grpc/status/status.pb.h" "src/proto/grpc/status/status.pb.h",
"src/proto/grpc/status/status_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -5980,12 +6013,16 @@
"headers": [ "headers": [
"src/proto/grpc/health/v1/health.grpc.pb.h", "src/proto/grpc/health/v1/health.grpc.pb.h",
"src/proto/grpc/health/v1/health.pb.h", "src/proto/grpc/health/v1/health.pb.h",
"src/proto/grpc/health/v1/health_mock.grpc.pb.h",
"src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h", "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h",
"src/proto/grpc/testing/duplicate/echo_duplicate.pb.h", "src/proto/grpc/testing/duplicate/echo_duplicate.pb.h",
"src/proto/grpc/testing/duplicate/echo_duplicate_mock.grpc.pb.h",
"src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.grpc.pb.h",
"src/proto/grpc/testing/echo.pb.h", "src/proto/grpc/testing/echo.pb.h",
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h", "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h",
"test/cpp/end2end/test_service_impl.h", "test/cpp/end2end/test_service_impl.h",
"test/cpp/util/byte_buffer_proto_helper.h", "test/cpp/util/byte_buffer_proto_helper.h",
"test/cpp/util/create_test_channel.h", "test/cpp/util/create_test_channel.h",
@ -6165,10 +6202,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h", "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h",
"test/cpp/interop/http2_client.h" "test/cpp/interop/http2_client.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -6192,6 +6232,7 @@
"headers": [ "headers": [
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"test/cpp/interop/client_helper.h" "test/cpp/interop/client_helper.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -6218,10 +6259,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h", "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h",
"test/cpp/interop/interop_client.h" "test/cpp/interop/interop_client.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -6270,10 +6314,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h" "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -6307,14 +6354,19 @@
"headers": [ "headers": [
"src/proto/grpc/testing/control.grpc.pb.h", "src/proto/grpc/testing/control.grpc.pb.h",
"src/proto/grpc/testing/control.pb.h", "src/proto/grpc/testing/control.pb.h",
"src/proto/grpc/testing/control_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/payloads.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.pb.h",
"src/proto/grpc/testing/payloads.pb.h", "src/proto/grpc/testing/payloads.pb.h",
"src/proto/grpc/testing/payloads_mock.grpc.pb.h",
"src/proto/grpc/testing/services.grpc.pb.h", "src/proto/grpc/testing/services.grpc.pb.h",
"src/proto/grpc/testing/services.pb.h", "src/proto/grpc/testing/services.pb.h",
"src/proto/grpc/testing/services_mock.grpc.pb.h",
"src/proto/grpc/testing/stats.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.pb.h",
"src/proto/grpc/testing/stats.pb.h", "src/proto/grpc/testing/stats.pb.h",
"src/proto/grpc/testing/stats_mock.grpc.pb.h",
"test/cpp/qps/benchmark_config.h", "test/cpp/qps/benchmark_config.h",
"test/cpp/qps/client.h", "test/cpp/qps/client.h",
"test/cpp/qps/driver.h", "test/cpp/qps/driver.h",
@ -9020,7 +9072,8 @@
"deps": [], "deps": [],
"headers": [ "headers": [
"src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h", "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h",
"src/proto/grpc/reflection/v1alpha/reflection.pb.h" "src/proto/grpc/reflection/v1alpha/reflection.pb.h",
"src/proto/grpc/reflection/v1alpha/reflection_mock.grpc.pb.h"
], ],
"is_filegroup": true, "is_filegroup": true,
"language": "c++", "language": "c++",
@ -9034,12 +9087,14 @@
"grpc++" "grpc++"
], ],
"headers": [ "headers": [
"include/grpc++/test/mock_stream.h",
"include/grpc++/test/server_context_test_spouse.h" "include/grpc++/test/server_context_test_spouse.h"
], ],
"is_filegroup": true, "is_filegroup": true,
"language": "c++", "language": "c++",
"name": "grpc++_test", "name": "grpc++_test",
"src": [ "src": [
"include/grpc++/test/mock_stream.h",
"include/grpc++/test/server_context_test_spouse.h" "include/grpc++/test/server_context_test_spouse.h"
], ],
"third_party": false, "third_party": false,

@ -3329,7 +3329,7 @@
}, },
{ {
"args": [ "args": [
"--generated_file_path=gens/src/proto/grpc/testing/compiler_test.grpc.pb.h" "--generated_file_path=gens/src/proto/grpc/testing/"
], ],
"ci_platforms": [ "ci_platforms": [
"linux", "linux",

@ -159,6 +159,9 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\include\grpc++\test\mock_stream.h" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\mock_test.cc"> <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\mock_test.cc">
</ClCompile> </ClCompile>

@ -5,8 +5,22 @@
<Filter>test\cpp\end2end</Filter> <Filter>test\cpp\end2end</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\include\grpc++\test\mock_stream.h">
<Filter>include\grpc++\test</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="include">
<UniqueIdentifier>{b827d6d2-cfa5-2dd4-6ebc-afcccd5e8e0c}</UniqueIdentifier>
</Filter>
<Filter Include="include\grpc++">
<UniqueIdentifier>{28289e8f-b68e-b9f5-7680-c15d77b574a5}</UniqueIdentifier>
</Filter>
<Filter Include="include\grpc++\test">
<UniqueIdentifier>{4a7b43be-c730-6221-d190-e394521f9ae7}</UniqueIdentifier>
</Filter>
<Filter Include="test"> <Filter Include="test">
<UniqueIdentifier>{69c257a2-3e4c-a86e-ce0d-1a97b237d294}</UniqueIdentifier> <UniqueIdentifier>{69c257a2-3e4c-a86e-ce0d-1a97b237d294}</UniqueIdentifier>
</Filter> </Filter>

Loading…
Cancel
Save