xref: /aosp_15_r20/external/libchrome/components/timers/alarm_timer_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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