OLD | NEW |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |