1 // Copyright (c) 2020 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_network_blackhole_detector.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 QuicNetworkBlackholeDetectorPeer {
15 public:
GetAlarm(QuicNetworkBlackholeDetector * detector)16 static QuicAlarm* GetAlarm(QuicNetworkBlackholeDetector* detector) {
17 return detector->alarm_.get();
18 }
19 };
20
21 namespace {
22 class MockDelegate : public QuicNetworkBlackholeDetector::Delegate {
23 public:
24 MOCK_METHOD(void, OnPathDegradingDetected, (), (override));
25 MOCK_METHOD(void, OnBlackholeDetected, (), (override));
26 MOCK_METHOD(void, OnPathMtuReductionDetected, (), (override));
27 };
28
29 const size_t kPathDegradingDelayInSeconds = 5;
30 const size_t kPathMtuReductionDelayInSeconds = 7;
31 const size_t kBlackholeDelayInSeconds = 10;
32
33 class QuicNetworkBlackholeDetectorTest : public QuicTest {
34 public:
QuicNetworkBlackholeDetectorTest()35 QuicNetworkBlackholeDetectorTest()
36 : detector_(&delegate_, &arena_, &alarm_factory_, /*context=*/nullptr),
37 alarm_(static_cast<MockAlarmFactory::TestAlarm*>(
38 QuicNetworkBlackholeDetectorPeer::GetAlarm(&detector_))),
39 path_degrading_delay_(
40 QuicTime::Delta::FromSeconds(kPathDegradingDelayInSeconds)),
41 path_mtu_reduction_delay_(
42 QuicTime::Delta::FromSeconds(kPathMtuReductionDelayInSeconds)),
43 blackhole_delay_(
44 QuicTime::Delta::FromSeconds(kBlackholeDelayInSeconds)) {
45 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
46 }
47
48 protected:
RestartDetection()49 void RestartDetection() {
50 detector_.RestartDetection(clock_.Now() + path_degrading_delay_,
51 clock_.Now() + blackhole_delay_,
52 clock_.Now() + path_mtu_reduction_delay_);
53 }
54
55 testing::StrictMock<MockDelegate> delegate_;
56 QuicConnectionArena arena_;
57 MockAlarmFactory alarm_factory_;
58
59 QuicNetworkBlackholeDetector detector_;
60
61 MockAlarmFactory::TestAlarm* alarm_;
62 MockClock clock_;
63 const QuicTime::Delta path_degrading_delay_;
64 const QuicTime::Delta path_mtu_reduction_delay_;
65 const QuicTime::Delta blackhole_delay_;
66 };
67
TEST_F(QuicNetworkBlackholeDetectorTest,StartAndFire)68 TEST_F(QuicNetworkBlackholeDetectorTest, StartAndFire) {
69 EXPECT_FALSE(detector_.IsDetectionInProgress());
70
71 RestartDetection();
72 EXPECT_TRUE(detector_.IsDetectionInProgress());
73 EXPECT_EQ(clock_.Now() + path_degrading_delay_, alarm_->deadline());
74
75 // Fire path degrading alarm.
76 clock_.AdvanceTime(path_degrading_delay_);
77 EXPECT_CALL(delegate_, OnPathDegradingDetected());
78 alarm_->Fire();
79
80 // Verify path mtu reduction detection is still in progress.
81 EXPECT_TRUE(detector_.IsDetectionInProgress());
82 EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_,
83 alarm_->deadline());
84
85 // Fire path mtu reduction detection alarm.
86 clock_.AdvanceTime(path_mtu_reduction_delay_ - path_degrading_delay_);
87 EXPECT_CALL(delegate_, OnPathMtuReductionDetected());
88 alarm_->Fire();
89
90 // Verify blackhole detection is still in progress.
91 EXPECT_TRUE(detector_.IsDetectionInProgress());
92 EXPECT_EQ(clock_.Now() + blackhole_delay_ - path_mtu_reduction_delay_,
93 alarm_->deadline());
94
95 // Fire blackhole detection alarm.
96 clock_.AdvanceTime(blackhole_delay_ - path_mtu_reduction_delay_);
97 EXPECT_CALL(delegate_, OnBlackholeDetected());
98 alarm_->Fire();
99 EXPECT_FALSE(detector_.IsDetectionInProgress());
100 }
101
TEST_F(QuicNetworkBlackholeDetectorTest,RestartAndStop)102 TEST_F(QuicNetworkBlackholeDetectorTest, RestartAndStop) {
103 RestartDetection();
104
105 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
106 RestartDetection();
107 EXPECT_EQ(clock_.Now() + path_degrading_delay_, alarm_->deadline());
108
109 detector_.StopDetection(/*permanent=*/false);
110 EXPECT_FALSE(detector_.IsDetectionInProgress());
111 }
112
TEST_F(QuicNetworkBlackholeDetectorTest,PathDegradingFiresAndRestart)113 TEST_F(QuicNetworkBlackholeDetectorTest, PathDegradingFiresAndRestart) {
114 EXPECT_FALSE(detector_.IsDetectionInProgress());
115 RestartDetection();
116 EXPECT_TRUE(detector_.IsDetectionInProgress());
117 EXPECT_EQ(clock_.Now() + path_degrading_delay_, alarm_->deadline());
118
119 // Fire path degrading alarm.
120 clock_.AdvanceTime(path_degrading_delay_);
121 EXPECT_CALL(delegate_, OnPathDegradingDetected());
122 alarm_->Fire();
123
124 // Verify path mtu reduction detection is still in progress.
125 EXPECT_TRUE(detector_.IsDetectionInProgress());
126 EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_,
127 alarm_->deadline());
128
129 // After 100ms, restart detections on forward progress.
130 clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
131 RestartDetection();
132 // Verify alarm is armed based on path degrading deadline.
133 EXPECT_EQ(clock_.Now() + path_degrading_delay_, alarm_->deadline());
134 }
135
136 } // namespace
137
138 } // namespace test
139 } // namespace quic
140