1 // Copyright (c) 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/quic_ping_manager.h"
6
7 #include "quiche/quic/core/quic_one_block_arena.h"
8 #include "quiche/quic/platform/api/quic_test.h"
9 #include "quiche/quic/test_tools/quic_test_utils.h"
10
11 namespace quic {
12 namespace test {
13
14 class QuicPingManagerPeer {
15 public:
GetAlarm(QuicPingManager * manager)16 static QuicAlarm* GetAlarm(QuicPingManager* manager) {
17 return manager->alarm_.get();
18 }
19
SetPerspective(QuicPingManager * manager,Perspective perspective)20 static void SetPerspective(QuicPingManager* manager,
21 Perspective perspective) {
22 manager->perspective_ = perspective;
23 }
24 };
25
26 namespace {
27
28 const bool kShouldKeepAlive = true;
29 const bool kHasInflightPackets = true;
30
31 class MockDelegate : public QuicPingManager::Delegate {
32 public:
33 MOCK_METHOD(void, OnKeepAliveTimeout, (), (override));
34 MOCK_METHOD(void, OnRetransmittableOnWireTimeout, (), (override));
35 };
36
37 class QuicPingManagerTest : public QuicTest {
38 public:
QuicPingManagerTest()39 QuicPingManagerTest()
40 : manager_(Perspective::IS_CLIENT, &delegate_, &arena_, &alarm_factory_,
41 /*context=*/nullptr),
42 alarm_(static_cast<MockAlarmFactory::TestAlarm*>(
43 QuicPingManagerPeer::GetAlarm(&manager_))) {
44 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
45 }
46
47 protected:
48 testing::StrictMock<MockDelegate> delegate_;
49 MockClock clock_;
50 QuicConnectionArena arena_;
51 MockAlarmFactory alarm_factory_;
52 QuicPingManager manager_;
53 MockAlarmFactory::TestAlarm* alarm_;
54 };
55
TEST_F(QuicPingManagerTest,KeepAliveTimeout)56 TEST_F(QuicPingManagerTest, KeepAliveTimeout) {
57 EXPECT_FALSE(alarm_->IsSet());
58
59 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
60 // Set alarm with in flight packets.
61 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
62 kHasInflightPackets);
63 EXPECT_TRUE(alarm_->IsSet());
64 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
65 alarm_->deadline() - clock_.ApproximateNow());
66
67 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
68 // Reset alarm with no in flight packets.
69 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
70 !kHasInflightPackets);
71 EXPECT_TRUE(alarm_->IsSet());
72 // Verify the deadline is set slightly less than 15 seconds in the future,
73 // because of the 1s alarm granularity.
74 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs) -
75 QuicTime::Delta::FromMilliseconds(5),
76 alarm_->deadline() - clock_.ApproximateNow());
77
78 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kPingTimeoutSecs));
79 EXPECT_CALL(delegate_, OnKeepAliveTimeout());
80 alarm_->Fire();
81 EXPECT_FALSE(alarm_->IsSet());
82 // Reset alarm with in flight packets.
83 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
84 kHasInflightPackets);
85 EXPECT_TRUE(alarm_->IsSet());
86
87 // Verify alarm is not armed if !kShouldKeepAlive.
88 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
89 manager_.SetAlarm(clock_.ApproximateNow(), !kShouldKeepAlive,
90 kHasInflightPackets);
91 EXPECT_FALSE(alarm_->IsSet());
92 }
93
TEST_F(QuicPingManagerTest,CustomizedKeepAliveTimeout)94 TEST_F(QuicPingManagerTest, CustomizedKeepAliveTimeout) {
95 EXPECT_FALSE(alarm_->IsSet());
96
97 // Set customized keep-alive timeout.
98 manager_.set_keep_alive_timeout(QuicTime::Delta::FromSeconds(10));
99
100 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
101 // Set alarm with in flight packets.
102 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
103 kHasInflightPackets);
104 EXPECT_TRUE(alarm_->IsSet());
105 EXPECT_EQ(QuicTime::Delta::FromSeconds(10),
106 alarm_->deadline() - clock_.ApproximateNow());
107
108 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
109 // Set alarm with no in flight packets.
110 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
111 !kHasInflightPackets);
112 EXPECT_TRUE(alarm_->IsSet());
113 // The deadline is set slightly less than 10 seconds in the future, because
114 // of the 1s alarm granularity.
115 EXPECT_EQ(
116 QuicTime::Delta::FromSeconds(10) - QuicTime::Delta::FromMilliseconds(5),
117 alarm_->deadline() - clock_.ApproximateNow());
118
119 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
120 EXPECT_CALL(delegate_, OnKeepAliveTimeout());
121 alarm_->Fire();
122 EXPECT_FALSE(alarm_->IsSet());
123 // Reset alarm with in flight packets.
124 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
125 kHasInflightPackets);
126 EXPECT_TRUE(alarm_->IsSet());
127
128 // Verify alarm is not armed if !kShouldKeepAlive.
129 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
130 manager_.SetAlarm(clock_.ApproximateNow(), !kShouldKeepAlive,
131 kHasInflightPackets);
132 EXPECT_FALSE(alarm_->IsSet());
133 }
134
TEST_F(QuicPingManagerTest,RetransmittableOnWireTimeout)135 TEST_F(QuicPingManagerTest, RetransmittableOnWireTimeout) {
136 const QuicTime::Delta kRtransmittableOnWireTimeout =
137 QuicTime::Delta::FromMilliseconds(50);
138 manager_.set_initial_retransmittable_on_wire_timeout(
139 kRtransmittableOnWireTimeout);
140
141 EXPECT_FALSE(alarm_->IsSet());
142
143 // Set alarm with in flight packets.
144 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
145 kHasInflightPackets);
146 // Verify alarm is in keep-alive mode.
147 EXPECT_TRUE(alarm_->IsSet());
148 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
149 alarm_->deadline() - clock_.ApproximateNow());
150
151 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
152 // Set alarm with no in flight packets.
153 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
154 !kHasInflightPackets);
155 EXPECT_TRUE(alarm_->IsSet());
156 // Verify alarm is in retransmittable-on-wire mode.
157 EXPECT_EQ(kRtransmittableOnWireTimeout,
158 alarm_->deadline() - clock_.ApproximateNow());
159
160 clock_.AdvanceTime(kRtransmittableOnWireTimeout);
161 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
162 alarm_->Fire();
163 EXPECT_FALSE(alarm_->IsSet());
164 // Reset alarm with in flight packets.
165 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
166 kHasInflightPackets);
167 // Verify the alarm is in keep-alive mode.
168 ASSERT_TRUE(alarm_->IsSet());
169 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
170 alarm_->deadline() - clock_.ApproximateNow());
171 }
172
TEST_F(QuicPingManagerTest,RetransmittableOnWireTimeoutExponentiallyBackOff)173 TEST_F(QuicPingManagerTest, RetransmittableOnWireTimeoutExponentiallyBackOff) {
174 const int kMaxAggressiveRetransmittableOnWireCount = 5;
175 SetQuicFlag(quic_max_aggressive_retransmittable_on_wire_ping_count,
176 kMaxAggressiveRetransmittableOnWireCount);
177 const QuicTime::Delta initial_retransmittable_on_wire_timeout =
178 QuicTime::Delta::FromMilliseconds(200);
179 manager_.set_initial_retransmittable_on_wire_timeout(
180 initial_retransmittable_on_wire_timeout);
181
182 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
183 EXPECT_FALSE(alarm_->IsSet());
184 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
185 kHasInflightPackets);
186 // Verify alarm is in keep-alive mode.
187 EXPECT_TRUE(alarm_->IsSet());
188 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
189 alarm_->deadline() - clock_.ApproximateNow());
190
191 // Verify no exponential backoff on the first few retransmittable on wire
192 // timeouts.
193 for (int i = 0; i <= kMaxAggressiveRetransmittableOnWireCount; ++i) {
194 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
195 // Reset alarm with no in flight packets.
196 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
197 !kHasInflightPackets);
198 EXPECT_TRUE(alarm_->IsSet());
199 // Verify alarm is in retransmittable-on-wire mode.
200 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
201 alarm_->deadline() - clock_.ApproximateNow());
202 clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
203 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
204 alarm_->Fire();
205 EXPECT_FALSE(alarm_->IsSet());
206 // Reset alarm with in flight packets.
207 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
208 kHasInflightPackets);
209 }
210
211 QuicTime::Delta retransmittable_on_wire_timeout =
212 initial_retransmittable_on_wire_timeout;
213
214 // Verify subsequent retransmittable-on-wire timeout is exponentially backed
215 // off.
216 while (retransmittable_on_wire_timeout * 2 <
217 QuicTime::Delta::FromSeconds(kPingTimeoutSecs)) {
218 retransmittable_on_wire_timeout = retransmittable_on_wire_timeout * 2;
219 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
220 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
221 !kHasInflightPackets);
222 EXPECT_TRUE(alarm_->IsSet());
223 EXPECT_EQ(retransmittable_on_wire_timeout,
224 alarm_->deadline() - clock_.ApproximateNow());
225
226 clock_.AdvanceTime(retransmittable_on_wire_timeout);
227 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
228 alarm_->Fire();
229 EXPECT_FALSE(alarm_->IsSet());
230 // Reset alarm with in flight packets.
231 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
232 kHasInflightPackets);
233 }
234
235 // Verify alarm is in keep-alive mode.
236 EXPECT_TRUE(alarm_->IsSet());
237 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
238 alarm_->deadline() - clock_.ApproximateNow());
239
240 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
241 // Reset alarm with no in flight packets
242 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
243 !kHasInflightPackets);
244 EXPECT_TRUE(alarm_->IsSet());
245 // Verify alarm is in keep-alive mode because retransmittable-on-wire deadline
246 // is later.
247 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs) -
248 QuicTime::Delta::FromMilliseconds(5),
249 alarm_->deadline() - clock_.ApproximateNow());
250 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kPingTimeoutSecs) -
251 QuicTime::Delta::FromMilliseconds(5));
252 EXPECT_CALL(delegate_, OnKeepAliveTimeout());
253 alarm_->Fire();
254 EXPECT_FALSE(alarm_->IsSet());
255 }
256
TEST_F(QuicPingManagerTest,ResetRetransmitableOnWireTimeoutExponentiallyBackOff)257 TEST_F(QuicPingManagerTest,
258 ResetRetransmitableOnWireTimeoutExponentiallyBackOff) {
259 const int kMaxAggressiveRetransmittableOnWireCount = 3;
260 SetQuicFlag(quic_max_aggressive_retransmittable_on_wire_ping_count,
261 kMaxAggressiveRetransmittableOnWireCount);
262 const QuicTime::Delta initial_retransmittable_on_wire_timeout =
263 QuicTime::Delta::FromMilliseconds(200);
264 manager_.set_initial_retransmittable_on_wire_timeout(
265 initial_retransmittable_on_wire_timeout);
266
267 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
268 EXPECT_FALSE(alarm_->IsSet());
269 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
270 kHasInflightPackets);
271 // Verify alarm is in keep-alive mode.
272 EXPECT_TRUE(alarm_->IsSet());
273 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
274 alarm_->deadline() - clock_.ApproximateNow());
275
276 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
277 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
278 !kHasInflightPackets);
279 EXPECT_TRUE(alarm_->IsSet());
280 // Verify alarm is in retransmittable-on-wire mode.
281 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
282 alarm_->deadline() - clock_.ApproximateNow());
283
284 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
285 clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
286 alarm_->Fire();
287
288 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
289 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
290 !kHasInflightPackets);
291 EXPECT_TRUE(alarm_->IsSet());
292 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
293 alarm_->deadline() - clock_.ApproximateNow());
294
295 manager_.reset_consecutive_retransmittable_on_wire_count();
296 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
297 !kHasInflightPackets);
298 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
299 alarm_->deadline() - clock_.ApproximateNow());
300 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
301 clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
302 alarm_->Fire();
303
304 for (int i = 0; i < kMaxAggressiveRetransmittableOnWireCount; i++) {
305 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
306 !kHasInflightPackets);
307 EXPECT_TRUE(alarm_->IsSet());
308 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
309 alarm_->deadline() - clock_.ApproximateNow());
310 clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
311 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
312 alarm_->Fire();
313 // Reset alarm with in flight packets.
314 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
315 kHasInflightPackets);
316 // Advance 5ms to receive next packet.
317 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
318 }
319
320 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
321 !kHasInflightPackets);
322 EXPECT_TRUE(alarm_->IsSet());
323 EXPECT_EQ(initial_retransmittable_on_wire_timeout * 2,
324 alarm_->deadline() - clock_.ApproximateNow());
325
326 clock_.AdvanceTime(2 * initial_retransmittable_on_wire_timeout);
327 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
328 alarm_->Fire();
329
330 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
331 manager_.reset_consecutive_retransmittable_on_wire_count();
332 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
333 !kHasInflightPackets);
334 EXPECT_TRUE(alarm_->IsSet());
335 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
336 alarm_->deadline() - clock_.ApproximateNow());
337 }
338
TEST_F(QuicPingManagerTest,RetransmittableOnWireLimit)339 TEST_F(QuicPingManagerTest, RetransmittableOnWireLimit) {
340 static constexpr int kMaxRetransmittableOnWirePingCount = 3;
341 SetQuicFlag(quic_max_retransmittable_on_wire_ping_count,
342 kMaxRetransmittableOnWirePingCount);
343 static constexpr QuicTime::Delta initial_retransmittable_on_wire_timeout =
344 QuicTime::Delta::FromMilliseconds(200);
345 static constexpr QuicTime::Delta kShortDelay =
346 QuicTime::Delta::FromMilliseconds(5);
347 ASSERT_LT(kShortDelay * 10, initial_retransmittable_on_wire_timeout);
348 manager_.set_initial_retransmittable_on_wire_timeout(
349 initial_retransmittable_on_wire_timeout);
350
351 clock_.AdvanceTime(kShortDelay);
352 EXPECT_FALSE(alarm_->IsSet());
353 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
354 kHasInflightPackets);
355
356 EXPECT_TRUE(alarm_->IsSet());
357 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
358 alarm_->deadline() - clock_.ApproximateNow());
359
360 for (int i = 0; i <= kMaxRetransmittableOnWirePingCount; i++) {
361 clock_.AdvanceTime(kShortDelay);
362 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
363 !kHasInflightPackets);
364 EXPECT_TRUE(alarm_->IsSet());
365 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
366 alarm_->deadline() - clock_.ApproximateNow());
367 clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
368 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
369 alarm_->Fire();
370 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
371 kHasInflightPackets);
372 }
373
374 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
375 !kHasInflightPackets);
376 EXPECT_TRUE(alarm_->IsSet());
377 // Verify alarm is in keep-alive mode.
378 EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
379 alarm_->deadline() - clock_.ApproximateNow());
380 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kPingTimeoutSecs));
381 EXPECT_CALL(delegate_, OnKeepAliveTimeout());
382 alarm_->Fire();
383 EXPECT_FALSE(alarm_->IsSet());
384 }
385
TEST_F(QuicPingManagerTest,MaxRetransmittableOnWireDelayShift)386 TEST_F(QuicPingManagerTest, MaxRetransmittableOnWireDelayShift) {
387 QuicPingManagerPeer::SetPerspective(&manager_, Perspective::IS_SERVER);
388 const int kMaxAggressiveRetransmittableOnWireCount = 3;
389 SetQuicFlag(quic_max_aggressive_retransmittable_on_wire_ping_count,
390 kMaxAggressiveRetransmittableOnWireCount);
391 const QuicTime::Delta initial_retransmittable_on_wire_timeout =
392 QuicTime::Delta::FromMilliseconds(200);
393 manager_.set_initial_retransmittable_on_wire_timeout(
394 initial_retransmittable_on_wire_timeout);
395
396 for (int i = 0; i <= kMaxAggressiveRetransmittableOnWireCount; i++) {
397 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
398 !kHasInflightPackets);
399 EXPECT_TRUE(alarm_->IsSet());
400 EXPECT_EQ(initial_retransmittable_on_wire_timeout,
401 alarm_->deadline() - clock_.ApproximateNow());
402 clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
403 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
404 alarm_->Fire();
405 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
406 kHasInflightPackets);
407 }
408 for (int i = 1; i <= 20; ++i) {
409 manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
410 !kHasInflightPackets);
411 EXPECT_TRUE(alarm_->IsSet());
412 if (i <= 10) {
413 EXPECT_EQ(initial_retransmittable_on_wire_timeout * (1 << i),
414 alarm_->deadline() - clock_.ApproximateNow());
415 } else {
416 // Verify shift is capped.
417 EXPECT_EQ(initial_retransmittable_on_wire_timeout * (1 << 10),
418 alarm_->deadline() - clock_.ApproximateNow());
419 }
420 clock_.AdvanceTime(alarm_->deadline() - clock_.ApproximateNow());
421 EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
422 alarm_->Fire();
423 }
424 }
425
426 } // namespace
427
428 } // namespace test
429 } // namespace quic
430