1 // Copyright 2013 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_alarm.h"
6
7 #include "quiche/quic/core/quic_connection_context.h"
8 #include "quiche/quic/platform/api/quic_expect_bug.h"
9 #include "quiche/quic/platform/api/quic_test.h"
10
11 using testing::ElementsAre;
12 using testing::Invoke;
13 using testing::Return;
14
15 namespace quic {
16 namespace test {
17 namespace {
18
19 class TraceCollector : public QuicConnectionTracer {
20 public:
21 ~TraceCollector() override = default;
22
PrintLiteral(const char * literal)23 void PrintLiteral(const char* literal) override { trace_.push_back(literal); }
24
PrintString(absl::string_view s)25 void PrintString(absl::string_view s) override {
26 trace_.push_back(std::string(s));
27 }
28
trace() const29 const std::vector<std::string>& trace() const { return trace_; }
30
31 private:
32 std::vector<std::string> trace_;
33 };
34
35 class MockDelegate : public QuicAlarm::Delegate {
36 public:
37 MOCK_METHOD(QuicConnectionContext*, GetConnectionContext, (), (override));
38 MOCK_METHOD(void, OnAlarm, (), (override));
39 };
40
41 class DestructiveDelegate : public QuicAlarm::DelegateWithoutContext {
42 public:
DestructiveDelegate()43 DestructiveDelegate() : alarm_(nullptr) {}
44
set_alarm(QuicAlarm * alarm)45 void set_alarm(QuicAlarm* alarm) { alarm_ = alarm; }
46
OnAlarm()47 void OnAlarm() override {
48 QUICHE_DCHECK(alarm_);
49 delete alarm_;
50 }
51
52 private:
53 QuicAlarm* alarm_;
54 };
55
56 class TestAlarm : public QuicAlarm {
57 public:
TestAlarm(QuicAlarm::Delegate * delegate)58 explicit TestAlarm(QuicAlarm::Delegate* delegate)
59 : QuicAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate)) {}
60
scheduled() const61 bool scheduled() const { return scheduled_; }
62
FireAlarm()63 void FireAlarm() {
64 scheduled_ = false;
65 Fire();
66 }
67
68 protected:
SetImpl()69 void SetImpl() override {
70 QUICHE_DCHECK(deadline().IsInitialized());
71 scheduled_ = true;
72 }
73
CancelImpl()74 void CancelImpl() override {
75 QUICHE_DCHECK(!deadline().IsInitialized());
76 scheduled_ = false;
77 }
78
79 private:
80 bool scheduled_;
81 };
82
83 class DestructiveAlarm : public QuicAlarm {
84 public:
DestructiveAlarm(DestructiveDelegate * delegate)85 explicit DestructiveAlarm(DestructiveDelegate* delegate)
86 : QuicAlarm(QuicArenaScopedPtr<DestructiveDelegate>(delegate)) {}
87
FireAlarm()88 void FireAlarm() { Fire(); }
89
90 protected:
SetImpl()91 void SetImpl() override {}
92
CancelImpl()93 void CancelImpl() override {}
94 };
95
96 class QuicAlarmTest : public QuicTest {
97 public:
QuicAlarmTest()98 QuicAlarmTest()
99 : delegate_(new MockDelegate()),
100 alarm_(delegate_),
101 deadline_(QuicTime::Zero() + QuicTime::Delta::FromSeconds(7)),
102 deadline2_(QuicTime::Zero() + QuicTime::Delta::FromSeconds(14)),
103 new_deadline_(QuicTime::Zero()) {}
104
ResetAlarm()105 void ResetAlarm() { alarm_.Set(new_deadline_); }
106
107 MockDelegate* delegate_; // not owned
108 TestAlarm alarm_;
109 QuicTime deadline_;
110 QuicTime deadline2_;
111 QuicTime new_deadline_;
112 };
113
TEST_F(QuicAlarmTest,IsSet)114 TEST_F(QuicAlarmTest, IsSet) { EXPECT_FALSE(alarm_.IsSet()); }
115
TEST_F(QuicAlarmTest,Set)116 TEST_F(QuicAlarmTest, Set) {
117 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
118 alarm_.Set(deadline);
119 EXPECT_TRUE(alarm_.IsSet());
120 EXPECT_TRUE(alarm_.scheduled());
121 EXPECT_EQ(deadline, alarm_.deadline());
122 }
123
TEST_F(QuicAlarmTest,Cancel)124 TEST_F(QuicAlarmTest, Cancel) {
125 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
126 alarm_.Set(deadline);
127 alarm_.Cancel();
128 EXPECT_FALSE(alarm_.IsSet());
129 EXPECT_FALSE(alarm_.scheduled());
130 EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
131 }
132
TEST_F(QuicAlarmTest,PermanentCancel)133 TEST_F(QuicAlarmTest, PermanentCancel) {
134 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
135 alarm_.Set(deadline);
136 alarm_.PermanentCancel();
137 EXPECT_FALSE(alarm_.IsSet());
138 EXPECT_FALSE(alarm_.scheduled());
139 EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
140
141 EXPECT_QUIC_BUG(alarm_.Set(deadline),
142 "Set called after alarm is permanently cancelled");
143 EXPECT_TRUE(alarm_.IsPermanentlyCancelled());
144 EXPECT_FALSE(alarm_.IsSet());
145 EXPECT_FALSE(alarm_.scheduled());
146 EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
147
148 EXPECT_QUIC_BUG(alarm_.Update(deadline, QuicTime::Delta::Zero()),
149 "Update called after alarm is permanently cancelled");
150 EXPECT_TRUE(alarm_.IsPermanentlyCancelled());
151 EXPECT_FALSE(alarm_.IsSet());
152 EXPECT_FALSE(alarm_.scheduled());
153 EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
154 }
155
TEST_F(QuicAlarmTest,Update)156 TEST_F(QuicAlarmTest, Update) {
157 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
158 alarm_.Set(deadline);
159 QuicTime new_deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(8);
160 alarm_.Update(new_deadline, QuicTime::Delta::Zero());
161 EXPECT_TRUE(alarm_.IsSet());
162 EXPECT_TRUE(alarm_.scheduled());
163 EXPECT_EQ(new_deadline, alarm_.deadline());
164 }
165
TEST_F(QuicAlarmTest,UpdateWithZero)166 TEST_F(QuicAlarmTest, UpdateWithZero) {
167 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
168 alarm_.Set(deadline);
169 alarm_.Update(QuicTime::Zero(), QuicTime::Delta::Zero());
170 EXPECT_FALSE(alarm_.IsSet());
171 EXPECT_FALSE(alarm_.scheduled());
172 EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
173 }
174
TEST_F(QuicAlarmTest,Fire)175 TEST_F(QuicAlarmTest, Fire) {
176 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
177 alarm_.Set(deadline);
178 EXPECT_CALL(*delegate_, OnAlarm());
179 alarm_.FireAlarm();
180 EXPECT_FALSE(alarm_.IsSet());
181 EXPECT_FALSE(alarm_.scheduled());
182 EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
183 }
184
TEST_F(QuicAlarmTest,FireAndResetViaSet)185 TEST_F(QuicAlarmTest, FireAndResetViaSet) {
186 alarm_.Set(deadline_);
187 new_deadline_ = deadline2_;
188 EXPECT_CALL(*delegate_, OnAlarm())
189 .WillOnce(Invoke(this, &QuicAlarmTest::ResetAlarm));
190 alarm_.FireAlarm();
191 EXPECT_TRUE(alarm_.IsSet());
192 EXPECT_TRUE(alarm_.scheduled());
193 EXPECT_EQ(deadline2_, alarm_.deadline());
194 }
195
TEST_F(QuicAlarmTest,FireDestroysAlarm)196 TEST_F(QuicAlarmTest, FireDestroysAlarm) {
197 DestructiveDelegate* delegate(new DestructiveDelegate);
198 DestructiveAlarm* alarm = new DestructiveAlarm(delegate);
199 delegate->set_alarm(alarm);
200 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
201 alarm->Set(deadline);
202 // This should not crash, even though it will destroy alarm.
203 alarm->FireAlarm();
204 }
205
TEST_F(QuicAlarmTest,NullAlarmContext)206 TEST_F(QuicAlarmTest, NullAlarmContext) {
207 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
208 alarm_.Set(deadline);
209
210 EXPECT_CALL(*delegate_, GetConnectionContext()).WillOnce(Return(nullptr));
211
212 EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Invoke([] {
213 QUIC_TRACELITERAL("Alarm fired.");
214 }));
215 alarm_.FireAlarm();
216 }
217
TEST_F(QuicAlarmTest,AlarmContextWithNullTracer)218 TEST_F(QuicAlarmTest, AlarmContextWithNullTracer) {
219 QuicConnectionContext context;
220 ASSERT_EQ(context.tracer, nullptr);
221
222 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
223 alarm_.Set(deadline);
224
225 EXPECT_CALL(*delegate_, GetConnectionContext()).WillOnce(Return(&context));
226
227 EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Invoke([] {
228 QUIC_TRACELITERAL("Alarm fired.");
229 }));
230 alarm_.FireAlarm();
231 }
232
TEST_F(QuicAlarmTest,AlarmContextWithTracer)233 TEST_F(QuicAlarmTest, AlarmContextWithTracer) {
234 QuicConnectionContext context;
235 std::unique_ptr<TraceCollector> tracer = std::make_unique<TraceCollector>();
236 const TraceCollector& tracer_ref = *tracer;
237 context.tracer = std::move(tracer);
238
239 QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
240 alarm_.Set(deadline);
241
242 EXPECT_CALL(*delegate_, GetConnectionContext()).WillOnce(Return(&context));
243
244 EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Invoke([] {
245 QUIC_TRACELITERAL("Alarm fired.");
246 }));
247
248 // Since |context| is not installed in the current thread, the messages before
249 // and after FireAlarm() should not be collected by |tracer|.
250 QUIC_TRACELITERAL("Should not be collected before alarm.");
251 alarm_.FireAlarm();
252 QUIC_TRACELITERAL("Should not be collected after alarm.");
253
254 EXPECT_THAT(tracer_ref.trace(), ElementsAre("Alarm fired."));
255 }
256
257 } // namespace
258 } // namespace test
259 } // namespace quic
260