1 // Copyright 2014 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 <sys/timerfd.h>
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/file_descriptor_watcher_posix.h"
12 #include "base/location.h"
13 #include "base/macros.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "components/timers/alarm_timer_chromeos.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 // Most of these tests have been lifted right out of timer_unittest.cc with only
24 // cosmetic changes. We want the AlarmTimer to be a drop-in replacement for the
25 // regular Timer so it should pass the same tests as the Timer class.
26 namespace timers {
27 namespace {
28 const base::TimeDelta kTenMilliseconds = base::TimeDelta::FromMilliseconds(10);
29
30 class AlarmTimerTester {
31 public:
AlarmTimerTester(bool * did_run,base::TimeDelta delay,base::OnceClosure quit_closure)32 AlarmTimerTester(bool* did_run,
33 base::TimeDelta delay,
34 base::OnceClosure quit_closure)
35 : did_run_(did_run),
36 quit_closure_(std::move(quit_closure)),
37 delay_(delay),
38 timer_(new timers::SimpleAlarmTimer()) {}
Start()39 void Start() {
40 timer_->Start(
41 FROM_HERE, delay_,
42 base::BindRepeating(&AlarmTimerTester::Run, base::Unretained(this)));
43 }
44
45 private:
Run()46 void Run() {
47 *did_run_ = true;
48 if (quit_closure_)
49 std::move(quit_closure_).Run();
50 }
51
52 bool* did_run_;
53 base::OnceClosure quit_closure_;
54 const base::TimeDelta delay_;
55 std::unique_ptr<timers::SimpleAlarmTimer> timer_;
56
57 DISALLOW_COPY_AND_ASSIGN(AlarmTimerTester);
58 };
59
60 class SelfDeletingAlarmTimerTester {
61 public:
SelfDeletingAlarmTimerTester(bool * did_run,base::TimeDelta delay,base::OnceClosure quit_closure)62 SelfDeletingAlarmTimerTester(bool* did_run,
63 base::TimeDelta delay,
64 base::OnceClosure quit_closure)
65 : did_run_(did_run),
66 quit_closure_(std::move(quit_closure)),
67 delay_(delay),
68 timer_(new timers::SimpleAlarmTimer()) {}
Start()69 void Start() {
70 timer_->Start(FROM_HERE, delay_,
71 base::BindRepeating(&SelfDeletingAlarmTimerTester::Run,
72 base::Unretained(this)));
73 }
74
75 private:
Run()76 void Run() {
77 *did_run_ = true;
78 timer_.reset();
79
80 if (quit_closure_)
81 std::move(quit_closure_).Run();
82 }
83
84 bool* did_run_;
85 base::OnceClosure quit_closure_;
86 const base::TimeDelta delay_;
87 std::unique_ptr<timers::SimpleAlarmTimer> timer_;
88
89 DISALLOW_COPY_AND_ASSIGN(SelfDeletingAlarmTimerTester);
90 };
91
92 } // namespace
93
94 //-----------------------------------------------------------------------------
95 // Each test is run against each type of MessageLoop. That way we are sure
96 // that timers work properly in all configurations.
97
TEST(AlarmTimerTest,SimpleAlarmTimer)98 TEST(AlarmTimerTest, SimpleAlarmTimer) {
99 base::MessageLoopForIO loop;
100 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
101
102 base::RunLoop run_loop;
103 bool did_run = false;
104 AlarmTimerTester f(&did_run, kTenMilliseconds,
105 run_loop.QuitWhenIdleClosure());
106 f.Start();
107
108 run_loop.Run();
109
110 EXPECT_TRUE(did_run);
111 }
112
TEST(AlarmTimerTest,SimpleAlarmTimer_Cancel)113 TEST(AlarmTimerTest, SimpleAlarmTimer_Cancel) {
114 base::MessageLoopForIO loop;
115 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
116
117 bool did_run_a = false;
118 AlarmTimerTester* a =
119 new AlarmTimerTester(&did_run_a, kTenMilliseconds, base::OnceClosure());
120
121 // This should run before the timer expires.
122 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a);
123
124 // Now start the timer.
125 a->Start();
126
127 base::RunLoop run_loop;
128 bool did_run_b = false;
129 AlarmTimerTester b(&did_run_b, kTenMilliseconds,
130 run_loop.QuitWhenIdleClosure());
131 b.Start();
132
133 run_loop.Run();
134
135 EXPECT_FALSE(did_run_a);
136 EXPECT_TRUE(did_run_b);
137 }
138
139 // If underlying timer does not handle this properly, we will crash or fail
140 // in full page heap environment.
TEST(AlarmTimerTest,SelfDeletingAlarmTimer)141 TEST(AlarmTimerTest, SelfDeletingAlarmTimer) {
142 base::MessageLoopForIO loop;
143 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
144
145 base::RunLoop run_loop;
146 bool did_run = false;
147 SelfDeletingAlarmTimerTester f(&did_run, kTenMilliseconds,
148 run_loop.QuitWhenIdleClosure());
149 f.Start();
150
151 run_loop.Run();
152
153 EXPECT_TRUE(did_run);
154 }
155
TEST(AlarmTimerTest,AlarmTimerZeroDelay)156 TEST(AlarmTimerTest, AlarmTimerZeroDelay) {
157 base::MessageLoopForIO loop;
158 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
159
160 base::RunLoop run_loop;
161 bool did_run = false;
162 AlarmTimerTester f(&did_run, base::TimeDelta(),
163 run_loop.QuitWhenIdleClosure());
164 f.Start();
165
166 run_loop.Run();
167
168 EXPECT_TRUE(did_run);
169 }
170
TEST(AlarmTimerTest,AlarmTimerZeroDelay_Cancel)171 TEST(AlarmTimerTest, AlarmTimerZeroDelay_Cancel) {
172 base::MessageLoopForIO loop;
173 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
174
175 bool did_run_a = false;
176 AlarmTimerTester* a =
177 new AlarmTimerTester(&did_run_a, base::TimeDelta(), base::OnceClosure());
178
179 // This should run before the timer expires.
180 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a);
181
182 // Now start the timer.
183 a->Start();
184
185 base::RunLoop run_loop;
186 bool did_run_b = false;
187 AlarmTimerTester b(&did_run_b, base::TimeDelta(),
188 run_loop.QuitWhenIdleClosure());
189 b.Start();
190
191 run_loop.Run();
192
193 EXPECT_FALSE(did_run_a);
194 EXPECT_TRUE(did_run_b);
195 }
196
TEST(AlarmTimerTest,MessageLoopShutdown)197 TEST(AlarmTimerTest, MessageLoopShutdown) {
198 // This test is designed to verify that shutdown of the
199 // message loop does not cause crashes if there were pending
200 // timers not yet fired. It may only trigger exceptions
201 // if debug heap checking is enabled.
202 bool did_run = false;
203 {
204 auto loop = std::make_unique<base::MessageLoopForIO>();
205 auto file_descriptor_watcher =
206 std::make_unique<base::FileDescriptorWatcher>(loop.get());
207 AlarmTimerTester a(&did_run, kTenMilliseconds, base::OnceClosure());
208 AlarmTimerTester b(&did_run, kTenMilliseconds, base::OnceClosure());
209 AlarmTimerTester c(&did_run, kTenMilliseconds, base::OnceClosure());
210 AlarmTimerTester d(&did_run, kTenMilliseconds, base::OnceClosure());
211
212 a.Start();
213 b.Start();
214
215 // Allow FileDescriptorWatcher to start watching the timers. Without this,
216 // tasks posted by FileDescriptorWatcher::WatchReadable() are leaked.
217 base::RunLoop().RunUntilIdle();
218
219 // MessageLoop and FileDescriptorWatcher destruct.
220 file_descriptor_watcher.reset();
221 loop.reset();
222 } // SimpleAlarmTimers destruct. SHOULD NOT CRASH, of course.
223
224 EXPECT_FALSE(did_run);
225 }
226
TEST(AlarmTimerTest,NonRepeatIsRunning)227 TEST(AlarmTimerTest, NonRepeatIsRunning) {
228 {
229 base::MessageLoopForIO loop;
230 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
231 timers::SimpleAlarmTimer timer;
232 EXPECT_FALSE(timer.IsRunning());
233 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), base::DoNothing());
234
235 // Allow FileDescriptorWatcher to start watching the timer. Without this, a
236 // task posted by FileDescriptorWatcher::WatchReadable() is leaked.
237 base::RunLoop().RunUntilIdle();
238
239 EXPECT_TRUE(timer.IsRunning());
240 timer.Stop();
241 EXPECT_FALSE(timer.IsRunning());
242 ASSERT_FALSE(timer.user_task().is_null());
243 timer.Reset();
244 base::RunLoop().RunUntilIdle();
245 EXPECT_TRUE(timer.IsRunning());
246 }
247 }
248
TEST(AlarmTimerTest,RetainNonRepeatIsRunning)249 TEST(AlarmTimerTest, RetainNonRepeatIsRunning) {
250 base::MessageLoopForIO loop;
251 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
252 timers::SimpleAlarmTimer timer;
253 EXPECT_FALSE(timer.IsRunning());
254 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), base::DoNothing());
255
256 // Allow FileDescriptorWatcher to start watching the timer. Without this, a
257 // task posted by FileDescriptorWatcher::WatchReadable() is leaked.
258 base::RunLoop().RunUntilIdle();
259
260 EXPECT_TRUE(timer.IsRunning());
261 timer.Reset();
262 base::RunLoop().RunUntilIdle();
263 EXPECT_TRUE(timer.IsRunning());
264 timer.Stop();
265 EXPECT_FALSE(timer.IsRunning());
266 timer.Reset();
267 base::RunLoop().RunUntilIdle();
268 EXPECT_TRUE(timer.IsRunning());
269 }
270
271 namespace {
272
273 bool g_callback_happened1 = false;
274 bool g_callback_happened2 = false;
275
ClearAllCallbackHappened()276 void ClearAllCallbackHappened() {
277 g_callback_happened1 = false;
278 g_callback_happened2 = false;
279 }
280
SetCallbackHappened1(base::OnceClosure quit_closure)281 void SetCallbackHappened1(base::OnceClosure quit_closure) {
282 g_callback_happened1 = true;
283 if (quit_closure)
284 std::move(quit_closure).Run();
285 }
286
SetCallbackHappened2(base::OnceClosure quit_closure)287 void SetCallbackHappened2(base::OnceClosure quit_closure) {
288 g_callback_happened2 = true;
289 if (quit_closure)
290 std::move(quit_closure).Run();
291 }
292
TEST(AlarmTimerTest,ContinuationStopStart)293 TEST(AlarmTimerTest, ContinuationStopStart) {
294 ClearAllCallbackHappened();
295 base::MessageLoopForIO loop;
296 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
297 timers::SimpleAlarmTimer timer;
298 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
299 base::BindRepeating(&SetCallbackHappened1,
300 base::DoNothing().Repeatedly()));
301 timer.Stop();
302
303 base::RunLoop run_loop;
304 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(40),
305 base::BindRepeating(&SetCallbackHappened2,
306 run_loop.QuitWhenIdleClosure()));
307 run_loop.Run();
308
309 EXPECT_FALSE(g_callback_happened1);
310 EXPECT_TRUE(g_callback_happened2);
311 }
312
TEST(AlarmTimerTest,ContinuationReset)313 TEST(AlarmTimerTest, ContinuationReset) {
314 ClearAllCallbackHappened();
315 base::MessageLoopForIO loop;
316 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
317
318 base::RunLoop run_loop;
319 timers::SimpleAlarmTimer timer;
320 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
321 base::BindRepeating(&SetCallbackHappened1,
322 run_loop.QuitWhenIdleClosure()));
323 timer.Reset();
324 ASSERT_FALSE(timer.user_task().is_null());
325 run_loop.Run();
326 EXPECT_TRUE(g_callback_happened1);
327 }
328
329 // Verify that no crash occurs if a timer is deleted while its callback is
330 // running.
TEST(AlarmTimerTest,DeleteTimerWhileCallbackIsRunning)331 TEST(AlarmTimerTest, DeleteTimerWhileCallbackIsRunning) {
332 base::MessageLoopForIO loop;
333 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
334 base::RunLoop run_loop;
335
336 // Will be deleted by the callback.
337 timers::SimpleAlarmTimer* timer = new timers::SimpleAlarmTimer;
338
339 timer->Start(
340 FROM_HERE, base::TimeDelta::FromMilliseconds(10),
341 base::BindRepeating(
342 [](timers::SimpleAlarmTimer* timer, base::RunLoop* run_loop) {
343 delete timer;
344 run_loop->Quit();
345 },
346 timer, &run_loop));
347 run_loop.Run();
348 }
349
350 // Verify that no crash occurs if a zero-delay timer is deleted while its
351 // callback is running.
TEST(AlarmTimerTest,DeleteTimerWhileCallbackIsRunningZeroDelay)352 TEST(AlarmTimerTest, DeleteTimerWhileCallbackIsRunningZeroDelay) {
353 base::MessageLoopForIO loop;
354 base::FileDescriptorWatcher file_descriptor_watcher(&loop);
355 base::RunLoop run_loop;
356
357 // Will be deleted by the callback.
358 timers::SimpleAlarmTimer* timer = new timers::SimpleAlarmTimer;
359
360 timer->Start(
361 FROM_HERE, base::TimeDelta(),
362 base::BindRepeating(
363 [](timers::SimpleAlarmTimer* timer, base::RunLoop* run_loop) {
364 delete timer;
365 run_loop->Quit();
366 },
367 timer, &run_loop));
368 run_loop.Run();
369 }
370
371 } // namespace
372 } // namespace timers
373