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_rate_policy.h"
16
17 #include <chrono>
18 #include <thread>
19
20 #include "gtest/gtest.h"
21 #include "src/core/lib/experiments/experiments.h"
22
23 namespace grpc_core {
24 namespace {
25
SendGranted()26 Chttp2PingRatePolicy::RequestSendPingResult SendGranted() {
27 return Chttp2PingRatePolicy::SendGranted{};
28 }
29
TooManyRecentPings()30 Chttp2PingRatePolicy::RequestSendPingResult TooManyRecentPings() {
31 return Chttp2PingRatePolicy::TooManyRecentPings{};
32 }
33
TEST(PingRatePolicy,NoOpClient)34 TEST(PingRatePolicy, NoOpClient) {
35 Chttp2PingRatePolicy policy{ChannelArgs(), true};
36 EXPECT_EQ(policy.TestOnlyMaxPingsWithoutData(), 2);
37 }
38
TEST(PingRatePolicy,NoOpServer)39 TEST(PingRatePolicy, NoOpServer) {
40 Chttp2PingRatePolicy policy{ChannelArgs(), false};
41 EXPECT_EQ(policy.TestOnlyMaxPingsWithoutData(), 0);
42 }
43
TEST(PingRatePolicy,ServerCanSendAtStart)44 TEST(PingRatePolicy, ServerCanSendAtStart) {
45 Chttp2PingRatePolicy policy{ChannelArgs(), false};
46 EXPECT_EQ(policy.RequestSendPing(Duration::Milliseconds(100), 0),
47 SendGranted());
48 }
49
TEST(PingRatePolicy,ClientBlockedUntilDataSent)50 TEST(PingRatePolicy, ClientBlockedUntilDataSent) {
51 if (IsMaxPingsWoDataThrottleEnabled()) {
52 GTEST_SKIP()
53 << "Pings are not blocked if max_pings_wo_data_throttle is enabled.";
54 }
55 Chttp2PingRatePolicy policy{ChannelArgs(), true};
56 EXPECT_EQ(policy.RequestSendPing(Duration::Milliseconds(10), 0),
57 TooManyRecentPings());
58 policy.ResetPingsBeforeDataRequired();
59 EXPECT_EQ(policy.RequestSendPing(Duration::Milliseconds(10), 0),
60 SendGranted());
61 policy.SentPing();
62 EXPECT_EQ(policy.RequestSendPing(Duration::Zero(), 0), SendGranted());
63 policy.SentPing();
64 EXPECT_EQ(policy.RequestSendPing(Duration::Zero(), 0), TooManyRecentPings());
65 }
66
TEST(PingRatePolicy,ClientThrottledUntilDataSent)67 TEST(PingRatePolicy, ClientThrottledUntilDataSent) {
68 if (!IsMaxPingsWoDataThrottleEnabled()) {
69 GTEST_SKIP()
70 << "Throttling behavior is enabled with max_pings_wo_data_throttle.";
71 }
72 Chttp2PingRatePolicy policy{ChannelArgs(), true};
73 // First ping is allowed.
74 EXPECT_EQ(policy.RequestSendPing(Duration::Milliseconds(10), 0),
75 SendGranted());
76 policy.SentPing();
77 // Second ping is throttled since no data has been sent.
78 auto result = policy.RequestSendPing(Duration::Zero(), 0);
79 EXPECT_TRUE(absl::holds_alternative<Chttp2PingRatePolicy::TooSoon>(result));
80 EXPECT_EQ(absl::get<Chttp2PingRatePolicy::TooSoon>(result).wait,
81 Duration::Minutes(1));
82 policy.ResetPingsBeforeDataRequired();
83 // After resetting pings before data required (data sent), we can send pings
84 // without being throttled.
85 EXPECT_EQ(policy.RequestSendPing(Duration::Zero(), 0), SendGranted());
86 policy.SentPing();
87 EXPECT_EQ(policy.RequestSendPing(Duration::Zero(), 0), SendGranted());
88 policy.SentPing();
89 // After reaching limit, we are throttled again.
90 result = policy.RequestSendPing(Duration::Zero(), 0);
91 EXPECT_TRUE(absl::holds_alternative<Chttp2PingRatePolicy::TooSoon>(result));
92 EXPECT_EQ(absl::get<Chttp2PingRatePolicy::TooSoon>(result).wait,
93 Duration::Minutes(1));
94 }
95
TEST(PingRatePolicy,RateThrottlingWorks)96 TEST(PingRatePolicy, RateThrottlingWorks) {
97 Chttp2PingRatePolicy policy{ChannelArgs(), false};
98 // Observe that we can fail if we send in a tight loop
99 while (policy.RequestSendPing(Duration::Milliseconds(10), 0) ==
100 SendGranted()) {
101 policy.SentPing();
102 }
103 // Observe that we can succeed if we wait a bit between pings
104 for (int i = 0; i < 100; i++) {
105 std::this_thread::sleep_for(std::chrono::milliseconds(20));
106 EXPECT_EQ(policy.RequestSendPing(Duration::Milliseconds(10), 0),
107 SendGranted());
108 policy.SentPing();
109 }
110 }
111
TEST(PingRatePolicy,TooManyPingsInflightBlocksSendingPings)112 TEST(PingRatePolicy, TooManyPingsInflightBlocksSendingPings) {
113 Chttp2PingRatePolicy policy{ChannelArgs(), false};
114 EXPECT_EQ(policy.RequestSendPing(Duration::Milliseconds(1), 100000000),
115 TooManyRecentPings());
116 }
117
118 } // namespace
119 } // namespace grpc_core
120
main(int argc,char ** argv)121 int main(int argc, char** argv) {
122 ::testing::InitGoogleTest(&argc, argv);
123 return RUN_ALL_TESTS();
124 }
125