1 // Copyright 2023 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/ext/transport/chttp2/transport/ping_abuse_policy.h"
16
17 #include <chrono>
18 #include <thread>
19
20 #include "gtest/gtest.h"
21
22 #include <grpc/impl/channel_arg_names.h>
23
24 namespace grpc_core {
25 namespace {
26
TEST(PingAbusePolicy,NoOp)27 TEST(PingAbusePolicy, NoOp) {
28 Chttp2PingAbusePolicy policy{ChannelArgs()};
29 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 2);
30 EXPECT_EQ(policy.TestOnlyMinPingIntervalWithoutData(), Duration::Minutes(5));
31 }
32
TEST(PingAbusePolicy,WithChannelArgs)33 TEST(PingAbusePolicy, WithChannelArgs) {
34 Chttp2PingAbusePolicy policy{
35 ChannelArgs()
36 .Set(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 100)
37 .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, 42)};
38 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 42);
39 EXPECT_EQ(policy.TestOnlyMinPingIntervalWithoutData(),
40 Duration::Milliseconds(100));
41 }
42
TEST(PingAbusePolicy,ChannelArgsRangeCheck)43 TEST(PingAbusePolicy, ChannelArgsRangeCheck) {
44 Chttp2PingAbusePolicy policy{
45 ChannelArgs()
46 .Set(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, -1000)
47 .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, -100)};
48 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 0);
49 EXPECT_EQ(policy.TestOnlyMinPingIntervalWithoutData(), Duration::Zero());
50 }
51
TEST(PingAbusePolicy,BasicOut)52 TEST(PingAbusePolicy, BasicOut) {
53 Chttp2PingAbusePolicy policy{ChannelArgs()};
54 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 2);
55 // First ping ok
56 EXPECT_FALSE(policy.ReceivedOnePing(false));
57 // Strike 1... too soon
58 EXPECT_FALSE(policy.ReceivedOnePing(false));
59 // Strike 2... too soon
60 EXPECT_FALSE(policy.ReceivedOnePing(false));
61 // Strike 3... you're out!
62 EXPECT_TRUE(policy.ReceivedOnePing(false));
63 }
64
TEST(PingAbusePolicy,TimePreventsOut)65 TEST(PingAbusePolicy, TimePreventsOut) {
66 Chttp2PingAbusePolicy policy{ChannelArgs().Set(
67 GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 1000)};
68 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 2);
69 // First ping ok
70 EXPECT_FALSE(policy.ReceivedOnePing(false));
71 // Strike 1... too soon
72 EXPECT_FALSE(policy.ReceivedOnePing(false));
73 // Strike 2... too soon
74 EXPECT_FALSE(policy.ReceivedOnePing(false));
75 // Sleep a bit, allowed
76 std::this_thread::sleep_for(std::chrono::seconds(2));
77 EXPECT_FALSE(policy.ReceivedOnePing(false));
78 }
79
TEST(PingAbusePolicy,TimerSustains)80 TEST(PingAbusePolicy, TimerSustains) {
81 Chttp2PingAbusePolicy policy{ChannelArgs().Set(
82 GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 10)};
83 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 2);
84 for (int i = 0; i < 100; i++) {
85 EXPECT_FALSE(policy.ReceivedOnePing(false));
86 std::this_thread::sleep_for(std::chrono::milliseconds(20));
87 }
88 }
89
TEST(PingAbusePolicy,IdleIncreasesTimeout)90 TEST(PingAbusePolicy, IdleIncreasesTimeout) {
91 Chttp2PingAbusePolicy policy{ChannelArgs().Set(
92 GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 1000)};
93 EXPECT_EQ(policy.TestOnlyMaxPingStrikes(), 2);
94 // First ping ok
95 EXPECT_FALSE(policy.ReceivedOnePing(true));
96 // Strike 1... too soon
97 EXPECT_FALSE(policy.ReceivedOnePing(true));
98 // Strike 2... too soon
99 EXPECT_FALSE(policy.ReceivedOnePing(true));
100 // Sleep a bit, allowed
101 std::this_thread::sleep_for(std::chrono::seconds(2));
102 EXPECT_TRUE(policy.ReceivedOnePing(true));
103 }
104
105 } // namespace
106 } // namespace grpc_core
107
main(int argc,char ** argv)108 int main(int argc, char** argv) {
109 ::testing::InitGoogleTest(&argc, argv);
110 // hardcode expected defaults so we don't account for external configuration
111 grpc_core::Chttp2PingAbusePolicy::SetDefaults(
112 grpc_core::ChannelArgs()
113 .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, 2)
114 .Set(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS,
115 grpc_core::Duration::Minutes(5).millis()));
116 return RUN_ALL_TESTS();
117 }
118