Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(714)

Side by Side Diff: base/timer/alarm_timer_unittest.cc

Issue 641943002: components: Introduce AlarmTimer class and use it for GCM heartbeat (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make some Timer variables protected to reduce duplication, clean up comments Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/macros.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/threading/platform_thread.h"
11 #include "base/time/time.h"
12 #include "base/timer/alarm_timer.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 // Most of these tests have been lifted right out of timer_unittest.cc with only
16 // cosmetic changes (like replacing calls to MessageLoop::current()->Run() with
17 // a RunLoop). We want the AlarmTimer to be a drop-in replacement for the
18 // regular Timer so it should pass the same tests as the Timer class.
19 //
20 // The only new tests are the .*ConcurrentResetAndTimerFired tests, which test
21 // that race conditions that can come up in the AlarmTimer::Delegate are
22 // properly handled.
23 namespace {
24 // The message loops on which each timer should be tested.
25 const base::MessageLoop::Type testing_message_loops[] = {
26 base::MessageLoop::TYPE_DEFAULT,
27 base::MessageLoop::TYPE_IO,
28 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop.
29 base::MessageLoop::TYPE_UI,
30 #endif
31 };
32
33 const int kNumTestingMessageLoops = arraysize(testing_message_loops);
34 const base::TimeDelta kTenMilliseconds = base::TimeDelta::FromMilliseconds(10);
35
36 class OneShotAlarmTimerTester {
37 public:
38 OneShotAlarmTimerTester(bool* did_run, base::TimeDelta delay)
39 : did_run_(did_run),
40 delay_(delay),
41 timer_(new base::AlarmTimer(false, false)) {
42 }
43 void Start() {
44 timer_->Start(FROM_HERE,
45 delay_,
46 base::Bind(&OneShotAlarmTimerTester::Run,
47 base::Unretained(this)));
48 }
49
50 private:
51 void Run() {
52 *did_run_ = true;
53
54 base::MessageLoop::current()->PostTask(
55 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
56 }
57
58 bool* did_run_;
59 const base::TimeDelta delay_;
60 scoped_ptr<base::AlarmTimer> timer_;
61
62 DISALLOW_COPY_AND_ASSIGN(OneShotAlarmTimerTester);
63 };
64
65 class OneShotSelfDeletingAlarmTimerTester {
66 public:
67 OneShotSelfDeletingAlarmTimerTester(bool* did_run, base::TimeDelta delay)
68 : did_run_(did_run),
69 delay_(delay),
70 timer_(new base::AlarmTimer(false, false)) {
71 }
72 void Start() {
73 timer_->Start(FROM_HERE,
74 delay_,
75 base::Bind(&OneShotSelfDeletingAlarmTimerTester::Run,
76 base::Unretained(this)));
77 }
78
79 private:
80 void Run() {
81 *did_run_ = true;
82 timer_.reset();
83
84 base::MessageLoop::current()->PostTask(
85 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
86 }
87
88 bool* did_run_;
89 const base::TimeDelta delay_;
90 scoped_ptr<base::AlarmTimer> timer_;
91
92 DISALLOW_COPY_AND_ASSIGN(OneShotSelfDeletingAlarmTimerTester);
93 };
94
95 class RepeatingAlarmTimerTester {
96 public:
97 RepeatingAlarmTimerTester(bool* did_run, base::TimeDelta delay)
98 : did_run_(did_run),
99 delay_(delay),
100 counter_(10),
101 timer_(new base::AlarmTimer(true, true)) {
102 }
103 void Start() {
104 timer_->Start(FROM_HERE,
105 delay_,
106 base::Bind(&RepeatingAlarmTimerTester::Run,
107 base::Unretained(this)));
108 }
109
110 private:
111 void Run() {
112 if (--counter_ == 0) {
113 *did_run_ = true;
114 timer_->Stop();
115
116 base::MessageLoop::current()->PostTask(
117 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
118 }
119 }
120
121 bool* did_run_;
122 const base::TimeDelta delay_;
123 int counter_;
124 scoped_ptr<base::AlarmTimer> timer_;
125
126 DISALLOW_COPY_AND_ASSIGN(RepeatingAlarmTimerTester);
127 };
128
129 void RunTest_OneShotAlarmTimer(base::MessageLoop::Type message_loop_type) {
130 base::MessageLoop loop(message_loop_type);
131
132 bool did_run = false;
133 OneShotAlarmTimerTester f(&did_run, kTenMilliseconds);
134 f.Start();
135
136 base::RunLoop().Run();
137
138 EXPECT_TRUE(did_run);
139 }
140
141 void RunTest_OneShotAlarmTimer_Cancel(
142 base::MessageLoop::Type message_loop_type) {
143 base::MessageLoop loop(message_loop_type);
144
145 bool did_run_a = false;
146 OneShotAlarmTimerTester* a = new OneShotAlarmTimerTester(&did_run_a,
147 kTenMilliseconds);
148
149 // This should run before the timer expires.
150 base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);
151
152 // Now start the timer.
153 a->Start();
154
155 bool did_run_b = false;
156 OneShotAlarmTimerTester b(&did_run_b, kTenMilliseconds);
157 b.Start();
158
159 base::RunLoop().Run();
160
161 EXPECT_FALSE(did_run_a);
162 EXPECT_TRUE(did_run_b);
163 }
164
165 void RunTest_OneShotSelfDeletingAlarmTimer(
166 base::MessageLoop::Type message_loop_type) {
167 base::MessageLoop loop(message_loop_type);
168
169 bool did_run = false;
170 OneShotSelfDeletingAlarmTimerTester f(&did_run, kTenMilliseconds);
171 f.Start();
172
173 base::RunLoop().Run();
174
175 EXPECT_TRUE(did_run);
176 }
177
178 void RunTest_RepeatingAlarmTimer(base::MessageLoop::Type message_loop_type,
179 const base::TimeDelta& delay) {
180 base::MessageLoop loop(message_loop_type);
181
182 bool did_run = false;
183 RepeatingAlarmTimerTester f(&did_run, delay);
184 f.Start();
185
186 base::RunLoop().Run();
187
188 EXPECT_TRUE(did_run);
189 }
190
191 void RunTest_RepeatingAlarmTimer_Cancel(
192 base::MessageLoop::Type message_loop_type, const base::TimeDelta& delay) {
193 base::MessageLoop loop(message_loop_type);
194
195 bool did_run_a = false;
196 RepeatingAlarmTimerTester* a = new RepeatingAlarmTimerTester(&did_run_a,
197 delay);
198
199 // This should run before the timer expires.
200 base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);
201
202 // Now start the timer.
203 a->Start();
204
205 bool did_run_b = false;
206 RepeatingAlarmTimerTester b(&did_run_b, delay);
207 b.Start();
208
209 base::RunLoop().Run();
210
211 EXPECT_FALSE(did_run_a);
212 EXPECT_TRUE(did_run_b);
213 }
214
215 } // namespace
216
217 //-----------------------------------------------------------------------------
218 // Each test is run against each type of MessageLoop. That way we are sure
219 // that timers work properly in all configurations.
220
221 TEST(AlarmTimerTest, OneShotAlarmTimer) {
222 for (int i = 0; i < kNumTestingMessageLoops; i++) {
223 RunTest_OneShotAlarmTimer(testing_message_loops[i]);
224 }
225 }
226
227 TEST(AlarmTimerTest, OneShotAlarmTimer_Cancel) {
228 for (int i = 0; i < kNumTestingMessageLoops; i++) {
229 RunTest_OneShotAlarmTimer_Cancel(testing_message_loops[i]);
230 }
231 }
232
233 // If underlying timer does not handle this properly, we will crash or fail
234 // in full page heap environment.
235 TEST(AlarmTimerTest, OneShotSelfDeletingAlarmTimer) {
236 for (int i = 0; i < kNumTestingMessageLoops; i++) {
237 RunTest_OneShotSelfDeletingAlarmTimer(testing_message_loops[i]);
238 }
239 }
240
241 TEST(AlarmTimerTest, RepeatingAlarmTimer) {
242 for (int i = 0; i < kNumTestingMessageLoops; i++) {
243 RunTest_RepeatingAlarmTimer(testing_message_loops[i],
244 kTenMilliseconds);
245 }
246 }
247
248 TEST(AlarmTimerTest, RepeatingAlarmTimer_Cancel) {
249 for (int i = 0; i < kNumTestingMessageLoops; i++) {
250 RunTest_RepeatingAlarmTimer_Cancel(testing_message_loops[i],
251 kTenMilliseconds);
252 }
253 }
254
255 TEST(AlarmTimerTest, RepeatingAlarmTimerZeroDelay) {
256 for (int i = 0; i < kNumTestingMessageLoops; i++) {
257 RunTest_RepeatingAlarmTimer(testing_message_loops[i],
258 base::TimeDelta::FromMilliseconds(0));
259 }
260 }
261
262 TEST(AlarmTimerTest, RepeatingAlarmTimerZeroDelay_Cancel) {
263 for (int i = 0; i < kNumTestingMessageLoops; i++) {
264 RunTest_RepeatingAlarmTimer_Cancel(testing_message_loops[i],
265 base::TimeDelta::FromMilliseconds(0));
266 }
267 }
268
269 TEST(AlarmTimerTest, MessageLoopShutdown) {
270 // This test is designed to verify that shutdown of the
271 // message loop does not cause crashes if there were pending
272 // timers not yet fired. It may only trigger exceptions
273 // if debug heap checking is enabled.
274 bool did_run = false;
275 {
276 OneShotAlarmTimerTester a(&did_run, kTenMilliseconds);
277 OneShotAlarmTimerTester b(&did_run, kTenMilliseconds);
278 OneShotAlarmTimerTester c(&did_run, kTenMilliseconds);
279 OneShotAlarmTimerTester d(&did_run, kTenMilliseconds);
280 {
281 base::MessageLoop loop;
282 a.Start();
283 b.Start();
284 } // MessageLoop destructs by falling out of scope.
285 } // OneShotTimers destruct. SHOULD NOT CRASH, of course.
286
287 EXPECT_FALSE(did_run);
288 }
289
290 void AlarmTimerTestCallback() {
291 }
292
293 TEST(AlarmTimerTest, NonRepeatIsRunning) {
294 {
295 base::MessageLoop loop;
296 base::AlarmTimer timer(false, false);
297 EXPECT_FALSE(timer.IsRunning());
298 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1),
299 base::Bind(&AlarmTimerTestCallback));
300 EXPECT_TRUE(timer.IsRunning());
301 timer.Stop();
302 EXPECT_FALSE(timer.IsRunning());
303 EXPECT_TRUE(timer.user_task().is_null());
304 }
305
306 {
307 base::AlarmTimer timer(true, false);
308 base::MessageLoop loop;
309 EXPECT_FALSE(timer.IsRunning());
310 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1),
311 base::Bind(&AlarmTimerTestCallback));
312 EXPECT_TRUE(timer.IsRunning());
313 timer.Stop();
314 EXPECT_FALSE(timer.IsRunning());
315 ASSERT_FALSE(timer.user_task().is_null());
316 timer.Reset();
317 EXPECT_TRUE(timer.IsRunning());
318 }
319 }
320
321 TEST(AlarmTimerTest, NonRepeatMessageLoopDeath) {
322 base::AlarmTimer timer(false, false);
323 {
324 base::MessageLoop loop;
325 EXPECT_FALSE(timer.IsRunning());
326 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1),
327 base::Bind(&AlarmTimerTestCallback));
328 EXPECT_TRUE(timer.IsRunning());
329 }
330 EXPECT_FALSE(timer.IsRunning());
331 EXPECT_TRUE(timer.user_task().is_null());
332 }
333
334 TEST(AlarmTimerTest, RetainRepeatIsRunning) {
335 base::MessageLoop loop;
336 base::AlarmTimer timer(FROM_HERE, base::TimeDelta::FromDays(1),
337 base::Bind(&AlarmTimerTestCallback), true);
338 EXPECT_FALSE(timer.IsRunning());
339 timer.Reset();
340 EXPECT_TRUE(timer.IsRunning());
341 timer.Stop();
342 EXPECT_FALSE(timer.IsRunning());
343 timer.Reset();
344 EXPECT_TRUE(timer.IsRunning());
345 }
346
347 TEST(AlarmTimerTest, RetainNonRepeatIsRunning) {
348 base::MessageLoop loop;
349 base::AlarmTimer timer(FROM_HERE, base::TimeDelta::FromDays(1),
350 base::Bind(&AlarmTimerTestCallback), false);
351 EXPECT_FALSE(timer.IsRunning());
352 timer.Reset();
353 EXPECT_TRUE(timer.IsRunning());
354 timer.Stop();
355 EXPECT_FALSE(timer.IsRunning());
356 timer.Reset();
357 EXPECT_TRUE(timer.IsRunning());
358 }
359
360 namespace {
361
362 bool g_callback_happened1 = false;
363 bool g_callback_happened2 = false;
364
365 void ClearAllCallbackHappened() {
366 g_callback_happened1 = false;
367 g_callback_happened2 = false;
368 }
369
370 void SetCallbackHappened1() {
371 g_callback_happened1 = true;
372 base::MessageLoop::current()->PostTask(
373 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
374 }
375
376 void SetCallbackHappened2() {
377 g_callback_happened2 = true;
378 base::MessageLoop::current()->PostTask(
379 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
380 }
381
382 TEST(AlarmTimerTest, ContinuationStopStart) {
383 {
384 ClearAllCallbackHappened();
385 base::MessageLoop loop;
386 base::AlarmTimer timer(false, false);
387 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
388 base::Bind(&SetCallbackHappened1));
389 timer.Stop();
390 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(40),
391 base::Bind(&SetCallbackHappened2));
392 base::RunLoop().Run();
393 EXPECT_FALSE(g_callback_happened1);
394 EXPECT_TRUE(g_callback_happened2);
395 }
396 }
397
398 TEST(AlarmTimerTest, ContinuationReset) {
399 {
400 ClearAllCallbackHappened();
401 base::MessageLoop loop;
402 base::AlarmTimer timer(false, false);
403 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
404 base::Bind(&SetCallbackHappened1));
405 timer.Reset();
406 // Since Reset happened before task ran, the user_task must not be cleared:
407 ASSERT_FALSE(timer.user_task().is_null());
408 base::RunLoop().Run();
409 EXPECT_TRUE(g_callback_happened1);
410 }
411 }
412
413 } // namespace
414
415
416 namespace {
417 void TimerRanCallback(bool* did_run) {
418 *did_run = true;
419
420 base::MessageLoop::current()->PostTask(
421 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
422 }
423
424 void RunTest_OneShotTimerConcurrentResetAndTimerFired(
425 base::MessageLoop::Type message_loop_type) {
426 base::MessageLoop loop(message_loop_type);
427
428 base::AlarmTimer timer(false, false);
429 bool did_run = false;
430
431 timer.Start(
432 FROM_HERE, kTenMilliseconds, base::Bind(&TimerRanCallback, &did_run));
433
434 // Sleep twice as long as the timer to ensure that the timer task gets queued.
435 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
436
437 // Now reset the timer. This is attempting to simulate the timer firing and
438 // being reset at the same time. The previously queued task should be
439 // removed.
440 timer.Reset();
441
442 base::RunLoop().RunUntilIdle();
443 EXPECT_FALSE(did_run);
444
445 // If the previous check failed, running the message loop again will hang the
446 // test so we only do it if the callback has not run yet.
447 if (!did_run) {
448 base::RunLoop().Run();
449 EXPECT_TRUE(did_run);
450 }
451 }
452
453 void RunTest_RepeatingTimerConcurrentResetAndTimerFired(
454 base::MessageLoop::Type message_loop_type) {
455 base::MessageLoop loop(message_loop_type);
456
457 base::AlarmTimer timer(true, true);
458 bool did_run = false;
459
460 timer.Start(
461 FROM_HERE, kTenMilliseconds, base::Bind(&TimerRanCallback, &did_run));
462
463 // Sleep more that three times as long as the timer duration to ensure that
464 // multiple tasks get queued.
465 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(35));
466
467 // Now reset the timer. This is attempting to simulate a very busy message
468 // loop where multiple tasks get queued but the timer gets reset before any of
469 // them have a chance to run.
470 timer.Reset();
471
472 base::RunLoop().RunUntilIdle();
473 EXPECT_FALSE(did_run);
474
475 // If the previous check failed, running the message loop again will hang the
476 // test so we only do it if the callback has not run yet.
477 if (!did_run) {
478 base::RunLoop().Run();
479 EXPECT_TRUE(did_run);
480 }
481 }
482
483 TEST(AlarmTimerTest, OneShotTimerConcurrentResetAndTimerFired) {
484 for (int i = 0; i < kNumTestingMessageLoops; i++) {
485 RunTest_OneShotTimerConcurrentResetAndTimerFired(testing_message_loops[i]);
486 }
487 }
488
489 TEST(AlarmTimerTest, RepeatingTimerConcurrentResetAndTimerFired) {
490 for (int i = 0; i < kNumTestingMessageLoops; i++) {
491 RunTest_RepeatingTimerConcurrentResetAndTimerFired(
492 testing_message_loops[i]);
493 }
494 }
495
496 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698