diff --git a/CMakeLists.txt b/CMakeLists.txt index ee8e994b470..9eb2007ba26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1403,6 +1403,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx time_jump_test) endif() add_dependencies(buildtests_cxx time_util_test) + add_dependencies(buildtests_cxx timeout_before_request_call_test) add_dependencies(buildtests_cxx timeout_encoding_test) add_dependencies(buildtests_cxx timer_manager_test) add_dependencies(buildtests_cxx timer_test) @@ -24778,6 +24779,50 @@ target_link_libraries(time_util_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(timeout_before_request_call_test + test/core/end2end/cq_verifier.cc + test/core/end2end/end2end_test_main.cc + test/core/end2end/end2end_test_suites.cc + test/core/end2end/end2end_tests.cc + test/core/end2end/fixtures/http_proxy_fixture.cc + test/core/end2end/fixtures/local_util.cc + test/core/end2end/fixtures/proxy.cc + test/core/end2end/tests/timeout_before_request_call.cc + test/core/event_engine/event_engine_test_utils.cc + test/core/util/test_lb_policies.cc +) +target_compile_features(timeout_before_request_call_test PUBLIC cxx_std_14) +target_include_directories(timeout_before_request_call_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(timeout_before_request_call_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + grpc_authorization_provider + grpc_unsecure + grpc_test_util +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 9d877645116..034b638c468 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -16455,6 +16455,42 @@ targets: - gtest - grpc_test_util uses_polling: false +- name: timeout_before_request_call_test + gtest: true + build: test + language: c++ + headers: + - test/core/end2end/cq_verifier.h + - test/core/end2end/end2end_tests.h + - test/core/end2end/fixtures/h2_oauth2_common.h + - test/core/end2end/fixtures/h2_ssl_cred_reload_fixture.h + - test/core/end2end/fixtures/h2_ssl_tls_common.h + - test/core/end2end/fixtures/h2_tls_common.h + - test/core/end2end/fixtures/http_proxy_fixture.h + - test/core/end2end/fixtures/inproc_fixture.h + - test/core/end2end/fixtures/local_util.h + - test/core/end2end/fixtures/proxy.h + - test/core/end2end/fixtures/secure_fixture.h + - test/core/end2end/fixtures/sockpair_fixture.h + - test/core/end2end/tests/cancel_test_helpers.h + - test/core/event_engine/event_engine_test_utils.h + - test/core/util/test_lb_policies.h + src: + - test/core/end2end/cq_verifier.cc + - test/core/end2end/end2end_test_main.cc + - test/core/end2end/end2end_test_suites.cc + - test/core/end2end/end2end_tests.cc + - test/core/end2end/fixtures/http_proxy_fixture.cc + - test/core/end2end/fixtures/local_util.cc + - test/core/end2end/fixtures/proxy.cc + - test/core/end2end/tests/timeout_before_request_call.cc + - test/core/event_engine/event_engine_test_utils.cc + - test/core/util/test_lb_policies.cc + deps: + - gtest + - grpc_authorization_provider + - grpc_unsecure + - grpc_test_util - name: timeout_encoding_test gtest: true build: test diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD index f046f6d9ace..2ddddc6506a 100644 --- a/test/core/end2end/BUILD +++ b/test/core/end2end/BUILD @@ -158,6 +158,7 @@ grpc_cc_library( "tests/cancel_test_helpers.h", ], external_deps = [ + "absl/functional:any_invocable", "absl/status", "absl/status:statusor", "absl/strings", @@ -196,6 +197,7 @@ grpc_cc_library( ], external_deps = [ "absl/base:core_headers", + "absl/functional:any_invocable", "absl/meta:type_traits", "absl/random", "absl/status", @@ -446,6 +448,8 @@ grpc_core_end2end_test(name = "simple_request") grpc_core_end2end_test(name = "streaming_error_response") +grpc_core_end2end_test(name = "timeout_before_request_call") + grpc_core_end2end_test(name = "trailing_metadata") grpc_core_end2end_test(name = "write_buffering") diff --git a/test/core/end2end/end2end_test_corpus/timeout_before_request_call/empty b/test/core/end2end/end2end_test_corpus/timeout_before_request_call/empty new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/test/core/end2end/end2end_test_corpus/timeout_before_request_call/empty @@ -0,0 +1 @@ + diff --git a/test/core/end2end/end2end_test_suites.cc b/test/core/end2end/end2end_test_suites.cc index eeab30bc63d..c19ce955beb 100644 --- a/test/core/end2end/end2end_test_suites.cc +++ b/test/core/end2end/end2end_test_suites.cc @@ -25,6 +25,7 @@ #include #include "absl/base/thread_annotations.h" +#include "absl/functional/any_invocable.h" #include "absl/meta/type_traits.h" #include "absl/random/random.h" #include "absl/status/status.h" @@ -122,8 +123,9 @@ void AddFailAuthCheckIfNeeded(const ChannelArgs& args, class CensusFixture : public CoreTestFixture { private: - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { grpc_server_credentials* server_creds = grpc_insecure_server_credentials_create(); auto* server = grpc_server_create( @@ -132,6 +134,7 @@ class CensusFixture : public CoreTestFixture { GPR_ASSERT( grpc_server_add_http2_port(server, localaddr_.c_str(), server_creds)); grpc_server_credentials_release(server_creds); + pre_server_start(server); grpc_server_start(server); return server; } @@ -150,8 +153,9 @@ class CensusFixture : public CoreTestFixture { class CompressionFixture : public CoreTestFixture { private: - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { auto* server = grpc_server_create( args.SetIfUnset(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, GRPC_COMPRESS_GZIP) @@ -164,6 +168,7 @@ class CompressionFixture : public CoreTestFixture { GPR_ASSERT( grpc_server_add_http2_port(server, localaddr_.c_str(), server_creds)); grpc_server_credentials_release(server_creds); + pre_server_start(server); grpc_server_start(server); return server; } @@ -246,11 +251,13 @@ class FdFixture : public CoreTestFixture { FdFixture() { create_sockets(fd_pair_); } private: - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { ExecCtx exec_ctx; auto* server = grpc_server_create(args.ToC().get(), nullptr); grpc_server_register_completion_queue(server, cq, nullptr); + pre_server_start(server); grpc_server_start(server); grpc_server_credentials* creds = grpc_insecure_server_credentials_create(); grpc_server_add_channel_from_fd(server, fd_pair_[1], creds); @@ -298,8 +305,9 @@ class HttpProxyFilter : public CoreTestFixture { ~HttpProxyFilter() override { grpc_end2end_http_proxy_destroy(proxy_); } private: - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { auto* server = grpc_server_create(args.ToC().get(), nullptr); grpc_server_register_completion_queue(server, cq, nullptr); grpc_server_credentials* server_creds = @@ -307,6 +315,7 @@ class HttpProxyFilter : public CoreTestFixture { GPR_ASSERT( grpc_server_add_http2_port(server, server_addr_.c_str(), server_creds)); grpc_server_credentials_release(server_creds); + pre_server_start(server); grpc_server_start(server); return server; } @@ -365,8 +374,9 @@ class ProxyFixture : public CoreTestFixture { return channel; } - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { auto* server = grpc_server_create(args.ToC().get(), nullptr); grpc_server_register_completion_queue(server, cq, nullptr); grpc_server_credentials* server_creds = @@ -374,6 +384,7 @@ class ProxyFixture : public CoreTestFixture { GPR_ASSERT(grpc_server_add_http2_port( server, grpc_end2end_proxy_get_server_port(proxy_), server_creds)); grpc_server_credentials_release(server_creds); + pre_server_start(server); grpc_server_start(server); return server; } @@ -443,8 +454,9 @@ class SslProxyFixture : public CoreTestFixture { return channel; } - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { grpc_slice cert_slice, key_slice; GPR_ASSERT(GRPC_LOG_IF_ERROR( "load_file", grpc_load_file(SERVER_CERT_PATH, 1, &cert_slice))); @@ -470,6 +482,7 @@ class SslProxyFixture : public CoreTestFixture { GPR_ASSERT(grpc_server_add_http2_port( server, grpc_end2end_proxy_get_server_port(proxy_), ssl_creds)); grpc_server_credentials_release(ssl_creds); + pre_server_start(server); grpc_server_start(server); return server; } @@ -506,9 +519,10 @@ class FixtureWithTracing final : public CoreTestFixture { // g_fixture_slowdown_factor = 1; } - grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) override { - return fixture_->MakeServer(args, cq); + grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { + return fixture_->MakeServer(args, cq, pre_server_start); } grpc_channel* MakeClient(const ChannelArgs& args, @@ -1028,6 +1042,13 @@ CORE_END2END_TEST_SUITE( CoreDeadlineTest, ConfigQuery().ExcludeFeatures(FEATURE_MASK_IS_MINSTACK).Run()); +CORE_END2END_TEST_SUITE( + CoreDeadlineSingleHopTest, + ConfigQuery() + .ExcludeFeatures(FEATURE_MASK_SUPPORTS_REQUEST_PROXYING | + FEATURE_MASK_IS_MINSTACK) + .Run()); + CORE_END2END_TEST_SUITE( CoreClientChannelTest, ConfigQuery().EnforceFeatures(FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL).Run()); diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc index 6c15e1f0d3c..cc5c9422287 100644 --- a/test/core/end2end/end2end_tests.cc +++ b/test/core/end2end/end2end_tests.cc @@ -319,12 +319,40 @@ CoreEnd2endTest::Call CoreEnd2endTest::ClientCallBuilder::Create() { } } +CoreEnd2endTest::ServerRegisteredMethod::ServerRegisteredMethod( + CoreEnd2endTest* test, absl::string_view name, + grpc_server_register_method_payload_handling payload_handling) { + GPR_ASSERT(test->server_ == nullptr); + test->pre_server_start_ = [old = std::move(test->pre_server_start_), + handle = handle_, name = std::string(name), + payload_handling](grpc_server* server) mutable { + *handle = grpc_server_register_method(server, name.c_str(), nullptr, + payload_handling, 0); + old(server); + }; +} + CoreEnd2endTest::IncomingCall::IncomingCall(CoreEnd2endTest& test, int tag) : impl_(std::make_unique(&test)) { test.ForceInitialized(); - grpc_server_request_call(test.server(), impl_->call.call_ptr(), - &impl_->call_details, &impl_->request_metadata, - test.cq(), test.cq(), CqVerifier::tag(tag)); + EXPECT_EQ( + grpc_server_request_call(test.server(), impl_->call.call_ptr(), + &impl_->call_details, &impl_->request_metadata, + test.cq(), test.cq(), CqVerifier::tag(tag)), + GRPC_CALL_OK); +} + +CoreEnd2endTest::IncomingCall::IncomingCall(CoreEnd2endTest& test, void* method, + IncomingMessage* message, int tag) + : impl_(std::make_unique(&test)) { + test.ForceInitialized(); + impl_->call_details.method = grpc_empty_slice(); + EXPECT_EQ(grpc_server_request_registered_call( + test.server(), method, impl_->call.call_ptr(), + &impl_->call_details.deadline, &impl_->request_metadata, + message == nullptr ? nullptr : &message->payload_, test.cq(), + test.cq(), CqVerifier::tag(tag)), + GRPC_CALL_OK); } absl::optional CoreEnd2endTest::IncomingCall::GetInitialMetadata( diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h index 5d8a607b0a1..db93973b1ad 100644 --- a/test/core/end2end/end2end_tests.h +++ b/test/core/end2end/end2end_tests.h @@ -95,8 +95,9 @@ class CoreTestFixture { public: virtual ~CoreTestFixture() = default; - virtual grpc_server* MakeServer(const ChannelArgs& args, - grpc_completion_queue* cq) = 0; + virtual grpc_server* MakeServer( + const ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) = 0; virtual grpc_channel* MakeClient(const ChannelArgs& args, grpc_completion_queue* cq) = 0; }; @@ -242,6 +243,8 @@ class CoreEnd2endTest : public ::testing::Test { grpc_metadata_array{0, 0, nullptr}); }; + class IncomingCall; + // Receiving container for one incoming message. class IncomingMessage final : public CqVerifier::SuccessfulStateString { public: @@ -270,6 +273,7 @@ class CoreEnd2endTest : public ::testing::Test { grpc_op MakeOp(); private: + friend class IncomingCall; grpc_byte_buffer* payload_ = nullptr; }; @@ -504,6 +508,8 @@ class CoreEnd2endTest : public ::testing::Test { class IncomingCall { public: IncomingCall(CoreEnd2endTest& test, int tag); + IncomingCall(CoreEnd2endTest& test, void* method, IncomingMessage* message, + int tag); IncomingCall(const IncomingCall&) = delete; IncomingCall& operator=(const IncomingCall&) = delete; IncomingCall(IncomingCall&&) noexcept = default; @@ -561,6 +567,24 @@ class CoreEnd2endTest : public ::testing::Test { std::unique_ptr impl_; }; + class ServerRegisteredMethod { + public: + ServerRegisteredMethod( + CoreEnd2endTest* test, absl::string_view name, + grpc_server_register_method_payload_handling payload_handling); + + void* handle() { return *handle_; } + + private: + std::shared_ptr handle_ = std::make_shared(nullptr); + }; + + ServerRegisteredMethod RegisterServerMethod( + absl::string_view name, + grpc_server_register_method_payload_handling payload_handling) { + return ServerRegisteredMethod(this, name, payload_handling); + } + // Begin construction of a client call. ClientCallBuilder NewClientCall(std::string method) { return ClientCallBuilder(*this, std::move(method)); @@ -570,6 +594,14 @@ class CoreEnd2endTest : public ::testing::Test { } // Request a call on the server - notifies `tag` when complete. IncomingCall RequestCall(int tag) { return IncomingCall(*this, tag); } + // Request a call on the server - notifies `tag` when complete. + IncomingCall RequestRegisteredCall(ServerRegisteredMethod method, int tag) { + return IncomingCall(*this, method.handle(), nullptr, tag); + } + IncomingCall RequestRegisteredCall(ServerRegisteredMethod method, + IncomingMessage* message, int tag) { + return IncomingCall(*this, method.handle(), message, tag); + } // Pull in CqVerifier types for ergonomics // TODO(ctiller): evaluate just dropping CqVerifier and folding it in here. @@ -616,7 +648,7 @@ class CoreEnd2endTest : public ::testing::Test { initialized_ = true; if (server_ != nullptr) ShutdownAndDestroyServer(); auto& f = fixture(); - server_ = f.MakeServer(args, cq_); + server_ = f.MakeServer(args, cq_, pre_server_start_); GPR_ASSERT(server_ != nullptr); } // Remove the client. @@ -730,6 +762,8 @@ class CoreEnd2endTest : public ::testing::Test { grpc_server* server_ = nullptr; grpc_channel* client_ = nullptr; std::unique_ptr cq_verifier_; + absl::AnyInvocable pre_server_start_ = [](grpc_server*) { + }; int expectations_ = 0; bool initialized_ = false; absl::AnyInvocable post_grpc_init_func_ = []() {}; @@ -755,6 +789,8 @@ class CoreLargeSendTest : public CoreEnd2endTest {}; class CoreClientChannelTest : public CoreEnd2endTest {}; // Test suite for tests that require deadline handling class CoreDeadlineTest : public CoreEnd2endTest {}; +// Test suite for tests that require deadline handling +class CoreDeadlineSingleHopTest : public CoreEnd2endTest {}; // Test suite for http2 tests that only work over a single hop (unproxyable) class Http2SingleHopTest : public CoreEnd2endTest {}; // Test suite for tests that require retry features diff --git a/test/core/end2end/fixtures/inproc_fixture.h b/test/core/end2end/fixtures/inproc_fixture.h index 72ef99c061c..aea3de38036 100644 --- a/test/core/end2end/fixtures/inproc_fixture.h +++ b/test/core/end2end/fixtures/inproc_fixture.h @@ -15,6 +15,8 @@ #ifndef GRPC_TEST_CORE_END2END_FIXTURES_INPROC_FIXTURE_H #define GRPC_TEST_CORE_END2END_FIXTURES_INPROC_FIXTURE_H +#include "absl/functional/any_invocable.h" + #include #include "src/core/ext/transport/inproc/inproc_transport.h" @@ -23,18 +25,25 @@ class InprocFixture : public grpc_core::CoreTestFixture { private: - grpc_server* MakeServer(const grpc_core::ChannelArgs& args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const grpc_core::ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { if (made_server_ != nullptr) return made_server_; made_server_ = grpc_server_create(args.ToC().get(), nullptr); grpc_server_register_completion_queue(made_server_, cq, nullptr); + pre_server_start(made_server_); grpc_server_start(made_server_); return made_server_; } grpc_channel* MakeClient(const grpc_core::ChannelArgs& args, grpc_completion_queue* cq) override { - return grpc_inproc_channel_create(MakeServer(args, cq), args.ToC().get(), - nullptr); + // Registered method registration isn't going to work for tests that create + // the client first and use inproc transports. + absl::AnyInvocable + not_sure_what_to_do_but_this_works_for_now = [](grpc_server*) {}; + return grpc_inproc_channel_create( + MakeServer(args, cq, not_sure_what_to_do_but_this_works_for_now), + args.ToC().get(), nullptr); } grpc_server* made_server_ = nullptr; diff --git a/test/core/end2end/fixtures/local_util.cc b/test/core/end2end/fixtures/local_util.cc index e91c5e193fe..7cb814de9e2 100644 --- a/test/core/end2end/fixtures/local_util.cc +++ b/test/core/end2end/fixtures/local_util.cc @@ -39,8 +39,9 @@ LocalTestFixture::LocalTestFixture(std::string localaddr, grpc_local_connect_type type) : localaddr_(std::move(localaddr)), type_(type) {} -grpc_server* LocalTestFixture::MakeServer(const grpc_core::ChannelArgs& args, - grpc_completion_queue* cq) { +grpc_server* LocalTestFixture::MakeServer( + const grpc_core::ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) { grpc_server_credentials* server_creds = grpc_local_server_credentials_create(type_); auto* server = grpc_server_create(args.ToC().get(), nullptr); @@ -54,6 +55,7 @@ grpc_server* LocalTestFixture::MakeServer(const grpc_core::ChannelArgs& args, GPR_ASSERT( grpc_server_add_http2_port(server, localaddr_.c_str(), server_creds)); grpc_server_credentials_release(server_creds); + pre_server_start(server); grpc_server_start(server); return server; } diff --git a/test/core/end2end/fixtures/local_util.h b/test/core/end2end/fixtures/local_util.h index 836444cf8b4..fc9f8d8af5c 100644 --- a/test/core/end2end/fixtures/local_util.h +++ b/test/core/end2end/fixtures/local_util.h @@ -21,6 +21,8 @@ #include +#include "absl/functional/any_invocable.h" + #include #include @@ -32,8 +34,9 @@ class LocalTestFixture final : public grpc_core::CoreTestFixture { LocalTestFixture(std::string localaddr, grpc_local_connect_type type); private: - grpc_server* MakeServer(const grpc_core::ChannelArgs& args, - grpc_completion_queue* cq) override; + grpc_server* MakeServer( + const grpc_core::ChannelArgs& args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override; grpc_channel* MakeClient(const grpc_core::ChannelArgs& args, grpc_completion_queue* cq) override; diff --git a/test/core/end2end/fixtures/secure_fixture.h b/test/core/end2end/fixtures/secure_fixture.h index 31b1112d4b0..d047e712d21 100644 --- a/test/core/end2end/fixtures/secure_fixture.h +++ b/test/core/end2end/fixtures/secure_fixture.h @@ -18,6 +18,8 @@ #include #include +#include "absl/functional/any_invocable.h" + #include #include #include @@ -49,14 +51,16 @@ class SecureFixture : public grpc_core::CoreTestFixture { virtual grpc_core::ChannelArgs MutateServerArgs(grpc_core::ChannelArgs args) { return args; } - grpc_server* MakeServer(const grpc_core::ChannelArgs& in_args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const grpc_core::ChannelArgs& in_args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { auto args = MutateServerArgs(in_args); auto* creds = MakeServerCreds(args); auto* server = grpc_server_create(args.ToC().get(), nullptr); grpc_server_register_completion_queue(server, cq, nullptr); GPR_ASSERT(grpc_server_add_http2_port(server, localaddr_.c_str(), creds)); grpc_server_credentials_release(creds); + pre_server_start(server); grpc_server_start(server); return server; } diff --git a/test/core/end2end/fixtures/sockpair_fixture.h b/test/core/end2end/fixtures/sockpair_fixture.h index 8aa1f715c2e..ce6d8e225e7 100644 --- a/test/core/end2end/fixtures/sockpair_fixture.h +++ b/test/core/end2end/fixtures/sockpair_fixture.h @@ -17,6 +17,7 @@ #include +#include "absl/functional/any_invocable.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "gtest/gtest.h" @@ -66,13 +67,15 @@ class SockpairFixture : public CoreTestFixture { private: virtual ChannelArgs MutateClientArgs(ChannelArgs args) { return args; } virtual ChannelArgs MutateServerArgs(ChannelArgs args) { return args; } - grpc_server* MakeServer(const ChannelArgs& in_args, - grpc_completion_queue* cq) override { + grpc_server* MakeServer( + const ChannelArgs& in_args, grpc_completion_queue* cq, + absl::AnyInvocable& pre_server_start) override { auto args = MutateServerArgs(in_args); ExecCtx exec_ctx; grpc_transport* transport; auto* server = grpc_server_create(args.ToC().get(), nullptr); grpc_server_register_completion_queue(server, cq, nullptr); + pre_server_start(server); grpc_server_start(server); auto server_channel_args = CoreConfiguration::Get() .channel_args_preconditioning() diff --git a/test/core/end2end/h2_ssl_cert_test.cc b/test/core/end2end/h2_ssl_cert_test.cc index a3495a6f9ec..7b2d4175ed6 100644 --- a/test/core/end2end/h2_ssl_cert_test.cc +++ b/test/core/end2end/h2_ssl_cert_test.cc @@ -23,6 +23,7 @@ #include #include +#include "absl/functional/any_invocable.h" #include "absl/types/optional.h" #include "gtest/gtest.h" @@ -203,7 +204,9 @@ static void simple_request_body(grpc_core::CoreTestFixture* f, grpc_call_error error; grpc_channel* client = f->MakeClient(grpc_core::ChannelArgs(), cq); - grpc_server* server = f->MakeServer(grpc_core::ChannelArgs(), cq); + absl::AnyInvocable pre_start_server = [](grpc_server*) {}; + grpc_server* server = + f->MakeServer(grpc_core::ChannelArgs(), cq, pre_start_server); grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr:1234"); c = grpc_channel_create_call(client, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, diff --git a/test/core/end2end/tests/timeout_before_request_call.cc b/test/core/end2end/tests/timeout_before_request_call.cc new file mode 100644 index 00000000000..051d2cdacb8 --- /dev/null +++ b/test/core/end2end/tests/timeout_before_request_call.cc @@ -0,0 +1,173 @@ +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +#include "gtest/gtest.h" + +#include +#include +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gprpp/time.h" +#include "src/core/lib/slice/slice.h" +#include "test/core/end2end/end2end_tests.h" + +namespace grpc_core { +namespace { + +CORE_END2END_TEST(CoreDeadlineTest, TimeoutBeforeRequestCall) { + auto c = NewClientCall("/foo").Timeout(Duration::Seconds(1)).Create(); + CoreEnd2endTest::IncomingStatusOnClient server_status; + CoreEnd2endTest::IncomingMetadata server_initial_metadata; + c.NewBatch(1) + .SendInitialMetadata({}) + .SendCloseFromClient() + .RecvInitialMetadata(server_initial_metadata) + .RecvStatusOnClient(server_status); + Expect(1, true); + Step(); + EXPECT_EQ(server_status.status(), GRPC_STATUS_DEADLINE_EXCEEDED); + auto s = RequestCall(2); + bool got_call = false; + std::unique_ptr client_close; + Expect(2, MaybePerformAction{[this, &s, &got_call, &client_close](bool ok) { + got_call = true; + if (ok) { + // If we successfully get a call, then we should additionally get a + // close tag. + client_close = std::make_unique(); + s.NewBatch(3).RecvCloseOnServer(*client_close); + Expect(3, true); + } + }}); + Step(); + if (client_close != nullptr) { + // If we got a close op then it should indicate cancelled. + EXPECT_TRUE(got_call); + EXPECT_TRUE(client_close->was_cancelled()); + } + if (!got_call) { + // Maybe we didn't get a call (didn't reach the server pre-deadline). + // In that case we should get a failed call back on shutdown. + ShutdownServerAndNotify(4); + Expect(2, false); + Expect(4, true); + Step(); + } +} + +CORE_END2END_TEST(CoreDeadlineTest, + TimeoutBeforeRequestCallWithRegisteredMethod) { + auto method = RegisterServerMethod("/foo", GRPC_SRM_PAYLOAD_NONE); + + auto c = NewClientCall("/foo").Timeout(Duration::Seconds(1)).Create(); + CoreEnd2endTest::IncomingStatusOnClient server_status; + CoreEnd2endTest::IncomingMetadata server_initial_metadata; + c.NewBatch(1) + .SendInitialMetadata({}) + .SendCloseFromClient() + .RecvInitialMetadata(server_initial_metadata) + .RecvStatusOnClient(server_status); + Expect(1, true); + Step(); + EXPECT_EQ(server_status.status(), GRPC_STATUS_DEADLINE_EXCEEDED); + auto s = RequestRegisteredCall(method, 2); + bool got_call = false; + std::unique_ptr client_close; + Expect(2, MaybePerformAction{[this, &s, &got_call, &client_close](bool ok) { + got_call = true; + if (ok) { + // If we successfully get a call, then we should additionally get a + // close tag. + client_close = std::make_unique(); + s.NewBatch(3).RecvCloseOnServer(*client_close); + Expect(3, true); + } + }}); + Step(); + if (client_close != nullptr) { + // If we got a close op then it should indicate cancelled. + EXPECT_TRUE(got_call); + EXPECT_TRUE(client_close->was_cancelled()); + } + if (!got_call) { + // Maybe we didn't get a call (didn't reach the server pre-deadline). + // In that case we should get a failed call back on shutdown. + ShutdownServerAndNotify(4); + Expect(2, false); + Expect(4, true); + Step(); + } +} + +CORE_END2END_TEST(CoreDeadlineSingleHopTest, + TimeoutBeforeRequestCallWithRegisteredMethodWithPayload) { + auto method = + RegisterServerMethod("/foo", GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER); + + const size_t kMessageSize = 10 * 1024 * 1024; + auto send_from_client = RandomSlice(kMessageSize); + InitServer( + ChannelArgs().Set(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, kMessageSize)); + InitClient( + ChannelArgs().Set(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, kMessageSize)); + + auto c = NewClientCall("/foo").Timeout(Duration::Seconds(1)).Create(); + CoreEnd2endTest::IncomingStatusOnClient server_status; + CoreEnd2endTest::IncomingMetadata server_initial_metadata; + c.NewBatch(1) + .SendInitialMetadata({}) + .SendCloseFromClient() + .SendMessage(send_from_client.Ref()) + .RecvInitialMetadata(server_initial_metadata) + .RecvStatusOnClient(server_status); + Expect(1, true); + Step(); + EXPECT_EQ(server_status.status(), GRPC_STATUS_DEADLINE_EXCEEDED); + IncomingMessage client_message; + auto s = RequestRegisteredCall(method, &client_message, 2); + bool got_call = false; + std::unique_ptr client_close; + Expect(2, MaybePerformAction{[this, &s, &got_call, &client_close](bool ok) { + got_call = true; + if (ok) { + // If we successfully get a call, then we should additionally get a + // close tag. + client_close = std::make_unique(); + s.NewBatch(3).RecvCloseOnServer(*client_close); + Expect(3, true); + } + }}); + Step(); + if (client_close != nullptr) { + // If we got a close op then it should indicate cancelled. + EXPECT_TRUE(got_call); + EXPECT_TRUE(client_close->was_cancelled()); + } + if (!got_call) { + // Maybe we didn't get a call (didn't reach the server pre-deadline). + // In that case we should get a failed call back on shutdown. + ShutdownServerAndNotify(4); + Expect(2, false); + Expect(4, true); + Step(); + } +} + +} // namespace +} // namespace grpc_core diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 522d4f3189f..27f82de75ef 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -10491,6 +10491,30 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "timeout_before_request_call_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false,