blob: 9b251b2e58a849a23101156724ec4b5b212eb998 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#include "base/message_loop.h"
6#include "base/task.h"
7#include "base/timer.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
darin@google.com0b8a30c2008-08-29 05:50:12 +090010using base::TimerComparison;
11
initial.commit3f4a7322008-07-27 06:49:38 +090012namespace {
darin@google.comd936b5b2008-08-26 14:53:57 +090013
14class TimerTest : public testing::Test {};
initial.commit3f4a7322008-07-27 06:49:38 +090015
16// A base class timer task that sanity-checks timer functionality and counts
17// the number of times it has run. Handles all message loop and memory
18// management issues.
19class TimerTask : public Task {
20 public:
21 // Runs all timers to completion. This returns only after all timers have
22 // finished firing.
23 static void RunTimers();
24
25 // Creates a new timer. If |repeating| is true, the timer will repeat 10
26 // times before terminating.
27 //
28 // All timers are managed on the message loop of the thread that calls this
29 // function the first time.
30 TimerTask(int delay, bool repeating);
31
32 virtual ~TimerTask();
33
34 int iterations() const { return iterations_; }
35 const Timer* timer() const { return timer_; }
36
37 // Resets the timer, if it exists.
38 void Reset();
39
40 // Task
41 virtual void Run();
42
43 protected:
44 // Shuts down the message loop if necessary.
45 static void QuitMessageLoop();
46
47 private:
48 static MessageLoop* message_loop() {
darin@google.com3a793ae2008-08-26 16:07:33 +090049 return MessageLoop::current();
initial.commit3f4a7322008-07-27 06:49:38 +090050 }
51
52 static int timer_count_;
53 static bool loop_running_;
54
55 bool timer_running_;
56 int delay_;
57 TimeTicks start_ticks_;
58 int iterations_;
59 Timer* timer_;
60};
61
62// static
63void TimerTask::RunTimers() {
64 if (timer_count_ && !loop_running_) {
65 loop_running_ = true;
66 message_loop()->Run();
67 }
68}
69
70TimerTask::TimerTask(int delay, bool repeating)
71 : timer_running_(false),
72 delay_(delay),
73 start_ticks_(TimeTicks::Now()),
74 iterations_(0),
75 timer_(NULL) {
76 Reset(); // This will just set up the variables to indicate we have a
77 // running timer.
78 timer_ = message_loop()->timer_manager()->StartTimer(delay, this, repeating);
79}
80
81TimerTask::~TimerTask() {
82 if (timer_) {
83 message_loop()->timer_manager()->StopTimer(timer_);
84 delete timer_;
85 }
86 if (timer_running_) {
87 timer_running_ = false;
88 if (--timer_count_ <= 0)
89 QuitMessageLoop();
90 }
91}
92
93void TimerTask::Reset() {
94 if (!timer_running_) {
95 timer_running_ = true;
96 ++timer_count_;
97 }
98 if (timer_) {
99 start_ticks_ = TimeTicks::Now();
100 message_loop()->timer_manager()->ResetTimer(timer_);
101 }
102}
103
104void TimerTask::Run() {
105 ++iterations_;
106
107 // Test that we fired on or after the delay, not before.
108 const TimeTicks ticks = TimeTicks::Now();
109 EXPECT_LE(delay_, (ticks - start_ticks_).InMilliseconds());
110 // Note: Add the delay rather than using the ticks recorded.
111 // Repeating timers have already started ticking before
112 // this callback; we pretend they started *now*, then
113 // it might seem like they fire early, when they do not.
114 start_ticks_ += TimeDelta::FromMilliseconds(delay_);
115
116 // If we're done running, shut down the message loop.
117 if (timer_->repeating() && (iterations_ < 10))
118 return; // Iterate 10 times before terminating.
119 message_loop()->timer_manager()->StopTimer(timer_);
120 timer_running_ = false;
121 if (--timer_count_ <= 0)
122 QuitMessageLoop();
123}
124
125// static
126void TimerTask::QuitMessageLoop() {
127 if (loop_running_) {
128 message_loop()->Quit();
129 loop_running_ = false;
130 }
131}
132
133int TimerTask::timer_count_ = 0;
134bool TimerTask::loop_running_ = false;
135
136// A task that deletes itself when run.
137class DeletingTask : public TimerTask {
138 public:
139 DeletingTask(int delay, bool repeating) : TimerTask(delay, repeating) { }
140
141 // Task
142 virtual void Run();
143};
144
145void DeletingTask::Run() {
146 delete this;
147
148 // Can't call TimerTask::Run() here, we've destroyed ourselves.
149}
150
151// A class that resets another TimerTask when run.
152class ResettingTask : public TimerTask {
153 public:
154 ResettingTask(int delay, bool repeating, TimerTask* task)
155 : TimerTask(delay, repeating),
156 task_(task) {
157 }
158
159 virtual void Run();
160
161 private:
162 TimerTask* task_;
163};
164
165void ResettingTask::Run() {
166 task_->Reset();
167
168 TimerTask::Run();
169}
170
171// A class that quits the message loop when run.
172class QuittingTask : public TimerTask {
173 public:
174 QuittingTask(int delay, bool repeating) : TimerTask(delay, repeating) { }
175
176 virtual void Run();
177};
178
179void QuittingTask::Run() {
180 QuitMessageLoop();
181
182 TimerTask::Run();
183}
184
185void RunTimerTest() {
186 // Make sure oneshot timers work correctly.
187 TimerTask task1(100, false);
188 TimerTask::RunTimers();
189 EXPECT_EQ(1, task1.iterations());
190
191 // Make sure repeating timers work correctly.
192 TimerTask task2(10, true);
193 TimerTask task3(100, true);
194 TimerTask::RunTimers();
195 EXPECT_EQ(10, task2.iterations());
196 EXPECT_EQ(10, task3.iterations());
197}
198
darin@google.comd936b5b2008-08-26 14:53:57 +0900199//-----------------------------------------------------------------------------
200// The timer test cases:
201
202void RunTest_TimerComparison(MessageLoop::Type message_loop_type) {
203 MessageLoop loop(message_loop_type);
204
initial.commit3f4a7322008-07-27 06:49:38 +0900205 // Make sure TimerComparison sorts correctly.
206 const TimerTask task1(10, false);
207 const Timer* timer1 = task1.timer();
208 const TimerTask task2(200, false);
209 const Timer* timer2 = task2.timer();
210 TimerComparison comparison;
211 EXPECT_FALSE(comparison(timer1, timer2));
212 EXPECT_TRUE(comparison(timer2, timer1));
213}
214
darin@google.comd936b5b2008-08-26 14:53:57 +0900215void RunTest_BasicTimer(MessageLoop::Type message_loop_type) {
216 MessageLoop loop(message_loop_type);
217
initial.commit3f4a7322008-07-27 06:49:38 +0900218 RunTimerTest();
219}
220
darin@google.comd936b5b2008-08-26 14:53:57 +0900221void RunTest_BrokenTimer(MessageLoop::Type message_loop_type) {
222 MessageLoop loop(message_loop_type);
223
initial.commit3f4a7322008-07-27 06:49:38 +0900224 // Simulate faulty early-firing timers. The tasks in RunTimerTest should
225 // nevertheless be invoked after their specified delays, regardless of when
226 // WM_TIMER fires.
227 TimerManager* manager = MessageLoop::current()->timer_manager();
228 manager->set_use_broken_delay(true);
229 RunTimerTest();
230 manager->set_use_broken_delay(false);
231}
232
darin@google.comd936b5b2008-08-26 14:53:57 +0900233void RunTest_DeleteFromRun(MessageLoop::Type message_loop_type) {
234 MessageLoop loop(message_loop_type);
235
initial.commit3f4a7322008-07-27 06:49:38 +0900236 // Make sure TimerManager correctly handles a Task that deletes itself when
237 // run.
mmentovai@google.com1e0dab22008-08-22 13:03:44 +0900238 new DeletingTask(50, true);
initial.commit3f4a7322008-07-27 06:49:38 +0900239 TimerTask timer_task(150, false);
mmentovai@google.com1e0dab22008-08-22 13:03:44 +0900240 new DeletingTask(250, true);
initial.commit3f4a7322008-07-27 06:49:38 +0900241 TimerTask::RunTimers();
242 EXPECT_EQ(1, timer_task.iterations());
243}
244
darin@google.comd936b5b2008-08-26 14:53:57 +0900245void RunTest_Reset(MessageLoop::Type message_loop_type) {
246 MessageLoop loop(message_loop_type);
247
initial.commit3f4a7322008-07-27 06:49:38 +0900248 // Make sure resetting a timer after it has fired works.
249 TimerTask timer_task1(250, false);
250 TimerTask timer_task2(100, true);
251 ResettingTask resetting_task1(600, false, &timer_task1);
252 TimerTask::RunTimers();
253 EXPECT_EQ(2, timer_task1.iterations());
254 EXPECT_EQ(10, timer_task2.iterations());
255
256 // Make sure resetting a timer before it has fired works. This will reset
257 // two timers, then stop the message loop between when they should have
258 // finally fired.
259 TimerTask timer_task3(100, false);
260 TimerTask timer_task4(600, false);
261 ResettingTask resetting_task3(50, false, &timer_task3);
262 ResettingTask resetting_task4(50, false, &timer_task4);
263 QuittingTask quitting_task(300, false);
264 TimerTask::RunTimers();
265 EXPECT_EQ(1, timer_task3.iterations());
266 EXPECT_EQ(0, timer_task4.iterations());
267}
268
darin@google.comd936b5b2008-08-26 14:53:57 +0900269void RunTest_FifoOrder(MessageLoop::Type message_loop_type) {
270 MessageLoop loop(message_loop_type);
271
initial.commit3f4a7322008-07-27 06:49:38 +0900272 // Creating timers with the same timeout should
273 // always compare to result in FIFO ordering.
274
275 // Derive from the timer so that we can set it's fire time.
276 // We have to do this, because otherwise, it's possible for
277 // two timers, created back to back, to have different times,
278 // and in that case, we aren't really testing what we want
279 // to test!
280 class MockTimer : public Timer {
281 public:
282 MockTimer(int delay) : Timer(delay, NULL, false) {}
283 void set_fire_time(const Time& t) { fire_time_ = t; }
284 };
285
286 class MockTimerManager : public TimerManager {
287 public:
darin@google.comee6fa722008-08-13 08:25:43 +0900288 MockTimerManager() : TimerManager(MessageLoop::current()) {
289 }
290
initial.commit3f4a7322008-07-27 06:49:38 +0900291 // Pops the most-recent to fire timer and returns its timer id.
292 // Returns -1 if there are no timers in the list.
293 int pop() {
294 int rv = -1;
295 Timer* top = PeekTopTimer();
296 if (top) {
297 rv = top->id();
298 StopTimer(top);
299 delete top;
300 }
301 return rv;
302 }
303 };
304
305 MockTimer t1(0);
306 MockTimer t2(0);
307 t2.set_fire_time(t1.fire_time());
308 TimerComparison comparison;
309 EXPECT_TRUE(comparison(&t2, &t1));
310
311 // Issue a tight loop of timers; most will have the
312 // same timestamp; some will not. Either way, since
313 // all are created with delay(0), the second timer
314 // must always be greater than the first. Then, pop
315 // all the timers and verify that it's a FIFO list.
316 MockTimerManager manager;
317 const int kNumTimers = 1024;
318 for (int i=0; i < kNumTimers; i++)
mmentovai@google.com1e0dab22008-08-22 13:03:44 +0900319 manager.StartTimer(0, NULL, false);
initial.commit3f4a7322008-07-27 06:49:38 +0900320
321 int last_id = -1;
322 int new_id = 0;
323 while((new_id = manager.pop()) > 0)
324 EXPECT_GT(new_id, last_id);
deanm@google.com97137862008-08-14 20:44:17 +0900325}
license.botf003cfe2008-08-24 09:55:55 +0900326
darin@google.com0b8a30c2008-08-29 05:50:12 +0900327namespace {
328
329class OneShotTimerTester {
330 public:
331 OneShotTimerTester(bool* did_run) : did_run_(did_run) {
332 }
333 void Start() {
334 timer_.Start(TimeDelta::FromMilliseconds(10), this,
335 &OneShotTimerTester::Run);
336 }
337 private:
338 void Run() {
339 *did_run_ = true;
340 MessageLoop::current()->Quit();
341 }
342 bool* did_run_;
343 base::OneShotTimer<OneShotTimerTester> timer_;
344};
345
346class RepeatingTimerTester {
347 public:
348 RepeatingTimerTester(bool* did_run) : did_run_(did_run), counter_(10) {
349 }
350 void Start() {
351 timer_.Start(TimeDelta::FromMilliseconds(10), this,
352 &RepeatingTimerTester::Run);
353 }
354 private:
355 void Run() {
356 if (--counter_ == 0) {
357 *did_run_ = true;
358 MessageLoop::current()->Quit();
359 }
360 }
361 bool* did_run_;
362 int counter_;
363 base::RepeatingTimer<RepeatingTimerTester> timer_;
364};
365
366} // namespace
367
368void RunTest_OneShotTimer(MessageLoop::Type message_loop_type) {
369 MessageLoop loop(message_loop_type);
370
371 bool did_run = false;
372 OneShotTimerTester f(&did_run);
373 f.Start();
374
375 MessageLoop::current()->Run();
376
377 EXPECT_TRUE(did_run);
378}
379
380void RunTest_OneShotTimer_Cancel(MessageLoop::Type message_loop_type) {
381 MessageLoop loop(message_loop_type);
382
383 bool did_run_a = false;
384 OneShotTimerTester* a = new OneShotTimerTester(&did_run_a);
385
386 // This should run before the timer expires.
387 MessageLoop::current()->DeleteSoon(FROM_HERE, a);
388
389 // Now start the timer.
390 a->Start();
391
392 bool did_run_b = false;
393 OneShotTimerTester b(&did_run_b);
394 b.Start();
395
396 MessageLoop::current()->Run();
397
398 EXPECT_FALSE(did_run_a);
399 EXPECT_TRUE(did_run_b);
400}
401
402void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type) {
403 MessageLoop loop(message_loop_type);
404
405 bool did_run = false;
406 RepeatingTimerTester f(&did_run);
407 f.Start();
408
409 MessageLoop::current()->Run();
410
411 EXPECT_TRUE(did_run);
412}
413
414void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) {
415 MessageLoop loop(message_loop_type);
416
417 bool did_run_a = false;
418 RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a);
419
420 // This should run before the timer expires.
421 MessageLoop::current()->DeleteSoon(FROM_HERE, a);
422
423 // Now start the timer.
424 a->Start();
425
426 bool did_run_b = false;
427 RepeatingTimerTester b(&did_run_b);
428 b.Start();
429
430 MessageLoop::current()->Run();
431
432 EXPECT_FALSE(did_run_a);
433 EXPECT_TRUE(did_run_b);
434}
435
darin@google.comd936b5b2008-08-26 14:53:57 +0900436} // namespace
437
438//-----------------------------------------------------------------------------
439// Each test is run against each type of MessageLoop. That way we are sure
440// that timers work properly in all configurations.
441
442TEST(TimerTest, TimerComparison) {
443 RunTest_TimerComparison(MessageLoop::TYPE_DEFAULT);
444 RunTest_TimerComparison(MessageLoop::TYPE_UI);
445 RunTest_TimerComparison(MessageLoop::TYPE_IO);
446}
447
448TEST(TimerTest, BasicTimer) {
449 RunTest_BasicTimer(MessageLoop::TYPE_DEFAULT);
450 RunTest_BasicTimer(MessageLoop::TYPE_UI);
451 RunTest_BasicTimer(MessageLoop::TYPE_IO);
452}
453
454TEST(TimerTest, BrokenTimer) {
455 RunTest_BrokenTimer(MessageLoop::TYPE_DEFAULT);
456 RunTest_BrokenTimer(MessageLoop::TYPE_UI);
457 RunTest_BrokenTimer(MessageLoop::TYPE_IO);
458}
459
460TEST(TimerTest, DeleteFromRun) {
461 RunTest_DeleteFromRun(MessageLoop::TYPE_DEFAULT);
462 RunTest_DeleteFromRun(MessageLoop::TYPE_UI);
463 RunTest_DeleteFromRun(MessageLoop::TYPE_IO);
464}
465
466TEST(TimerTest, Reset) {
467 RunTest_Reset(MessageLoop::TYPE_DEFAULT);
468 RunTest_Reset(MessageLoop::TYPE_UI);
469 RunTest_Reset(MessageLoop::TYPE_IO);
470}
471
472TEST(TimerTest, FifoOrder) {
473 RunTest_FifoOrder(MessageLoop::TYPE_DEFAULT);
474 RunTest_FifoOrder(MessageLoop::TYPE_UI);
475 RunTest_FifoOrder(MessageLoop::TYPE_IO);
476}
darin@google.com0b8a30c2008-08-29 05:50:12 +0900477
478TEST(TimerTest, OneShotTimer) {
479 RunTest_OneShotTimer(MessageLoop::TYPE_DEFAULT);
480 RunTest_OneShotTimer(MessageLoop::TYPE_UI);
481 RunTest_OneShotTimer(MessageLoop::TYPE_IO);
482}
483
484TEST(TimerTest, OneShotTimer_Cancel) {
485 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_DEFAULT);
486 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_UI);
487 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_IO);
488}
489
490TEST(TimerTest, RepeatingTimer) {
491 RunTest_RepeatingTimer(MessageLoop::TYPE_DEFAULT);
492 RunTest_RepeatingTimer(MessageLoop::TYPE_UI);
493 RunTest_RepeatingTimer(MessageLoop::TYPE_IO);
494}
495
496TEST(TimerTest, RepeatingTimer_Cancel) {
497 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_DEFAULT);
498 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_UI);
499 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_IO);
500}