1 //
2 //
3 // Copyright 2017 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/impl/channel_arg_names.h>
20 #include <grpc/status.h>
21
22 #include <memory>
23
24 #include "gtest/gtest.h"
25 #include "src/core/lib/channel/channel_args.h"
26 #include "src/core/util/time.h"
27 #include "test/core/end2end/end2end_tests.h"
28
29 #define MAX_PING_STRIKES 2
30
31 namespace grpc_core {
32 namespace {
33
34 // Send more pings than server allows to trigger server's GOAWAY.
CORE_END2END_TEST(RetryHttp2Test,BadPing)35 CORE_END2END_TEST(RetryHttp2Test, BadPing) {
36 InitClient(ChannelArgs()
37 .Set(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, 0)
38 .Set(GRPC_ARG_HTTP2_BDP_PROBE, 0));
39 InitServer(ChannelArgs()
40 .Set(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS,
41 Duration::Minutes(5).millis())
42 .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, MAX_PING_STRIKES)
43 .Set(GRPC_ARG_HTTP2_BDP_PROBE, 0));
44 auto c = NewClientCall("/foo").Timeout(Duration::Seconds(10)).Create();
45 IncomingStatusOnClient server_status;
46 IncomingMetadata server_initial_metadata;
47 c.NewBatch(1)
48 .SendInitialMetadata({})
49 .SendCloseFromClient()
50 .RecvInitialMetadata(server_initial_metadata)
51 .RecvStatusOnClient(server_status);
52 auto s = RequestCall(101);
53 Expect(101, true);
54 Step();
55 // Send too many pings to the server to trigger the punishment:
56 // The first ping will let server mark its last_recv time. Afterwards, each
57 // ping will trigger a ping strike, and we need at least MAX_PING_STRIKES
58 // strikes to trigger the punishment. So (MAX_PING_STRIKES + 2) pings are
59 // needed here.
60 int i;
61 for (i = 1; i <= MAX_PING_STRIKES + 2; i++) {
62 PingServerFromClient(200 + i);
63 Expect(200 + i, true);
64 if (i == MAX_PING_STRIKES + 2) {
65 Expect(1, true);
66 }
67 Step();
68 }
69 IncomingCloseOnServer client_close;
70 s.NewBatch(102)
71 .SendInitialMetadata({})
72 .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {})
73 .RecvCloseOnServer(client_close);
74 Expect(102, true);
75 Step();
76 ShutdownServerAndNotify(103);
77 Expect(103, true);
78 Step();
79 // The connection should be closed immediately after the misbehaved pings,
80 // the in-progress RPC should fail.
81 EXPECT_EQ(server_status.status(), GRPC_STATUS_UNAVAILABLE);
82 EXPECT_EQ(s.method(), "/foo");
83 EXPECT_TRUE(client_close.was_cancelled());
84 }
85
86 // Try sending more pings than server allows, but server should be fine because
87 // max_pings_without_data should limit pings sent out on wire.
CORE_END2END_TEST(RetryHttp2Test,PingsWithoutData)88 CORE_END2END_TEST(RetryHttp2Test, PingsWithoutData) {
89 if (IsMaxPingsWoDataThrottleEnabled()) {
90 GTEST_SKIP() << "pings are not limited if this experiment is enabled";
91 }
92 // Only allow MAX_PING_STRIKES pings without data (DATA/HEADERS/WINDOW_UPDATE)
93 // so that the transport will throttle the excess pings.
94 InitClient(ChannelArgs()
95 .Set(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, MAX_PING_STRIKES)
96 .Set(GRPC_ARG_HTTP2_BDP_PROBE, 0));
97 InitServer(ChannelArgs()
98 .Set(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS,
99 Duration::Minutes(5).millis())
100 .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, MAX_PING_STRIKES)
101 .Set(GRPC_ARG_HTTP2_BDP_PROBE, 0));
102 auto c = NewClientCall("/foo").Timeout(Duration::Seconds(10)).Create();
103 IncomingStatusOnClient server_status;
104 IncomingMetadata server_initial_metadata;
105 c.NewBatch(1)
106 .SendInitialMetadata({})
107 .SendCloseFromClient()
108 .RecvInitialMetadata(server_initial_metadata)
109 .RecvStatusOnClient(server_status);
110 auto s = RequestCall(101);
111 Expect(101, true);
112 Step();
113 // Send too many pings to the server similar to the previous test case.
114 // However, since we set the MAX_PINGS_WITHOUT_DATA at the client side, only
115 // MAX_PING_STRIKES will actually be sent and the rpc will still succeed.
116 int i;
117 for (i = 1; i <= MAX_PING_STRIKES + 2; i++) {
118 PingServerFromClient(200 + i);
119 if (i <= MAX_PING_STRIKES) {
120 Expect(200 + i, true);
121 }
122 Step();
123 }
124 IncomingCloseOnServer client_close;
125 s.NewBatch(102)
126 .SendInitialMetadata({})
127 .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {})
128 .RecvCloseOnServer(client_close);
129 Expect(102, true);
130 // Client call should return.
131 Expect(1, true);
132 Step();
133 ShutdownServerAndNotify(103);
134 Expect(103, true);
135 // Also expect the previously blocked pings to complete with an error
136 Expect(200 + MAX_PING_STRIKES + 1, false);
137 Expect(200 + MAX_PING_STRIKES + 2, false);
138 Step();
139 // The rpc should be successful.
140 EXPECT_EQ(server_status.status(), GRPC_STATUS_UNIMPLEMENTED);
141 EXPECT_EQ(s.method(), "/foo");
142 }
143
144 } // namespace
145 } // namespace grpc_core
146