diff options
author | Noah Eisen <ncteisen@google.com> | 2017-04-25 17:01:08 -0700 |
---|---|---|
committer | Noah Eisen <ncteisen@google.com> | 2017-04-25 17:01:08 -0700 |
commit | f725d7e6b6ac57641e67f363f3e3b585d074f0e2 (patch) | |
tree | 08d98309e9fe0993e6fb33e79662776fc7cc5b54 | |
parent | ad8d36d4dcd4deeec2d05644b78eb78ae0918f06 (diff) | |
parent | b864e7c41c6d0363e23093fb090625f260994962 (diff) |
Merge branch 'master' of https://github.com/grpc/grpc into client-auth-filter-fuzz
52 files changed, 1396 insertions, 378 deletions
@@ -54,33 +54,46 @@ grpc_cc_library( ], ) -grpc_cc_library( - name = "grpc", +grpc_cc_libraries( + name_list = ["grpc", "grpc_unsecure",], srcs = [ "src/core/lib/surface/init.c", - "src/core/plugin_registry/grpc_plugin_registry.c", + ], + additional_src_list = [ + [ + "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", standalone = True, deps = [ "census", "grpc_base", - "grpc_lb_policy_grpclb_secure", "grpc_lb_policy_pick_first", "grpc_lb_policy_round_robin", "grpc_load_reporting", "grpc_max_age_filter", - "grpc_resolver_dns_ares", "grpc_resolver_dns_native", "grpc_resolver_sockaddr", - "grpc_secure", "grpc_transport_chttp2_client_insecure", - "grpc_transport_chttp2_client_secure", "grpc_transport_chttp2_server_insecure", - "grpc_transport_chttp2_server_secure", "grpc_message_size_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( @@ -99,32 +112,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( name = "grpc++", srcs = [ "src/cpp/client/insecure_credentials.cc", @@ -174,7 +174,7 @@ LD_ubsan = clang LDXX_ubsan = clang++ CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow -DEFINES_ubsan = NDEBUG +DEFINES_ubsan = NDEBUG GRPC_UBSAN VALID_CONFIG_tsan = 1 REQUIRE_CUSTOM_LIBRARIES_tsan = 1 @@ -418,7 +418,7 @@ AROPTS = $(GRPC_CROSS_AROPTS) # e.g., rc --target=elf32-little USE_BUILT_PROTOC = false 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 ifeq ($(V),1) E = @: @@ -793,7 +793,7 @@ PROTOBUF_PKG_CONFIG = false PC_REQUIRES_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_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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + + $(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 $<" $(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) $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(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 ifeq ($(NO_PROTOC),true) $(GENDIR)/src/proto/grpc/testing/control.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: protoc_dep_error 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 $(E) "[PROTOC] Generating protobuf CC file from $<" $(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.grpc.pb.cc: protoc_dep_error 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 $(E) "[PROTOC] Generating protobuf CC file from $<" $(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.grpc.pb.cc: protoc_dep_error 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 $(E) "[PROTOC] Generating protobuf CC file from $<" $(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 $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(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 ifeq ($(NO_PROTOC),true) $(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 else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error 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 $(E) "[PROTOC] Generating protobuf CC file from $<" $(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.grpc.pb.cc: protoc_dep_error else + $(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 $<" $(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.grpc.pb.cc: protoc_dep_error 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 $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl index a3996eca00..0600bb9e30 100644 --- a/bazel/cc_grpc_library.bzl +++ b/bazel/cc_grpc_library.bzl @@ -2,7 +2,7 @@ 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. 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" use_external: When True the grpc deps are prefixed with //external. This 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. """ 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], plugin = plugin, well_known_protos = well_known_protos, + generate_mock = generate_mock, **kwargs ) diff --git a/bazel/generate_cc.bzl b/bazel/generate_cc.bzl index 35c2983b54..8f0f94f563 100644 --- a/bazel/generate_cc.bzl +++ b/bazel/generate_cc.bzl @@ -12,6 +12,8 @@ def generate_cc_impl(ctx): if ctx.executable.plugin: outs += [proto.basename[:-len(".proto")] + ".grpc.pb.h" 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: outs += [proto.basename[:-len(".proto")] + ".pb.h" 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 = [] if ctx.executable.plugin: 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] else: arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] @@ -71,6 +76,10 @@ generate_cc = rule( "well_known_protos" : attr.label( mandatory = False, ), + "generate_mock" : attr.bool( + default = False, + mandatory = False, + ), "_protoc": attr.label( default = Label("//external:protocol_compiler"), executable = True, diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index 984c06de48..a104fa00a0 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -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++"): - for i in range(len(name_list)): +def grpc_cc_libraries(name_list, additional_src_list = [], additional_dep_list = [], srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language="C++"): + 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( name = name_list[i], - srcs = srcs, + srcs = srcs + asl[i], hdrs = hdrs, public_hdrs = public_hdrs, - deps = deps + additional_dep_list[i], + deps = deps + adl[i], external_deps = external_deps, standalone = standalone, language = language @@ -72,7 +75,7 @@ def grpc_proto_plugin(name, srcs = [], deps = []): load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library") 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( name = name, srcs = srcs, @@ -80,5 +83,6 @@ def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None, well_known_protos = well_known_protos, proto_only = not has_services, use_external = use_external, + generate_mock = generate_mock, ) diff --git a/build.yaml b/build.yaml index 58a474aabf..cd38b3cf33 100644 --- a/build.yaml +++ b/build.yaml @@ -969,6 +969,7 @@ filegroups: - name: grpc++_test language: c++ public_headers: + - include/grpc++/test/mock_stream.h - include/grpc++/test/server_context_test_spouse.h deps: - grpc++ @@ -3691,7 +3692,7 @@ targets: - grpc - gpr 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 build: test run: false @@ -3952,6 +3953,8 @@ targets: gtest: true build: test language: c++ + headers: + - include/grpc++/test/mock_stream.h src: - test/cpp/end2end/mock_test.cc deps: @@ -4464,7 +4467,7 @@ configs: CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs CXX: clang++ - DEFINES: NDEBUG + DEFINES: NDEBUG GRPC_UBSAN LD: clang LDFLAGS: -fsanitize=undefined,unsigned-integer-overflow LDXX: clang++ @@ -89,7 +89,6 @@ EXPORTS grpc_server_request_registered_call grpc_server_create grpc_server_register_completion_queue - grpc_server_register_non_listening_completion_queue grpc_server_add_insecure_http2_port grpc_server_start grpc_server_shutdown_and_notify diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h index a5a4f3d739..4bf35ae778 100644 --- a/include/grpc++/impl/codegen/client_unary_call.h +++ b/include/grpc++/impl/codegen/client_unary_call.h @@ -52,7 +52,9 @@ template <class InputMessage, class OutputMessage> Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, ClientContext* context, const InputMessage& request, 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)); CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>, diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h index 61617f2bdc..c8ab726b0f 100644 --- a/include/grpc++/impl/codegen/completion_queue.h +++ b/include/grpc++/impl/codegen/completion_queue.h @@ -102,7 +102,9 @@ class CompletionQueue : private GrpcLibraryCodegen { public: /// Default constructor. Implicitly creates a \a grpc_completion_queue /// 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. /// @@ -182,6 +184,16 @@ class CompletionQueue : private GrpcLibraryCodegen { }; 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: // Friend synchronous wrappers so that they can access Pluck(), which is // a semi-private API geared towards the synchronous implementation. @@ -215,18 +227,6 @@ class CompletionQueue : private GrpcLibraryCodegen { const InputMessage& request, 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); /// Wraps \a grpc_completion_queue_pluck. @@ -289,17 +289,19 @@ class CompletionQueue : private GrpcLibraryCodegen { /// by servers. Instantiated by \a ServerBuilder. class ServerCompletionQueue : public CompletionQueue { public: - bool IsFrequentlyPolled() { return is_frequently_polled_; } + bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; } private: - bool is_frequently_polled_; + grpc_cq_polling_type polling_type_; friend class ServerBuilder; /// \param is_frequently_polled Informs the GRPC library about whether the /// server completion queue would be actively polled (by calling Next() or /// AsyncNext()). By default all server completion queues are assumed to be /// frequently polled. - ServerCompletionQueue(bool is_frequently_polled = true) - : is_frequently_polled_(is_frequently_polled) {} + ServerCompletionQueue(grpc_cq_polling_type polling_type) + : CompletionQueue(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type}), + polling_type_(polling_type) {} }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/core_codegen.h b/include/grpc++/impl/codegen/core_codegen.h index 86601076bd..a1593729eb 100644 --- a/include/grpc++/impl/codegen/core_codegen.h +++ b/include/grpc++/impl/codegen/core_codegen.h @@ -44,8 +44,15 @@ namespace grpc { /// Implementation of the core codegen interface. -class CoreCodegen : public CoreCodegenInterface { +class CoreCodegen final : public CoreCodegenInterface { 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( void* reserved) override; grpc_completion_queue* grpc_completion_queue_create_for_pluck( diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h index a0665f4e06..7cc3a82476 100644 --- a/include/grpc++/impl/codegen/core_codegen_interface.h +++ b/include/grpc++/impl/codegen/core_codegen_interface.h @@ -59,6 +59,12 @@ class CoreCodegenInterface { virtual void assert_fail(const char* failed_assertion, const char* file, 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( void* reserved) = 0; virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck( diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h index 328d5cb1e8..a010924cef 100644 --- a/include/grpc++/impl/codegen/sync_stream.h +++ b/include/grpc++/impl/codegen/sync_stream.h @@ -156,7 +156,9 @@ class ClientReader final : public ClientReaderInterface<R> { ClientReader(ChannelInterface* channel, const RpcMethod& method, ClientContext* context, const W& request) : 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_)) { CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose> @@ -230,7 +232,9 @@ class ClientWriter : public ClientWriterInterface<W> { ClientWriter(ChannelInterface* channel, const RpcMethod& method, ClientContext* context, R* response) : 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_)) { finish_ops_.RecvMessage(response); finish_ops_.AllowNoMessage(); @@ -330,7 +334,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method, ClientContext* 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_)) { if (!context_->initial_metadata_corked_) { CallOpSet<CallOpSendInitialMetadata> ops; diff --git a/include/grpc++/test/mock_stream.h b/include/grpc++/test/mock_stream.h new file mode 100644 index 0000000000..f2de9472d6 --- /dev/null +++ b/include/grpc++/test/mock_stream.h @@ -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 diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index 5ded451540..1eeb075927 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -93,55 +93,6 @@ GRPCAPI const char *grpc_version_string(void); /** Return a string specifying what the 'g' in gRPC stands for */ 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 NULL if no factory can be found */ GRPCAPI const grpc_completion_queue_factory * @@ -427,15 +378,6 @@ GRPCAPI void grpc_server_register_completion_queue(grpc_server *server, grpc_completion_queue *cq, 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. Returns bound port number on success, 0 on failure. REQUIRES: server not started */ diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index b5d637ed41..d9f5e07a8d 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -556,6 +556,55 @@ typedef struct { 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 } #endif diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 4cc6a4cf39..d3e71625d6 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -1408,4 +1408,180 @@ grpc::string GetSourceEpilogue(grpc_generator::File *file, 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 ¶ms) { + 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 ¶ms) { + 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 diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h index 69fd8a93e9..6119ebe289 100644 --- a/src/compiler/cpp_generator.h +++ b/src/compiler/cpp_generator.h @@ -65,6 +65,8 @@ struct Parameters { bool use_system_headers; // Prefix to any grpc include grpc::string grpc_search_path; + // Generate GMOCK code to facilitate unit testing. + bool generate_mock_code; }; // 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, const Parameters ¶ms); +// Return the prologue of the generated mock file. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated mock file. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated mock file. +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of generated mock file. +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated mock file. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated mock file. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated mock file. +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of generated mock file. +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + } // namespace grpc_cpp_generator #endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc index 4ee05ee037..35f1bf3e93 100644 --- a/src/compiler/cpp_plugin.cc +++ b/src/compiler/cpp_plugin.cc @@ -62,6 +62,7 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc_cpp_generator::Parameters generator_parameters; generator_parameters.use_system_headers = true; + generator_parameters.generate_mock_code = false; ProtoBufFile pbfile(file); @@ -85,6 +86,13 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { } } else if (param[0] == "grpc_search_path") { 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 { *error = grpc::string("Unknown parameter: ") + *parameter_string; return false; @@ -114,6 +122,19 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get()); 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; } diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c index ca283d034f..af70746064 100644 --- a/src/core/lib/iomgr/udp_server.c +++ b/src/core/lib/iomgr/udp_server.c @@ -92,6 +92,11 @@ struct grpc_udp_listener { struct grpc_udp_listener *next; }; +struct shutdown_fd_args { + grpc_fd *fd; + gpr_mu *server_mu; +}; + /* the overall server */ struct grpc_udp_server { gpr_mu mu; @@ -151,8 +156,13 @@ grpc_udp_server *grpc_udp_server_create(const grpc_channel_args *args) { return s; } -static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *fd, grpc_error *error) { - grpc_fd_shutdown(exec_ctx, (grpc_fd *)fd, GRPC_ERROR_REF(error)); +static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *args, + 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) { @@ -242,7 +252,10 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, if (s->active_ports) { for (sp = s->head; sp; sp = sp->next) { 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); sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure, sp->server->user_data); diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c index 35e9f7eb30..eae3f103b1 100644 --- a/src/core/lib/surface/completion_queue.c +++ b/src/core/lib/surface/completion_queue.c @@ -60,13 +60,154 @@ typedef struct { void *tag; } 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}, +}; + /* Completion queue structure */ struct grpc_completion_queue { /** owned by pollset */ gpr_mu *mu; grpc_cq_completion_type completion_type; - grpc_cq_polling_type polling_type; + + const cq_poller_vtable *poller_vtable; /** completed events */ grpc_cq_completion completed_head; @@ -127,15 +268,18 @@ grpc_completion_queue *grpc_completion_queue_create_internal( "polling_type=%d)", 2, (completion_type, polling_type)); - cc = gpr_zalloc(sizeof(grpc_completion_queue) + grpc_pollset_size()); - grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu); + const cq_poller_vtable *poller_vtable = + &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 cc->outstanding_tags = NULL; cc->outstanding_tag_capacity = 0; #endif cc->completion_type = completion_type; - cc->polling_type = polling_type; + cc->poller_vtable = poller_vtable; /* Initial ref is dropped by grpc_completion_queue_shutdown */ gpr_ref_init(&cc->pending_events, 1); @@ -164,10 +308,6 @@ grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc) { return cc->completion_type; } -grpc_cq_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc) { - return cc->polling_type; -} - #ifdef GRPC_CQ_REF_COUNT_DEBUG void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, const char *file, int line) { @@ -195,7 +335,7 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) { #endif if (gpr_unref(&cc->owning_refs)) { 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)); #ifndef NDEBUG gpr_free(cc->outstanding_tags); #endif @@ -280,7 +420,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, } } 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); if (kick_error != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(kick_error); @@ -295,8 +435,8 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, GPR_ASSERT(!cc->shutdown); GPR_ASSERT(cc->shutdown_called); cc->shutdown = 1; - grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), - &cc->pollset_shutdown_done); + cc->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cc), + &cc->pollset_shutdown_done); gpr_mu_unlock(cc->mu); } @@ -452,8 +592,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, gpr_mu_lock(cc->mu); continue; } else { - grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), NULL, - now, iteration_deadline); + grpc_error *err = cc->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cc), + NULL, now, iteration_deadline); if (err != GRPC_ERROR_NONE) { gpr_mu_unlock(cc->mu); const char *msg = grpc_error_string(err); @@ -644,8 +784,8 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, grpc_exec_ctx_flush(&exec_ctx); gpr_mu_lock(cc->mu); } else { - grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), - &worker, now, iteration_deadline); + grpc_error *err = cc->poller_vtable->work( + &exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, iteration_deadline); if (err != GRPC_ERROR_NONE) { del_plucker(cc, tag, &worker); gpr_mu_unlock(cc->mu); @@ -689,8 +829,8 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) { if (gpr_unref(&cc->pending_events)) { GPR_ASSERT(!cc->shutdown); cc->shutdown = 1; - grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), - &cc->pollset_shutdown_done); + cc->poller_vtable->shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), + &cc->pollset_shutdown_done); } gpr_mu_unlock(cc->mu); grpc_exec_ctx_finish(&exec_ctx); @@ -706,7 +846,7 @@ void grpc_completion_queue_destroy(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) { @@ -727,4 +867,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; } -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; +} diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h index 1ff3d64293..a932087939 100644 --- a/src/core/lib/surface/completion_queue.h +++ b/src/core/lib/surface/completion_queue.h @@ -94,13 +94,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_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); -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_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc); grpc_completion_queue *grpc_completion_queue_create_internal( grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type); diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index e133d1d2a4..934ca0431a 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -981,7 +981,7 @@ const grpc_channel_filter grpc_server_top_filter = { static void register_completion_queue(grpc_server *server, grpc_completion_queue *cq, - bool is_non_listening, void *reserved) { + void *reserved) { size_t i, n; GPR_ASSERT(!reserved); 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); - if (is_non_listening) { - grpc_cq_mark_non_listening_server_cq(cq); - } - GRPC_CQ_INTERNAL_REF(cq, "server"); n = server->cq_count++; 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 */ } - register_completion_queue(server, cq, false, 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); + register_completion_queue(server, cq, 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 = gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count); 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++] = grpc_cq_pollset(server->cqs[i]); } diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc index 4f8b826aec..f679a33945 100644 --- a/src/cpp/common/core_codegen.cc +++ b/src/cpp/common/core_codegen.cc @@ -54,6 +54,18 @@ struct grpc_byte_buffer; 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( void* reserved) { return ::grpc_completion_queue_create_for_next(reserved); diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index 3a15afc49e..2ead048a1f 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -83,7 +83,8 @@ ServerBuilder::~ServerBuilder() { std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue( 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); return std::unique_ptr<ServerCompletionQueue>(cq); } @@ -242,6 +243,16 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { sync_server_cqs(std::make_shared< 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) { // This is a Sync server gpr_log(GPR_INFO, @@ -251,9 +262,12 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { sync_server_settings_.max_pollers, 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 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 // 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) { grpc_server_register_completion_queue(server->server_, (*it)->cq(), nullptr); + num_frequently_polled_cqs++; } // 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 // as non-listening queues for (auto it = cqs_.begin(); it != cqs_.end(); ++it) { - if ((*it)->IsFrequentlyPolled()) { - grpc_server_register_completion_queue(server->server_, (*it)->cq(), - nullptr); - num_frequently_polled_cqs++; - } else { - grpc_server_register_non_listening_completion_queue(server->server_, - (*it)->cq(), nullptr); - } + grpc_server_register_completion_queue(server->server_, (*it)->cq(), + nullptr); } if (num_frequently_polled_cqs == 0) { diff --git a/src/node/ext/server_generic.cc b/src/node/ext/server_generic.cc index 24573bd52f..088273d527 100644 --- a/src/node/ext/server_generic.cc +++ b/src/node/ext/server_generic.cc @@ -44,9 +44,11 @@ namespace grpc { namespace node { Server::Server(grpc_server *server) : wrapped_server(server) { - shutdown_queue = grpc_completion_queue_create_for_pluck(NULL); - grpc_server_register_non_listening_completion_queue(server, shutdown_queue, - NULL); + grpc_completion_queue_attributes attrs = { + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_NON_LISTENING}; + 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() { diff --git a/src/proto/grpc/health/v1/BUILD b/src/proto/grpc/health/v1/BUILD new file mode 100644 index 0000000000..dbb91d9139 --- /dev/null +++ b/src/proto/grpc/health/v1/BUILD @@ -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"], +) diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD index 6f3422e4d1..805988c337 100644 --- a/src/proto/grpc/testing/BUILD +++ b/src/proto/grpc/testing/BUILD @@ -36,6 +36,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_proto_library") grpc_proto_library( name = "compiler_test_proto", srcs = ["compiler_test.proto"], + generate_mock = True, ) grpc_proto_library( @@ -55,6 +56,7 @@ grpc_proto_library( name = "echo_proto", srcs = ["echo.proto"], deps = ["echo_messages_proto"], + generate_mock = True, ) grpc_proto_library( diff --git a/src/proto/grpc/testing/compiler_test.proto b/src/proto/grpc/testing/compiler_test.proto index 085e8ae59f..24735522e0 100644 --- a/src/proto/grpc/testing/compiler_test.proto +++ b/src/proto/grpc/testing/compiler_test.proto @@ -59,6 +59,14 @@ service ServiceA { // Method A2 leading comment 2 rpc MethodA2(stream Request) returns (Response); // 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 diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi index 4f1776e002..f66f6e4122 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi @@ -356,8 +356,6 @@ cdef extern from "grpc/grpc.h": void grpc_server_register_completion_queue(grpc_server *server, grpc_completion_queue *cq, 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( grpc_server *server, const char *addr) 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( const grpc_compression_options *opts, grpc_compression_algorithm algorithm) nogil - diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi index 18db38b686..97192efda7 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi @@ -82,20 +82,11 @@ cdef class Server: self.c_server, queue.c_completion_queue, NULL) 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): if self.is_started: raise ValueError("the server has already started") 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 with nogil: grpc_server_start(self.c_server) diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 1c68b2dc7c..a412277f6d 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -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_create_type grpc_server_create_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_start_type grpc_server_start_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_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_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_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"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index c33fdd210e..7df8dd69fc 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -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); 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 -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); 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 diff --git a/templates/Makefile.template b/templates/Makefile.template index 1e6ca9337d..5ce606f828 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -311,7 +311,7 @@ USE_BUILT_PROTOC = false 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 ifeq ($(V),1) E = @: @@ -716,7 +716,7 @@ PC_REQUIRES_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 =\ % for tgt in targets: @@ -1240,6 +1240,14 @@ $(GENDIR)/${p}.pb.cc: protoc_dep_error $(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error 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, []))} $(E) "[PROTOC] Generating protobuf CC file from $<" $(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, []))} $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(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 % endfor diff --git a/templates/tools/run_tests/generated/sources_and_headers.json.template b/templates/tools/run_tests/generated/sources_and_headers.json.template index 1c5c9747d6..c7dc3c837d 100644 --- a/templates/tools/run_tests/generated/sources_and_headers.json.template +++ b/templates/tools/run_tests/generated/sources_and_headers.json.template @@ -9,7 +9,7 @@ for f in src: name, ext = os.path.splitext(f) 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 def all_targets(targets, libs, filegroups): diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c index 38054dd1e7..254c3a6b61 100644 --- a/test/core/util/port_server_client.c +++ b/test/core/util/port_server_client.c @@ -103,7 +103,7 @@ void grpc_free_port_using_server(int port) { grpc_resource_quota *resource_quota = grpc_resource_quota_create("port_server_client/free"); grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req, - grpc_timeout_seconds_to_deadline(10), + grpc_timeout_seconds_to_deadline(30), grpc_closure_create(freed_port_from_server, &pr, grpc_schedule_on_exec_ctx), &rsp); @@ -235,7 +235,7 @@ int grpc_pick_port_using_server(void) { grpc_resource_quota_create("port_server_client/pick"); grpc_httpcli_get( &exec_ctx, &context, &pr.pops, resource_quota, &req, - grpc_timeout_seconds_to_deadline(10), + grpc_timeout_seconds_to_deadline(30), grpc_closure_create(got_port_from_server, &pr, grpc_schedule_on_exec_ctx), &pr.response); grpc_resource_quota_unref_internal(&exec_ctx, resource_quota); diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 0180d6f08d..9a400c54ca 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -348,6 +348,14 @@ bool BuiltUnderMsan() { #endif } +bool BuiltUnderUbsan() { +#ifdef GRPC_UBSAN + return true; +#else + return false; +#endif +} + int64_t grpc_test_sanitizer_slowdown_factor() { int64_t sanitizer_multiplier = 1; if (BuiltUnderValgrind()) { @@ -358,6 +366,8 @@ int64_t grpc_test_sanitizer_slowdown_factor() { sanitizer_multiplier = 3; } else if (BuiltUnderMsan()) { sanitizer_multiplier = 4; + } else if (BuiltUnderUbsan()) { + sanitizer_multiplier = 5; } return sanitizer_multiplier; } diff --git a/test/cpp/codegen/BUILD b/test/cpp/codegen/BUILD index 14d5733da2..43d133fc34 100644 --- a/test/cpp/codegen/BUILD +++ b/test/cpp/codegen/BUILD @@ -62,7 +62,7 @@ cc_test( cc_test( name = "golden_file_test", 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 = [ ":compiler_test_golden", "//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen", diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index fd26a17ac1..8e3ae32a49 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -89,10 +89,30 @@ class ServiceA final { return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag)); } // 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: 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::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 { 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) { 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: 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::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::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_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()); @@ -131,6 +169,12 @@ class ServiceA final { // Method A2 leading comment 2 virtual ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response); // 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> class WithAsyncMethod_MethodA1 : public BaseClass { @@ -172,7 +216,47 @@ class ServiceA final { ::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> class WithGenericMethod_MethodA1 : public BaseClass { private: @@ -208,6 +292,40 @@ class ServiceA final { } }; 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 { private: 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; }; typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedUnaryService; - typedef Service SplitStreamedService; - typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedService; + template <class BaseClass> + 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 diff --git a/test/cpp/codegen/compiler_test_mock_golden b/test/cpp/codegen/compiler_test_mock_golden new file mode 100644 index 0000000000..8e4b4d5911 --- /dev/null +++ b/test/cpp/codegen/compiler_test_mock_golden @@ -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 + diff --git a/test/cpp/codegen/golden_file_test.cc b/test/cpp/codegen/golden_file_test.cc index 158a4d933c..7789ac738b 100644 --- a/test/cpp/codegen/golden_file_test.cc +++ b/test/cpp/codegen/golden_file_test.cc @@ -37,16 +37,18 @@ #include <gflags/gflags.h> #include <gtest/gtest.h> -DEFINE_string(generated_file_path, "", - "path to the generated compiler_test.grpc.pb.h file"); +DEFINE_string( + 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 kMockGoldenFilePath[] = "test/cpp/codegen/compiler_test_mock_golden"; -TEST(GoldenFileTest, TestGeneratedFile) { - ASSERT_FALSE(FLAGS_generated_file_path.empty()); - - std::ifstream generated(FLAGS_generated_file_path); - std::ifstream golden(kGoldenFilePath); +void run_test(std::basic_string<char> generated_file, + std::basic_string<char> golden_file) { + std::ifstream generated(generated_file); + std::ifstream golden(golden_file); ASSERT_TRUE(generated.good()); ASSERT_TRUE(golden.good()); @@ -61,8 +63,23 @@ TEST(GoldenFileTest, TestGeneratedFile) { 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) { ::testing::InitGoogleTest(&argc, argv); ::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(); } diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD index 0bf7948fcf..f1212e15c7 100644 --- a/test/cpp/end2end/BUILD +++ b/test/cpp/end2end/BUILD @@ -51,6 +51,7 @@ cc_test( "//src/proto/grpc/testing:echo_messages_proto", "//src/proto/grpc/testing:echo_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:grpc_test_util", "//test/cpp/util:test_util", diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 0b5215ef8e..cc3958bf13 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -38,6 +38,7 @@ #include <grpc++/channel.h> #include <grpc++/client_context.h> #include <grpc++/create_channel.h> +#include <grpc++/ext/health_check_service_server_builder_option.h> #include <grpc++/server.h> #include <grpc++/server_builder.h> #include <grpc++/server_context.h> @@ -49,6 +50,7 @@ #include <gtest/gtest.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/echo.grpc.pb.h" #include "test/core/util/port.h" @@ -224,13 +226,15 @@ class ServerBuilderSyncPluginDisabler : public ::grpc::ServerBuilderOption { class TestScenario { 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) : disable_blocking(non_block), + health_check_service(hcs), credentials_type(creds_type), message_content(content) {} void Log() const; bool disable_blocking; + bool health_check_service; // 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) // manage vector insertion using a copy constructor @@ -243,6 +247,8 @@ static std::ostream& operator<<(std::ostream& out, return out << "TestScenario{disable_blocking=" << (scenario.disable_blocking ? "true" : "false") << ", credentials='" << scenario.credentials_type + << ", health_check_service=" + << (scenario.health_check_service ? "true" : "false") << "', message_size=" << scenario.message_content.size() << "}"; } @@ -252,6 +258,8 @@ void TestScenario::Log() const { gpr_log(GPR_DEBUG, "%s", out.str().c_str()); } +class HealthCheck : public health::v1::Health::Service {}; + class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { protected: AsyncEnd2endTest() { GetParam().Log(); } @@ -268,6 +276,9 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { GetParam().credentials_type); builder.AddListeningPort(server_address_.str(), server_creds); builder.RegisterService(&service_); + if (GetParam().health_check_service) { + builder.RegisterService(&health_check_); + } cq_ = builder.AddCompletionQueue(); // 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<Server> server_; grpc::testing::EchoTestService::AsyncService service_; + HealthCheck health_check_; std::ostringstream server_address_; int port_; @@ -1754,12 +1766,14 @@ std::vector<TestScenario> CreateTestScenarios(bool test_disable_blocking, messages.push_back(big_msg); } - for (auto cred = credentials_types.begin(); cred != credentials_types.end(); - ++cred) { - for (auto msg = messages.begin(); msg != messages.end(); msg++) { - scenarios.emplace_back(false, *cred, *msg); - if (test_disable_blocking) { - scenarios.emplace_back(true, *cred, *msg); + for (auto health_check_service : {false, true}) { + for (auto cred = credentials_types.begin(); cred != credentials_types.end(); + ++cred) { + for (auto msg = messages.begin(); msg != messages.end(); msg++) { + scenarios.emplace_back(false, *cred, health_check_service, *msg); + if (test_disable_blocking) { + scenarios.emplace_back(true, *cred, health_check_service, *msg); + } } } } diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc index fdb2732e50..7e330063ed 100644 --- a/test/cpp/end2end/mock_test.cc +++ b/test/cpp/end2end/mock_test.cc @@ -34,6 +34,7 @@ #include <climits> #include <thread> +#include <gmock/gmock.h> #include <grpc++/channel.h> #include <grpc++/client_context.h> #include <grpc++/create_channel.h> @@ -46,120 +47,35 @@ #include <grpc/support/time.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/echo.grpc.pb.h" +#include "src/proto/grpc/testing/echo_mock.grpc.pb.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" +#include <iostream> + +using namespace std; using grpc::testing::EchoRequest; using grpc::testing::EchoResponse; using grpc::testing::EchoTestService; +using grpc::testing::MockClientReaderWriter; 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 testing { 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 { public: explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {} @@ -174,6 +90,55 @@ class FakeClient { 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() { EchoRequest request; EchoResponse response; @@ -219,6 +184,30 @@ class TestServiceImpl : public EchoTestService::Service { 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( ServerContext* context, ServerReaderWriter<EchoResponse, EchoRequest>* stream) override { @@ -231,6 +220,25 @@ class TestServiceImpl : public EchoTestService::Service { } 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 { @@ -267,16 +275,82 @@ TEST_F(MockTest, SimpleRpc) { ResetStub(); FakeClient client(stub_.get()); 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.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) { ResetStub(); FakeClient client(stub_.get()); 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.DoBidiStream(); } diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h index f129ede26a..98aca1c346 100644 --- a/test/cpp/microbenchmarks/fullstack_fixtures.h +++ b/test/cpp/microbenchmarks/fullstack_fixtures.h @@ -113,13 +113,17 @@ class TCP : public FullstackFixture { public: TCP(Service* service, const FixtureConfiguration& fixture_configuration = FixtureConfiguration()) - : FullstackFixture(service, fixture_configuration, MakeAddress()) {} + : FullstackFixture(service, fixture_configuration, MakeAddress(&port_)) {} + + ~TCP() { grpc_recycle_unused_port(port_); } private: - static grpc::string MakeAddress() { - int port = grpc_pick_unused_port_or_die(); + int port_; + + static grpc::string MakeAddress(int* port) { + *port = grpc_pick_unused_port_or_die(); std::stringstream addr; - addr << "localhost:" << port; + addr << "localhost:" << *port; return addr.str(); } }; @@ -128,14 +132,18 @@ class UDS : public FullstackFixture { public: UDS(Service* service, const FixtureConfiguration& fixture_configuration = FixtureConfiguration()) - : FullstackFixture(service, fixture_configuration, MakeAddress()) {} + : FullstackFixture(service, fixture_configuration, MakeAddress(&port_)) {} + + ~UDS() { grpc_recycle_unused_port(port_); } private: - static grpc::string MakeAddress() { - int port = grpc_pick_unused_port_or_die(); // just for a unique id - not a - // real port + int port_; + + static grpc::string MakeAddress(int* port) { + *port = grpc_pick_unused_port_or_die(); // just for a unique id - not a + // real port std::stringstream addr; - addr << "unix:/tmp/bm_fullstack." << port; + addr << "unix:/tmp/bm_fullstack." << *port; return addr.str(); } }; diff --git a/third_party/gtest.BUILD b/third_party/gtest.BUILD index 52c9ca2ba7..b70f2c51bc 100644 --- a/third_party/gtest.BUILD +++ b/third_party/gtest.BUILD @@ -2,11 +2,14 @@ cc_library( name = "gtest", srcs = [ "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 = [ "googletest", "googletest/include", + "googlemock", + "googlemock/include", ], linkstatic = 1, visibility = [ diff --git a/tools/jenkins/run_performance.sh b/tools/jenkins/run_performance.sh index 544e31dcbd..f530fb46b8 100755 --- a/tools/jenkins/run_performance.sh +++ b/tools/jenkins/run_performance.sh @@ -37,4 +37,5 @@ BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong # Enter the gRPC repo root cd $(dirname $0)/../.. +tools/run_tests/start_port_server.py tools/profiling/microbenchmarks/bm_diff.py -d origin/$ghprbTargetBranch -b $BENCHMARKS_TO_RUN diff --git a/tools/profiling/microbenchmarks/bm_diff.py b/tools/profiling/microbenchmarks/bm_diff.py index 6ee4cbfc7b..3c15478774 100755 --- a/tools/profiling/microbenchmarks/bm_diff.py +++ b/tools/profiling/microbenchmarks/bm_diff.py @@ -204,7 +204,10 @@ def eintr_be_gone(fn): def read_json(filename): - with open(filename) as f: return json.loads(f.read()) + try: + with open(filename) as f: return json.loads(f.read()) + except ValueError, e: + return None def finalize(): @@ -217,16 +220,18 @@ def finalize(): js_old_ctr = read_json('%s.counters.old.%d.json' % (bm, loop)) js_old_opt = read_json('%s.opt.old.%d.json' % (bm, loop)) - for row in bm_json.expand_json(js_new_ctr, js_new_opt): - print row - name = row['cpp_name'] - if name.endswith('_mean') or name.endswith('_stddev'): continue - benchmarks[name].add_sample(row, True) - for row in bm_json.expand_json(js_old_ctr, js_old_opt): - print row - name = row['cpp_name'] - if name.endswith('_mean') or name.endswith('_stddev'): continue - benchmarks[name].add_sample(row, False) + if js_new_ctr: + for row in bm_json.expand_json(js_new_ctr, js_new_opt): + print row + name = row['cpp_name'] + if name.endswith('_mean') or name.endswith('_stddev'): continue + benchmarks[name].add_sample(row, True) + if js_old_ctr: + for row in bm_json.expand_json(js_old_ctr, js_old_opt): + print row + name = row['cpp_name'] + if name.endswith('_mean') or name.endswith('_stddev'): continue + benchmarks[name].add_sample(row, False) really_interesting = set() for name, bm in benchmarks.items(): diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index f525faab9c..1f3bf7837f 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -2871,14 +2871,19 @@ "headers": [ "src/proto/grpc/testing/control.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.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.pb.h", + "src/proto/grpc/testing/services_mock.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, "language": "c++", @@ -2899,14 +2904,19 @@ "headers": [ "src/proto/grpc/testing/control.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.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.pb.h", + "src/proto/grpc/testing/services_mock.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, "language": "c++", @@ -3027,7 +3037,8 @@ ], "headers": [ "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, "language": "c++", @@ -3084,7 +3095,8 @@ ], "headers": [ "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, "language": "c++", @@ -3229,7 +3241,9 @@ "src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.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, "language": "c++", @@ -3249,7 +3263,8 @@ ], "headers": [ "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, "language": "c++", @@ -3271,7 +3286,8 @@ ], "headers": [ "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, "language": "c++", @@ -3426,6 +3442,7 @@ "headers": [ "src/proto/grpc/testing/metrics.grpc.pb.h", "src/proto/grpc/testing/metrics.pb.h", + "src/proto/grpc/testing/metrics_mock.grpc.pb.h", "test/cpp/util/metrics_server.h" ], "is_filegroup": false, @@ -3447,11 +3464,14 @@ "grpc++_test_util", "grpc_test_util" ], - "headers": [], + "headers": [ + "include/grpc++/test/mock_stream.h" + ], "is_filegroup": false, "language": "c++", "name": "mock_test", "src": [ + "include/grpc++/test/mock_stream.h", "test/cpp/end2end/mock_test.cc" ], "third_party": false, @@ -3610,10 +3630,13 @@ "headers": [ "src/proto/grpc/testing/empty.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.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, "language": "c++", @@ -3639,10 +3662,13 @@ "headers": [ "src/proto/grpc/testing/empty.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.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, "language": "c++", @@ -3743,7 +3769,9 @@ "src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.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, "language": "c++", @@ -3880,12 +3908,16 @@ "headers": [ "src/proto/grpc/testing/empty.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "src/proto/grpc/testing/metrics.grpc.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.pb.h", + "src/proto/grpc/testing/test_mock.grpc.pb.h", "test/cpp/interop/client_helper.h", "test/cpp/interop/interop_client.h", "test/cpp/interop/stress_interop_client.h", @@ -5900,7 +5932,8 @@ "headers": [ "include/grpc++/support/error_details.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, "language": "c++", @@ -5980,12 +6013,16 @@ "headers": [ "src/proto/grpc/health/v1/health.grpc.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.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.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_mock.grpc.pb.h", + "src/proto/grpc/testing/echo_mock.grpc.pb.h", "test/cpp/end2end/test_service_impl.h", "test/cpp/util/byte_buffer_proto_helper.h", "test/cpp/util/create_test_channel.h", @@ -6165,10 +6202,13 @@ "headers": [ "src/proto/grpc/testing/empty.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.pb.h", + "src/proto/grpc/testing/test_mock.grpc.pb.h", "test/cpp/interop/http2_client.h" ], "is_filegroup": false, @@ -6192,6 +6232,7 @@ "headers": [ "src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "test/cpp/interop/client_helper.h" ], "is_filegroup": false, @@ -6218,10 +6259,13 @@ "headers": [ "src/proto/grpc/testing/empty.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.pb.h", + "src/proto/grpc/testing/test_mock.grpc.pb.h", "test/cpp/interop/interop_client.h" ], "is_filegroup": false, @@ -6270,10 +6314,13 @@ "headers": [ "src/proto/grpc/testing/empty.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.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, "language": "c++", @@ -6307,14 +6354,19 @@ "headers": [ "src/proto/grpc/testing/control.grpc.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.pb.h", + "src/proto/grpc/testing/messages_mock.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.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.pb.h", + "src/proto/grpc/testing/services_mock.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.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/client.h", "test/cpp/qps/driver.h", @@ -9020,7 +9072,8 @@ "deps": [], "headers": [ "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, "language": "c++", @@ -9034,12 +9087,14 @@ "grpc++" ], "headers": [ + "include/grpc++/test/mock_stream.h", "include/grpc++/test/server_context_test_spouse.h" ], "is_filegroup": true, "language": "c++", "name": "grpc++_test", "src": [ + "include/grpc++/test/mock_stream.h", "include/grpc++/test/server_context_test_spouse.h" ], "third_party": false, diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 38e9e2a880..2928b870c9 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -3329,7 +3329,7 @@ }, { "args": [ - "--generated_file_path=gens/src/proto/grpc/testing/compiler_test.grpc.pb.h" + "--generated_file_path=gens/src/proto/grpc/testing/" ], "ci_platforms": [ "linux", diff --git a/tools/run_tests/python_utils/port_server.py b/tools/run_tests/python_utils/port_server.py index dbd32efc0e..e96ee0b08c 100755 --- a/tools/run_tests/python_utils/port_server.py +++ b/tools/run_tests/python_utils/port_server.py @@ -33,18 +33,20 @@ from __future__ import print_function import argparse -from six.moves import BaseHTTPServer +from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler import hashlib import os import socket import sys import time +from SocketServer import ThreadingMixIn +import threading # increment this number whenever making a change to ensure that # the changes are picked up by running CI servers # note that all changes must be backwards compatible -_MY_VERSION = 9 +_MY_VERSION = 14 if len(sys.argv) == 2 and sys.argv[1] == 'dump_version': @@ -68,6 +70,7 @@ print('port server running on port %d' % args.port) pool = [] in_use = {} +mu = threading.Lock() def refill_pool(max_timeout, req): @@ -95,28 +98,33 @@ def refill_pool(max_timeout, req): def allocate_port(req): global pool global in_use + global mu + mu.acquire() max_timeout = 600 while not pool: refill_pool(max_timeout, req) if not pool: req.log_message("failed to find ports: retrying soon") + mu.release() time.sleep(1) + mu.acquire() max_timeout /= 2 port = pool[0] pool = pool[1:] in_use[port] = time.time() + mu.release() return port keep_running = True -class Handler(BaseHTTPServer.BaseHTTPRequestHandler): +class Handler(BaseHTTPRequestHandler): def setup(self): # If the client is unreachable for 5 seconds, close the connection self.timeout = 5 - BaseHTTPServer.BaseHTTPRequestHandler.setup(self) + BaseHTTPRequestHandler.setup(self) def do_GET(self): global keep_running @@ -158,12 +166,11 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler): elif self.path == '/quitquitquit': self.send_response(200) self.end_headers() - keep_running = False + self.server.shutdown() +class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): + """Handle requests in a separate thread""" -httpd = BaseHTTPServer.HTTPServer(('', args.port), Handler) -while keep_running: - httpd.handle_request() - sys.stderr.flush() -print('done') +ThreadedHTTPServer(('', args.port), Handler).serve_forever() + diff --git a/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj b/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj index 8c840fd5be..bc1cae5911 100644 --- a/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj +++ b/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj @@ -160,6 +160,9 @@ </ItemDefinitionGroup> <ItemGroup> + <ClInclude Include="$(SolutionDir)\..\include\grpc++\test\mock_stream.h" /> + </ItemGroup> + <ItemGroup> <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\mock_test.cc"> </ClCompile> </ItemGroup> diff --git a/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj.filters b/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj.filters index 1b3b773b08..6db61c9037 100644 --- a/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj.filters +++ b/vsprojects/vcxproj/test/mock_test/mock_test.vcxproj.filters @@ -5,8 +5,22 @@ <Filter>test\cpp\end2end</Filter> </ClCompile> </ItemGroup> + <ItemGroup> + <ClInclude Include="$(SolutionDir)\..\include\grpc++\test\mock_stream.h"> + <Filter>include\grpc++\test</Filter> + </ClInclude> + </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"> <UniqueIdentifier>{69c257a2-3e4c-a86e-ce0d-1a97b237d294}</UniqueIdentifier> </Filter> |