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

Side by Side Diff: base/timer_unittest.cc

Issue 483: Eliminate the TimerManager by pulling its priority queue into MessageLoop.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « base/timer.cc ('k') | base/tracked.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/message_loop.h" 5 #include "base/message_loop.h"
6 #include "base/task.h" 6 #include "base/task.h"
7 #include "base/timer.h" 7 #include "base/timer.h"
8 #include "testing/gtest/include/gtest/gtest.h" 8 #include "testing/gtest/include/gtest/gtest.h"
9 9
10 using base::TimerComparison;
11
12 namespace {
13
14 class TimerTest : public testing::Test {};
15
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.
19 class 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() {
49 return MessageLoop::current();
50 }
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
63 void TimerTask::RunTimers() {
64 if (timer_count_ && !loop_running_) {
65 loop_running_ = true;
66 message_loop()->Run();
67 }
68 }
69
70 TimerTask::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_deprecated()->StartTimer(
79 delay, this, repeating);
80 }
81
82 TimerTask::~TimerTask() {
83 if (timer_) {
84 message_loop()->timer_manager_deprecated()->StopTimer(timer_);
85 delete timer_;
86 }
87 if (timer_running_) {
88 timer_running_ = false;
89 if (--timer_count_ <= 0)
90 QuitMessageLoop();
91 }
92 }
93
94 void TimerTask::Reset() {
95 if (!timer_running_) {
96 timer_running_ = true;
97 ++timer_count_;
98 }
99 if (timer_) {
100 start_ticks_ = TimeTicks::Now();
101 message_loop()->timer_manager_deprecated()->ResetTimer(timer_);
102 }
103 }
104
105 void TimerTask::Run() {
106 ++iterations_;
107
108 // Test that we fired on or after the delay, not before.
109 const TimeTicks ticks = TimeTicks::Now();
110 EXPECT_LE(delay_, (ticks - start_ticks_).InMilliseconds());
111 // Note: Add the delay rather than using the ticks recorded.
112 // Repeating timers have already started ticking before
113 // this callback; we pretend they started *now*, then
114 // it might seem like they fire early, when they do not.
115 start_ticks_ += TimeDelta::FromMilliseconds(delay_);
116
117 // If we're done running, shut down the message loop.
118 if (timer_->repeating() && (iterations_ < 10))
119 return; // Iterate 10 times before terminating.
120 message_loop()->timer_manager_deprecated()->StopTimer(timer_);
121 timer_running_ = false;
122 if (--timer_count_ <= 0)
123 QuitMessageLoop();
124 }
125
126 // static
127 void TimerTask::QuitMessageLoop() {
128 if (loop_running_) {
129 message_loop()->Quit();
130 loop_running_ = false;
131 }
132 }
133
134 int TimerTask::timer_count_ = 0;
135 bool TimerTask::loop_running_ = false;
136
137 // A task that deletes itself when run.
138 class DeletingTask : public TimerTask {
139 public:
140 DeletingTask(int delay, bool repeating) : TimerTask(delay, repeating) { }
141
142 // Task
143 virtual void Run();
144 };
145
146 void DeletingTask::Run() {
147 delete this;
148
149 // Can't call TimerTask::Run() here, we've destroyed ourselves.
150 }
151
152 // A class that resets another TimerTask when run.
153 class ResettingTask : public TimerTask {
154 public:
155 ResettingTask(int delay, bool repeating, TimerTask* task)
156 : TimerTask(delay, repeating),
157 task_(task) {
158 }
159
160 virtual void Run();
161
162 private:
163 TimerTask* task_;
164 };
165
166 void ResettingTask::Run() {
167 task_->Reset();
168
169 TimerTask::Run();
170 }
171
172 // A class that quits the message loop when run.
173 class QuittingTask : public TimerTask {
174 public:
175 QuittingTask(int delay, bool repeating) : TimerTask(delay, repeating) { }
176
177 virtual void Run();
178 };
179
180 void QuittingTask::Run() {
181 QuitMessageLoop();
182
183 TimerTask::Run();
184 }
185
186 void RunTimerTest() {
187 // Make sure oneshot timers work correctly.
188 TimerTask task1(100, false);
189 TimerTask::RunTimers();
190 EXPECT_EQ(1, task1.iterations());
191
192 // Make sure repeating timers work correctly.
193 TimerTask task2(10, true);
194 TimerTask task3(100, true);
195 TimerTask::RunTimers();
196 EXPECT_EQ(10, task2.iterations());
197 EXPECT_EQ(10, task3.iterations());
198 }
199
200 //-----------------------------------------------------------------------------
201 // The timer test cases:
202
203 void RunTest_TimerComparison(MessageLoop::Type message_loop_type) {
204 MessageLoop loop(message_loop_type);
205
206 // Make sure TimerComparison sorts correctly.
207 const TimerTask task1(10, false);
208 const Timer* timer1 = task1.timer();
209 const TimerTask task2(200, false);
210 const Timer* timer2 = task2.timer();
211 TimerComparison comparison;
212 EXPECT_FALSE(comparison(timer1, timer2));
213 EXPECT_TRUE(comparison(timer2, timer1));
214 }
215
216 void RunTest_BasicTimer(MessageLoop::Type message_loop_type) {
217 MessageLoop loop(message_loop_type);
218
219 RunTimerTest();
220 }
221
222 void RunTest_BrokenTimer(MessageLoop::Type message_loop_type) {
223 MessageLoop loop(message_loop_type);
224
225 // Simulate faulty early-firing timers. The tasks in RunTimerTest should
226 // nevertheless be invoked after their specified delays, regardless of when
227 // WM_TIMER fires.
228 TimerManager* manager = MessageLoop::current()->timer_manager_deprecated();
229 manager->set_use_broken_delay(true);
230 RunTimerTest();
231 manager->set_use_broken_delay(false);
232 }
233
234 void RunTest_DeleteFromRun(MessageLoop::Type message_loop_type) {
235 MessageLoop loop(message_loop_type);
236
237 // Make sure TimerManager correctly handles a Task that deletes itself when
238 // run.
239 new DeletingTask(50, true);
240 TimerTask timer_task(150, false);
241 new DeletingTask(250, true);
242 TimerTask::RunTimers();
243 EXPECT_EQ(1, timer_task.iterations());
244 }
245
246 void RunTest_Reset(MessageLoop::Type message_loop_type) {
247 MessageLoop loop(message_loop_type);
248
249 // Make sure resetting a timer after it has fired works.
250 TimerTask timer_task1(250, false);
251 TimerTask timer_task2(100, true);
252 ResettingTask resetting_task1(600, false, &timer_task1);
253 TimerTask::RunTimers();
254 EXPECT_EQ(2, timer_task1.iterations());
255 EXPECT_EQ(10, timer_task2.iterations());
256
257 // Make sure resetting a timer before it has fired works. This will reset
258 // two timers, then stop the message loop between when they should have
259 // finally fired.
260 TimerTask timer_task3(100, false);
261 TimerTask timer_task4(600, false);
262 ResettingTask resetting_task3(50, false, &timer_task3);
263 ResettingTask resetting_task4(50, false, &timer_task4);
264 QuittingTask quitting_task(300, false);
265 TimerTask::RunTimers();
266 EXPECT_EQ(1, timer_task3.iterations());
267 EXPECT_EQ(0, timer_task4.iterations());
268 }
269
270 void RunTest_FifoOrder(MessageLoop::Type message_loop_type) {
271 MessageLoop loop(message_loop_type);
272
273 // Creating timers with the same timeout should
274 // always compare to result in FIFO ordering.
275
276 // Derive from the timer so that we can set it's fire time.
277 // We have to do this, because otherwise, it's possible for
278 // two timers, created back to back, to have different times,
279 // and in that case, we aren't really testing what we want
280 // to test!
281 class MockTimer : public Timer {
282 public:
283 MockTimer(int delay) : Timer(delay, NULL, false) {}
284 void set_fire_time(const Time& t) { fire_time_ = t; }
285 };
286
287 class MockTimerManager : public TimerManager {
288 public:
289 MockTimerManager() : TimerManager(MessageLoop::current()) {
290 }
291
292 // Pops the most-recent to fire timer and returns its timer id.
293 // Returns -1 if there are no timers in the list.
294 int pop() {
295 int rv = -1;
296 Timer* top = PeekTopTimer();
297 if (top) {
298 rv = top->id();
299 StopTimer(top);
300 delete top;
301 }
302 return rv;
303 }
304 };
305
306 MockTimer t1(0);
307 MockTimer t2(0);
308 t2.set_fire_time(t1.fire_time());
309 TimerComparison comparison;
310 EXPECT_TRUE(comparison(&t2, &t1));
311
312 // Issue a tight loop of timers; most will have the
313 // same timestamp; some will not. Either way, since
314 // all are created with delay(0), the second timer
315 // must always be greater than the first. Then, pop
316 // all the timers and verify that it's a FIFO list.
317 MockTimerManager manager;
318 const int kNumTimers = 1024;
319 for (int i=0; i < kNumTimers; i++)
320 manager.StartTimer(0, NULL, false);
321
322 int last_id = -1;
323 int new_id = 0;
324 while((new_id = manager.pop()) > 0)
325 EXPECT_GT(new_id, last_id);
326 }
327
328 namespace { 10 namespace {
329 11
330 class OneShotTimerTester { 12 class OneShotTimerTester {
331 public: 13 public:
332 OneShotTimerTester(bool* did_run) : did_run_(did_run) { 14 OneShotTimerTester(bool* did_run) : did_run_(did_run) {
333 } 15 }
334 void Start() { 16 void Start() {
335 timer_.Start(TimeDelta::FromMilliseconds(10), this, 17 timer_.Start(TimeDelta::FromMilliseconds(10), this,
336 &OneShotTimerTester::Run); 18 &OneShotTimerTester::Run);
337 } 19 }
(...skipping 19 matching lines...) Expand all
357 if (--counter_ == 0) { 39 if (--counter_ == 0) {
358 *did_run_ = true; 40 *did_run_ = true;
359 MessageLoop::current()->Quit(); 41 MessageLoop::current()->Quit();
360 } 42 }
361 } 43 }
362 bool* did_run_; 44 bool* did_run_;
363 int counter_; 45 int counter_;
364 base::RepeatingTimer<RepeatingTimerTester> timer_; 46 base::RepeatingTimer<RepeatingTimerTester> timer_;
365 }; 47 };
366 48
367 } // namespace
368
369 void RunTest_OneShotTimer(MessageLoop::Type message_loop_type) { 49 void RunTest_OneShotTimer(MessageLoop::Type message_loop_type) {
370 MessageLoop loop(message_loop_type); 50 MessageLoop loop(message_loop_type);
371 51
372 bool did_run = false; 52 bool did_run = false;
373 OneShotTimerTester f(&did_run); 53 OneShotTimerTester f(&did_run);
374 f.Start(); 54 f.Start();
375 55
376 MessageLoop::current()->Run(); 56 MessageLoop::current()->Run();
377 57
378 EXPECT_TRUE(did_run); 58 EXPECT_TRUE(did_run);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 EXPECT_FALSE(did_run_a); 113 EXPECT_FALSE(did_run_a);
434 EXPECT_TRUE(did_run_b); 114 EXPECT_TRUE(did_run_b);
435 } 115 }
436 116
437 } // namespace 117 } // namespace
438 118
439 //----------------------------------------------------------------------------- 119 //-----------------------------------------------------------------------------
440 // Each test is run against each type of MessageLoop. That way we are sure 120 // Each test is run against each type of MessageLoop. That way we are sure
441 // that timers work properly in all configurations. 121 // that timers work properly in all configurations.
442 122
443 TEST(TimerTest, TimerComparison) {
444 RunTest_TimerComparison(MessageLoop::TYPE_DEFAULT);
445 RunTest_TimerComparison(MessageLoop::TYPE_UI);
446 RunTest_TimerComparison(MessageLoop::TYPE_IO);
447 }
448
449 TEST(TimerTest, BasicTimer) {
450 RunTest_BasicTimer(MessageLoop::TYPE_DEFAULT);
451 RunTest_BasicTimer(MessageLoop::TYPE_UI);
452 RunTest_BasicTimer(MessageLoop::TYPE_IO);
453 }
454
455 TEST(TimerTest, BrokenTimer) {
456 RunTest_BrokenTimer(MessageLoop::TYPE_DEFAULT);
457 RunTest_BrokenTimer(MessageLoop::TYPE_UI);
458 RunTest_BrokenTimer(MessageLoop::TYPE_IO);
459 }
460
461 TEST(TimerTest, DeleteFromRun) {
462 RunTest_DeleteFromRun(MessageLoop::TYPE_DEFAULT);
463 RunTest_DeleteFromRun(MessageLoop::TYPE_UI);
464 RunTest_DeleteFromRun(MessageLoop::TYPE_IO);
465 }
466
467 TEST(TimerTest, Reset) {
468 RunTest_Reset(MessageLoop::TYPE_DEFAULT);
469 RunTest_Reset(MessageLoop::TYPE_UI);
470 RunTest_Reset(MessageLoop::TYPE_IO);
471 }
472
473 TEST(TimerTest, FifoOrder) {
474 RunTest_FifoOrder(MessageLoop::TYPE_DEFAULT);
475 RunTest_FifoOrder(MessageLoop::TYPE_UI);
476 RunTest_FifoOrder(MessageLoop::TYPE_IO);
477 }
478
479 TEST(TimerTest, OneShotTimer) { 123 TEST(TimerTest, OneShotTimer) {
480 RunTest_OneShotTimer(MessageLoop::TYPE_DEFAULT); 124 RunTest_OneShotTimer(MessageLoop::TYPE_DEFAULT);
481 RunTest_OneShotTimer(MessageLoop::TYPE_UI); 125 RunTest_OneShotTimer(MessageLoop::TYPE_UI);
482 RunTest_OneShotTimer(MessageLoop::TYPE_IO); 126 RunTest_OneShotTimer(MessageLoop::TYPE_IO);
483 } 127 }
484 128
485 TEST(TimerTest, OneShotTimer_Cancel) { 129 TEST(TimerTest, OneShotTimer_Cancel) {
486 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_DEFAULT); 130 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_DEFAULT);
487 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_UI); 131 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_UI);
488 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_IO); 132 RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_IO);
489 } 133 }
490 134
491 TEST(TimerTest, RepeatingTimer) { 135 TEST(TimerTest, RepeatingTimer) {
492 RunTest_RepeatingTimer(MessageLoop::TYPE_DEFAULT); 136 RunTest_RepeatingTimer(MessageLoop::TYPE_DEFAULT);
493 RunTest_RepeatingTimer(MessageLoop::TYPE_UI); 137 RunTest_RepeatingTimer(MessageLoop::TYPE_UI);
494 RunTest_RepeatingTimer(MessageLoop::TYPE_IO); 138 RunTest_RepeatingTimer(MessageLoop::TYPE_IO);
495 } 139 }
496 140
497 TEST(TimerTest, RepeatingTimer_Cancel) { 141 TEST(TimerTest, RepeatingTimer_Cancel) {
498 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_DEFAULT); 142 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_DEFAULT);
499 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_UI); 143 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_UI);
500 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_IO); 144 RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_IO);
501 } 145 }
OLDNEW
« no previous file with comments | « base/timer.cc ('k') | base/tracked.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698