• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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