21 #include <arpa/inet.h>
24 #include <netinet/in.h>
25 #include <netinet/tcp.h>
35 #include "absl/flags/flag.h"
36 #include "absl/time/time.h"
48 #include "src/proto/grpc/testing/empty.pb.h"
49 #include "src/proto/grpc/testing/messages.pb.h"
50 #include "src/proto/grpc/testing/test.grpc.pb.h"
51 #include "src/proto/grpc/testing/test.pb.h"
56 "User provided credentials type.");
59 "Shell command to induce fallback, e.g. by unrouting addresses");
60 ABSL_FLAG(
int, fallback_deadline_seconds, 1,
61 "Number of seconds to wait for fallback to occur after inducing it");
63 "Test case to run. Valid options are:\n\n"
64 "fallback_before_startup : fallback before making RPCs to backends"
65 "fallback_after_startup : fallback after making RPCs to backends");
67 #ifdef LINUX_VERSION_CODE
68 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
69 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT
73 #ifdef SOCKET_SUPPORTS_TCP_USER_TIMEOUT
74 using grpc::testing::GrpclbRouteType;
77 using grpc::testing::TestService;
86 GrpclbRouteType DoRPCAndGetPath(TestService::Stub*
stub,
int deadline_seconds,
89 deadline_seconds, rpc_mode);
93 if (rpc_mode == WaitForReady) {
96 request.set_fill_grpclb_route_type(
true);
103 s.error_message().c_str());
104 return GrpclbRouteType::GRPCLB_ROUTE_TYPE_UNKNOWN;
107 GrpclbRouteType::GRPCLB_ROUTE_TYPE_BACKEND ||
109 GrpclbRouteType::GRPCLB_ROUTE_TYPE_FALLBACK);
112 return response.grpclb_route_type();
115 GrpclbRouteType DoRPCAndGetPath(TestService::Stub*
stub,
int deadline_seconds) {
116 return DoRPCAndGetPath(
stub, deadline_seconds, FailFast);
119 GrpclbRouteType DoWaitForReadyRPCAndGetPath(TestService::Stub*
stub,
120 int deadline_seconds) {
121 return DoRPCAndGetPath(
stub, deadline_seconds, WaitForReady);
126 gpr_log(
GPR_INFO,
"Setting socket option TCP_USER_TIMEOUT on fd: %d", fd);
127 if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &
timeout,
133 socklen_t
len =
sizeof(newval);
134 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &
len) ||
136 gpr_log(
GPR_ERROR,
"Failed to get expected socket option TCP_USER_TIMEOUT");
151 TcpUserTimeoutDestroy,
nullptr};
153 std::unique_ptr<TestService::Stub> CreateFallbackTestStub() {
157 &kTcpUserTimeoutMutatorVtable);
161 std::shared_ptr<grpc::ChannelCredentials> channel_creds =
163 absl::GetFlag(FLAGS_custom_credentials_type), &channel_args);
165 absl::GetFlag(FLAGS_server_uri), channel_creds, channel_args));
171 if (WIFEXITED(
out)) {
184 void WaitForFallbackAndDoRPCs(TestService::Stub*
stub) {
185 int fallback_retry_count = 0;
186 bool fallback =
false;
190 while (
absl::Now() < fallback_deadline) {
191 GrpclbRouteType grpclb_route_type = DoRPCAndGetPath(
stub, 1);
192 if (grpclb_route_type == GrpclbRouteType::GRPCLB_ROUTE_TYPE_BACKEND) {
194 "Got grpclb route type backend. Backends are "
195 "supposed to be unreachable, so this test is broken");
198 if (grpclb_route_type == GrpclbRouteType::GRPCLB_ROUTE_TYPE_FALLBACK) {
200 "Made one successful RPC to a fallback. Now expect the same for "
206 fallback_retry_count);
208 fallback_retry_count++;
214 for (
int i = 0;
i < 30;
i++) {
215 GrpclbRouteType grpclb_route_type = DoRPCAndGetPath(
stub, 20);
217 GrpclbRouteType::GRPCLB_ROUTE_TYPE_FALLBACK);
222 void DoFallbackBeforeStartupTest() {
223 std::unique_ptr<TestService::Stub>
stub = CreateFallbackTestStub();
225 WaitForFallbackAndDoRPCs(
stub.get());
228 void DoFallbackAfterStartupTest() {
229 std::unique_ptr<TestService::Stub>
stub = CreateFallbackTestStub();
230 GrpclbRouteType grpclb_route_type = DoRPCAndGetPath(
stub.get(), 20);
231 GPR_ASSERT(grpclb_route_type == GrpclbRouteType::GRPCLB_ROUTE_TYPE_BACKEND);
233 WaitForFallbackAndDoRPCs(
stub.get());
238 int main(
int argc,
char** argv) {
241 if (
absl::GetFlag(FLAGS_test_case) ==
"fallback_before_startup") {
242 DoFallbackBeforeStartupTest();
244 }
else if (
absl::GetFlag(FLAGS_test_case) ==
"fallback_after_startup") {
245 DoFallbackAfterStartupTest();
256 int main(
int argc,
char** argv) {
259 "This test requires TCP_USER_TIMEOUT, which isn't available");
263 #endif // SOCKET_SUPPORTS_TCP_USER_TIMEOUT