timer_unittest.cc revision ddb351dbec246cf1fab5ec20d2d5520909041de1
1// Copyright (c) 2011 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/memory/scoped_ptr.h"
6#include "base/message_loop.h"
7#include "base/task.h"
8#include "base/timer.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11using base::TimeDelta;
12
13namespace {
14
15class OneShotTimerTester {
16 public:
17  OneShotTimerTester(bool* did_run, unsigned milliseconds = 10)
18      : did_run_(did_run),
19        delay_ms_(milliseconds) {
20  }
21  void Start() {
22    timer_.Start(TimeDelta::FromMilliseconds(delay_ms_), this,
23                 &OneShotTimerTester::Run);
24  }
25 private:
26  void Run() {
27    *did_run_ = true;
28    MessageLoop::current()->Quit();
29  }
30  bool* did_run_;
31  base::OneShotTimer<OneShotTimerTester> timer_;
32  const unsigned delay_ms_;
33};
34
35class OneShotSelfDeletingTimerTester {
36 public:
37  explicit OneShotSelfDeletingTimerTester(bool* did_run) :
38      did_run_(did_run),
39      timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
40  }
41  void Start() {
42    timer_->Start(TimeDelta::FromMilliseconds(10), this,
43                  &OneShotSelfDeletingTimerTester::Run);
44  }
45 private:
46  void Run() {
47    *did_run_ = true;
48    timer_.reset();
49    MessageLoop::current()->Quit();
50  }
51  bool* did_run_;
52  scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
53};
54
55class RepeatingTimerTester {
56 public:
57  explicit RepeatingTimerTester(bool* did_run)
58      : did_run_(did_run), counter_(10) {
59  }
60
61  void Start() {
62    timer_.Start(TimeDelta::FromMilliseconds(10), this,
63                 &RepeatingTimerTester::Run);
64  }
65 private:
66  void Run() {
67    if (--counter_ == 0) {
68      *did_run_ = true;
69      MessageLoop::current()->Quit();
70    }
71  }
72  bool* did_run_;
73  int counter_;
74  base::RepeatingTimer<RepeatingTimerTester> timer_;
75};
76
77void RunTest_OneShotTimer(MessageLoop::Type message_loop_type) {
78  MessageLoop loop(message_loop_type);
79
80  bool did_run = false;
81  OneShotTimerTester f(&did_run);
82  f.Start();
83
84  MessageLoop::current()->Run();
85
86  EXPECT_TRUE(did_run);
87}
88
89void RunTest_OneShotTimer_Cancel(MessageLoop::Type message_loop_type) {
90  MessageLoop loop(message_loop_type);
91
92  bool did_run_a = false;
93  OneShotTimerTester* a = new OneShotTimerTester(&did_run_a);
94
95  // This should run before the timer expires.
96  MessageLoop::current()->DeleteSoon(FROM_HERE, a);
97
98  // Now start the timer.
99  a->Start();
100
101  bool did_run_b = false;
102  OneShotTimerTester b(&did_run_b);
103  b.Start();
104
105  MessageLoop::current()->Run();
106
107  EXPECT_FALSE(did_run_a);
108  EXPECT_TRUE(did_run_b);
109}
110
111void RunTest_OneShotSelfDeletingTimer(MessageLoop::Type message_loop_type) {
112  MessageLoop loop(message_loop_type);
113
114  bool did_run = false;
115  OneShotSelfDeletingTimerTester f(&did_run);
116  f.Start();
117
118  MessageLoop::current()->Run();
119
120  EXPECT_TRUE(did_run);
121}
122
123void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type) {
124  MessageLoop loop(message_loop_type);
125
126  bool did_run = false;
127  RepeatingTimerTester f(&did_run);
128  f.Start();
129
130  MessageLoop::current()->Run();
131
132  EXPECT_TRUE(did_run);
133}
134
135void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) {
136  MessageLoop loop(message_loop_type);
137
138  bool did_run_a = false;
139  RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a);
140
141  // This should run before the timer expires.
142  MessageLoop::current()->DeleteSoon(FROM_HERE, a);
143
144  // Now start the timer.
145  a->Start();
146
147  bool did_run_b = false;
148  RepeatingTimerTester b(&did_run_b);
149  b.Start();
150
151  MessageLoop::current()->Run();
152
153  EXPECT_FALSE(did_run_a);
154  EXPECT_TRUE(did_run_b);
155}
156
157class DelayTimerTarget {
158 public:
159  DelayTimerTarget()
160      : signaled_(false) {
161  }
162
163  bool signaled() const { return signaled_; }
164
165  void Signal() {
166    ASSERT_FALSE(signaled_);
167    signaled_ = true;
168  }
169
170 private:
171  bool signaled_;
172};
173
174void RunTest_DelayTimer_NoCall(MessageLoop::Type message_loop_type) {
175  MessageLoop loop(message_loop_type);
176
177  // If Delay is never called, the timer shouldn't go off.
178  DelayTimerTarget target;
179  base::DelayTimer<DelayTimerTarget> timer(
180      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
181
182  bool did_run = false;
183  OneShotTimerTester tester(&did_run);
184  tester.Start();
185  MessageLoop::current()->Run();
186
187  ASSERT_FALSE(target.signaled());
188}
189
190void RunTest_DelayTimer_OneCall(MessageLoop::Type message_loop_type) {
191  MessageLoop loop(message_loop_type);
192
193  DelayTimerTarget target;
194  base::DelayTimer<DelayTimerTarget> timer(
195      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
196  timer.Reset();
197
198  bool did_run = false;
199  OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
200  tester.Start();
201  MessageLoop::current()->Run();
202
203  ASSERT_TRUE(target.signaled());
204}
205
206struct ResetHelper {
207  ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
208              DelayTimerTarget* target)
209      : timer_(timer),
210        target_(target) {
211  }
212
213  void Reset() {
214    ASSERT_FALSE(target_->signaled());
215    timer_->Reset();
216  }
217
218 private:
219  base::DelayTimer<DelayTimerTarget> *const timer_;
220  DelayTimerTarget *const target_;
221};
222
223void RunTest_DelayTimer_Reset(MessageLoop::Type message_loop_type) {
224  MessageLoop loop(message_loop_type);
225
226  // If Delay is never called, the timer shouldn't go off.
227  DelayTimerTarget target;
228  base::DelayTimer<DelayTimerTarget> timer(
229      TimeDelta::FromMilliseconds(50), &target, &DelayTimerTarget::Signal);
230  timer.Reset();
231
232  ResetHelper reset_helper(&timer, &target);
233
234  base::OneShotTimer<ResetHelper> timers[20];
235  for (size_t i = 0; i < arraysize(timers); ++i) {
236    timers[i].Start(TimeDelta::FromMilliseconds(i * 10), &reset_helper,
237                    &ResetHelper::Reset);
238  }
239
240  bool did_run = false;
241  OneShotTimerTester tester(&did_run, 300);
242  tester.Start();
243  MessageLoop::current()->Run();
244
245  ASSERT_TRUE(target.signaled());
246}
247
248class DelayTimerFatalTarget {
249 public:
250  void Signal() {
251    ASSERT_TRUE(false);
252  }
253};
254
255
256void RunTest_DelayTimer_Deleted(MessageLoop::Type message_loop_type) {
257  MessageLoop loop(message_loop_type);
258
259  DelayTimerFatalTarget target;
260
261  {
262    base::DelayTimer<DelayTimerFatalTarget> timer(
263        TimeDelta::FromMilliseconds(50), &target,
264        &DelayTimerFatalTarget::Signal);
265    timer.Reset();
266  }
267
268  // When the timer is deleted, the DelayTimerFatalTarget should never be
269  // called.
270  base::PlatformThread::Sleep(100);
271}
272
273}  // namespace
274
275//-----------------------------------------------------------------------------
276// Each test is run against each type of MessageLoop.  That way we are sure
277// that timers work properly in all configurations.
278
279TEST(TimerTest, OneShotTimer) {
280  RunTest_OneShotTimer(MessageLoop::TYPE_DEFAULT);
281  RunTest_OneShotTimer(MessageLoop::TYPE_UI);
282  RunTest_OneShotTimer(MessageLoop::TYPE_IO);
283}
284
285TEST(TimerTest, OneShotTimer_Cancel) {
286  RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_DEFAULT);
287  RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_UI);
288  RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_IO);
289}
290
291// If underline timer does not handle properly, we will crash or fail
292// in full page heap or purify environment.
293TEST(TimerTest, OneShotSelfDeletingTimer) {
294  RunTest_OneShotSelfDeletingTimer(MessageLoop::TYPE_DEFAULT);
295  RunTest_OneShotSelfDeletingTimer(MessageLoop::TYPE_UI);
296  RunTest_OneShotSelfDeletingTimer(MessageLoop::TYPE_IO);
297}
298
299TEST(TimerTest, RepeatingTimer) {
300  RunTest_RepeatingTimer(MessageLoop::TYPE_DEFAULT);
301  RunTest_RepeatingTimer(MessageLoop::TYPE_UI);
302  RunTest_RepeatingTimer(MessageLoop::TYPE_IO);
303}
304
305TEST(TimerTest, RepeatingTimer_Cancel) {
306  RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_DEFAULT);
307  RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_UI);
308  RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_IO);
309}
310
311TEST(TimerTest, DelayTimer_NoCall) {
312  RunTest_DelayTimer_NoCall(MessageLoop::TYPE_DEFAULT);
313  RunTest_DelayTimer_NoCall(MessageLoop::TYPE_UI);
314  RunTest_DelayTimer_NoCall(MessageLoop::TYPE_IO);
315}
316
317TEST(TimerTest, DelayTimer_OneCall) {
318  RunTest_DelayTimer_OneCall(MessageLoop::TYPE_DEFAULT);
319  RunTest_DelayTimer_OneCall(MessageLoop::TYPE_UI);
320  RunTest_DelayTimer_OneCall(MessageLoop::TYPE_IO);
321}
322
323// It's flaky on the buildbot, http://crbug.com/25038.
324TEST(TimerTest, FLAKY_DelayTimer_Reset) {
325  RunTest_DelayTimer_Reset(MessageLoop::TYPE_DEFAULT);
326  RunTest_DelayTimer_Reset(MessageLoop::TYPE_UI);
327  RunTest_DelayTimer_Reset(MessageLoop::TYPE_IO);
328}
329
330TEST(TimerTest, DelayTimer_Deleted) {
331  RunTest_DelayTimer_Deleted(MessageLoop::TYPE_DEFAULT);
332  RunTest_DelayTimer_Deleted(MessageLoop::TYPE_UI);
333  RunTest_DelayTimer_Deleted(MessageLoop::TYPE_IO);
334}
335
336TEST(TimerTest, MessageLoopShutdown) {
337  // This test is designed to verify that shutdown of the
338  // message loop does not cause crashes if there were pending
339  // timers not yet fired.  It may only trigger exceptions
340  // if debug heap checking (or purify) is enabled.
341  bool did_run = false;
342  {
343    OneShotTimerTester a(&did_run);
344    OneShotTimerTester b(&did_run);
345    OneShotTimerTester c(&did_run);
346    OneShotTimerTester d(&did_run);
347    {
348      MessageLoop loop(MessageLoop::TYPE_DEFAULT);
349      a.Start();
350      b.Start();
351    }  // MessageLoop destructs by falling out of scope.
352  }  // OneShotTimers destruct.  SHOULD NOT CRASH, of course.
353
354  EXPECT_FALSE(did_run);
355}
356