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

Side by Side Diff: components/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: Fix gyp files 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 "components/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.
Daniel Erat 2014/10/23 03:44:54 i don't love the duplication here but don't have a
blundell 2014/10/23 05:54:20 This duplication seems pretty bad. Could you reach
Chirantan Ekbote 2014/10/23 23:53:30 I've filed crbug.com/426647. We'll land this for
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 timer::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<timer::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 timer::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<timer::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 timer::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<timer::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 TEST(AlarmTimerTest, NonRepeatIsRunning) {
291 {
292 base::MessageLoop loop;
293 timer::AlarmTimer timer(false, false);
294 EXPECT_FALSE(timer.IsRunning());
295 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1),
296 base::Bind(&base::DoNothing));
297 EXPECT_TRUE(timer.IsRunning());
298 timer.Stop();
299 EXPECT_FALSE(timer.IsRunning());
300 EXPECT_TRUE(timer.user_task().is_null());
301 }
302
303 {
304 timer::AlarmTimer timer(true, false);
305 base::MessageLoop loop;
306 EXPECT_FALSE(timer.IsRunning());
307 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1),
308 base::Bind(&base::DoNothing));
309 EXPECT_TRUE(timer.IsRunning());
310 timer.Stop();
311 EXPECT_FALSE(timer.IsRunning());
312 ASSERT_FALSE(timer.user_task().is_null());
313 timer.Reset();
314 EXPECT_TRUE(timer.IsRunning());
315 }
316 }
317
318 TEST(AlarmTimerTest, NonRepeatMessageLoopDeath) {
319 timer::AlarmTimer timer(false, false);
320 {
321 base::MessageLoop loop;
322 EXPECT_FALSE(timer.IsRunning());
323 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1),
324 base::Bind(&base::DoNothing));
325 EXPECT_TRUE(timer.IsRunning());
326 }
327 EXPECT_FALSE(timer.IsRunning());
328 EXPECT_TRUE(timer.user_task().is_null());
329 }
330
331 TEST(AlarmTimerTest, RetainRepeatIsRunning) {
332 base::MessageLoop loop;
333 timer::AlarmTimer timer(FROM_HERE, base::TimeDelta::FromDays(1),
334 base::Bind(&base::DoNothing), true);
335 EXPECT_FALSE(timer.IsRunning());
336 timer.Reset();
337 EXPECT_TRUE(timer.IsRunning());
338 timer.Stop();
339 EXPECT_FALSE(timer.IsRunning());
340 timer.Reset();
341 EXPECT_TRUE(timer.IsRunning());
342 }
343
344 TEST(AlarmTimerTest, RetainNonRepeatIsRunning) {
345 base::MessageLoop loop;
346 timer::AlarmTimer timer(FROM_HERE, base::TimeDelta::FromDays(1),
347 base::Bind(&base::DoNothing), false);
348 EXPECT_FALSE(timer.IsRunning());
349 timer.Reset();
350 EXPECT_TRUE(timer.IsRunning());
351 timer.Stop();
352 EXPECT_FALSE(timer.IsRunning());
353 timer.Reset();
354 EXPECT_TRUE(timer.IsRunning());
355 }
356
357 namespace {
358
359 bool g_callback_happened1 = false;
360 bool g_callback_happened2 = false;
361
362 void ClearAllCallbackHappened() {
363 g_callback_happened1 = false;
364 g_callback_happened2 = false;
365 }
366
367 void SetCallbackHappened1() {
368 g_callback_happened1 = true;
369 base::MessageLoop::current()->PostTask(
370 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
371 }
372
373 void SetCallbackHappened2() {
374 g_callback_happened2 = true;
375 base::MessageLoop::current()->PostTask(
376 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
377 }
378
379 TEST(AlarmTimerTest, ContinuationStopStart) {
380 {
381 ClearAllCallbackHappened();
382 base::MessageLoop loop;
383 timer::AlarmTimer timer(false, false);
384 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
385 base::Bind(&SetCallbackHappened1));
386 timer.Stop();
387 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(40),
388 base::Bind(&SetCallbackHappened2));
389 base::RunLoop().Run();
390 EXPECT_FALSE(g_callback_happened1);
391 EXPECT_TRUE(g_callback_happened2);
392 }
393 }
394
395 TEST(AlarmTimerTest, ContinuationReset) {
396 {
397 ClearAllCallbackHappened();
398 base::MessageLoop loop;
399 timer::AlarmTimer timer(false, false);
400 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
401 base::Bind(&SetCallbackHappened1));
402 timer.Reset();
403 // Since Reset happened before task ran, the user_task must not be cleared:
404 ASSERT_FALSE(timer.user_task().is_null());
405 base::RunLoop().Run();
406 EXPECT_TRUE(g_callback_happened1);
407 }
408 }
409
410 } // namespace
411
412
413 namespace {
414 void TimerRanCallback(bool* did_run) {
415 *did_run = true;
416
417 base::MessageLoop::current()->PostTask(
418 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
419 }
420
421 void RunTest_OneShotTimerConcurrentResetAndTimerFired(
422 base::MessageLoop::Type message_loop_type) {
423 base::MessageLoop loop(message_loop_type);
424
425 timer::AlarmTimer timer(false, false);
426 bool did_run = false;
427
428 timer.Start(
429 FROM_HERE, kTenMilliseconds, base::Bind(&TimerRanCallback, &did_run));
430
431 // Sleep twice as long as the timer to ensure that the timer task gets queued.
432 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
433
434 // Now reset the timer. This is attempting to simulate the timer firing and
435 // being reset at the same time. The previously queued task should be
436 // removed.
437 timer.Reset();
438
439 base::RunLoop().RunUntilIdle();
440 EXPECT_FALSE(did_run);
441
442 // If the previous check failed, running the message loop again will hang the
443 // test so we only do it if the callback has not run yet.
444 if (!did_run) {
445 base::RunLoop().Run();
446 EXPECT_TRUE(did_run);
447 }
448 }
449
450 void RunTest_RepeatingTimerConcurrentResetAndTimerFired(
451 base::MessageLoop::Type message_loop_type) {
452 base::MessageLoop loop(message_loop_type);
453
454 timer::AlarmTimer timer(true, true);
455 bool did_run = false;
456
457 timer.Start(
458 FROM_HERE, kTenMilliseconds, base::Bind(&TimerRanCallback, &did_run));
459
460 // Sleep more that three times as long as the timer duration to ensure that
461 // multiple tasks get queued.
462 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(35));
463
464 // Now reset the timer. This is attempting to simulate a very busy message
465 // loop where multiple tasks get queued but the timer gets reset before any of
466 // them have a chance to run.
467 timer.Reset();
468
469 base::RunLoop().RunUntilIdle();
470 EXPECT_FALSE(did_run);
471
472 // If the previous check failed, running the message loop again will hang the
473 // test so we only do it if the callback has not run yet.
474 if (!did_run) {
475 base::RunLoop().Run();
476 EXPECT_TRUE(did_run);
477 }
478 }
479
480 TEST(AlarmTimerTest, OneShotTimerConcurrentResetAndTimerFired) {
481 for (int i = 0; i < kNumTestingMessageLoops; i++) {
482 RunTest_OneShotTimerConcurrentResetAndTimerFired(testing_message_loops[i]);
483 }
484 }
485
486 TEST(AlarmTimerTest, RepeatingTimerConcurrentResetAndTimerFired) {
487 for (int i = 0; i < kNumTestingMessageLoops; i++) {
488 RunTest_RepeatingTimerConcurrentResetAndTimerFired(
489 testing_message_loops[i]);
490 }
491 }
492
493 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698