blob: a196519f55423798d4a4fd4d053f5f77ecf44ade [file] [log] [blame]
[email protected]b026e35d2010-10-19 02:31:031// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]b7243c42010-07-23 05:23:135#include <vector>
6
[email protected]9cfb89a2010-06-09 21:20:417#include "base/eintr_wrapper.h"
initial.commitd7cae122008-07-26 21:49:388#include "base/logging.h"
9#include "base/message_loop.h"
[email protected]b16ef312008-08-19 18:36:2310#include "base/platform_thread.h"
initial.commitd7cae122008-07-26 21:49:3811#include "base/ref_counted.h"
[email protected]9cfb89a2010-06-09 21:20:4112#include "base/task.h"
[email protected]b16ef312008-08-19 18:36:2313#include "base/thread.h"
initial.commitd7cae122008-07-26 21:49:3814#include "testing/gtest/include/gtest/gtest.h"
15
[email protected]295039bd2008-08-15 04:32:5716#if defined(OS_WIN)
17#include "base/message_pump_win.h"
[email protected]b16ef312008-08-19 18:36:2318#include "base/scoped_handle.h"
[email protected]295039bd2008-08-15 04:32:5719#endif
[email protected]f74c8962009-04-22 20:01:3620#if defined(OS_POSIX)
21#include "base/message_pump_libevent.h"
22#endif
[email protected]295039bd2008-08-15 04:32:5723
[email protected]4d9bdfaf2008-08-26 05:53:5724using base::Thread;
[email protected]e1acf6f2008-10-27 20:43:3325using base::Time;
26using base::TimeDelta;
[email protected]4d9bdfaf2008-08-26 05:53:5727
28// TODO(darin): Platform-specific MessageLoop tests should be grouped together
29// to avoid chopping this file up with so many #ifdefs.
[email protected]b16ef312008-08-19 18:36:2330
initial.commitd7cae122008-07-26 21:49:3831namespace {
32
[email protected]4d9bdfaf2008-08-26 05:53:5733class MessageLoopTest : public testing::Test {};
initial.commitd7cae122008-07-26 21:49:3834
35class Foo : public base::RefCounted<Foo> {
36 public:
37 Foo() : test_count_(0) {
38 }
39
40 void Test0() {
41 ++test_count_;
42 }
43
44 void Test1ConstRef(const std::string& a) {
45 ++test_count_;
46 result_.append(a);
47 }
48
49 void Test1Ptr(std::string* a) {
50 ++test_count_;
51 result_.append(*a);
52 }
53
54 void Test1Int(int a) {
55 test_count_ += a;
56 }
57
58 void Test2Ptr(std::string* a, std::string* b) {
59 ++test_count_;
60 result_.append(*a);
61 result_.append(*b);
62 }
63
64 void Test2Mixed(const std::string& a, std::string* b) {
65 ++test_count_;
66 result_.append(a);
67 result_.append(*b);
68 }
69
70 int test_count() const { return test_count_; }
71 const std::string& result() const { return result_; }
72
73 private:
[email protected]877d55d2009-11-05 21:53:0874 friend class base::RefCounted<Foo>;
75
76 ~Foo() {}
77
initial.commitd7cae122008-07-26 21:49:3878 int test_count_;
79 std::string result_;
80};
81
82class QuitMsgLoop : public base::RefCounted<QuitMsgLoop> {
83 public:
84 void QuitNow() {
85 MessageLoop::current()->Quit();
86 }
[email protected]877d55d2009-11-05 21:53:0887
88 private:
89 friend class base::RefCounted<QuitMsgLoop>;
90
91 ~QuitMsgLoop() {}
initial.commitd7cae122008-07-26 21:49:3892};
93
[email protected]4d9bdfaf2008-08-26 05:53:5794void RunTest_PostTask(MessageLoop::Type message_loop_type) {
95 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:3896
initial.commitd7cae122008-07-26 21:49:3897 // Add tests to message loop
[email protected]ad8e04a2010-11-01 04:16:2798 scoped_refptr<Foo> foo(new Foo());
initial.commitd7cae122008-07-26 21:49:3899 std::string a("a"), b("b"), c("c"), d("d");
100 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
101 foo.get(), &Foo::Test0));
102 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
103 foo.get(), &Foo::Test1ConstRef, a));
104 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
105 foo.get(), &Foo::Test1Ptr, &b));
106 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
107 foo.get(), &Foo::Test1Int, 100));
108 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
109 foo.get(), &Foo::Test2Ptr, &a, &c));
110 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
111 foo.get(), &Foo::Test2Mixed, a, &d));
112
113 // After all tests, post a message that will shut down the message loop
[email protected]ad8e04a2010-11-01 04:16:27114 scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop());
initial.commitd7cae122008-07-26 21:49:38115 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
116 quit.get(), &QuitMsgLoop::QuitNow));
117
118 // Now kick things off
119 MessageLoop::current()->Run();
120
121 EXPECT_EQ(foo->test_count(), 105);
122 EXPECT_EQ(foo->result(), "abacad");
123}
124
[email protected]4d9bdfaf2008-08-26 05:53:57125void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
126 MessageLoop loop(message_loop_type);
127
initial.commitd7cae122008-07-26 21:49:38128 // Add tests to message loop
[email protected]ad8e04a2010-11-01 04:16:27129 scoped_refptr<Foo> foo(new Foo());
initial.commitd7cae122008-07-26 21:49:38130 std::string a("a"), b("b"), c("c"), d("d");
131 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
132 foo.get(), &Foo::Test0));
133 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
134 foo.get(), &Foo::Test1ConstRef, a));
135 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
136 foo.get(), &Foo::Test1Ptr, &b));
137 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
138 foo.get(), &Foo::Test1Int, 100));
139 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
140 foo.get(), &Foo::Test2Ptr, &a, &c));
141 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
142 foo.get(), &Foo::Test2Mixed, a, &d));
143
144 // After all tests, post a message that will shut down the message loop
[email protected]ad8e04a2010-11-01 04:16:27145 scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop());
initial.commitd7cae122008-07-26 21:49:38146 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
147 quit.get(), &QuitMsgLoop::QuitNow));
148
149 // Now kick things off with the SEH block active.
150 MessageLoop::current()->set_exception_restoration(true);
151 MessageLoop::current()->Run();
152 MessageLoop::current()->set_exception_restoration(false);
153
154 EXPECT_EQ(foo->test_count(), 105);
155 EXPECT_EQ(foo->result(), "abacad");
156}
157
[email protected]752578562008-09-07 08:08:29158// This class runs slowly to simulate a large amount of work being done.
159class SlowTask : public Task {
160 public:
161 SlowTask(int pause_ms, int* quit_counter)
162 : pause_ms_(pause_ms), quit_counter_(quit_counter) {
163 }
164 virtual void Run() {
165 PlatformThread::Sleep(pause_ms_);
166 if (--(*quit_counter_) == 0)
167 MessageLoop::current()->Quit();
168 }
169 private:
170 int pause_ms_;
171 int* quit_counter_;
172};
173
174// This class records the time when Run was called in a Time object, which is
175// useful for building a variety of MessageLoop tests.
176class RecordRunTimeTask : public SlowTask {
177 public:
178 RecordRunTimeTask(Time* run_time, int* quit_counter)
179 : SlowTask(10, quit_counter), run_time_(run_time) {
180 }
181 virtual void Run() {
182 *run_time_ = Time::Now();
183 // Cause our Run function to take some time to execute. As a result we can
184 // count on subsequent RecordRunTimeTask objects running at a future time,
185 // without worry about the resolution of our system clock being an issue.
186 SlowTask::Run();
187 }
188 private:
189 Time* run_time_;
190};
191
192void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
193 MessageLoop loop(message_loop_type);
194
195 // Test that PostDelayedTask results in a delayed task.
196
197 const int kDelayMS = 100;
198
199 int num_tasks = 1;
200 Time run_time;
201
202 loop.PostDelayedTask(
203 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), kDelayMS);
204
205 Time time_before_run = Time::Now();
206 loop.Run();
207 Time time_after_run = Time::Now();
208
209 EXPECT_EQ(0, num_tasks);
210 EXPECT_LT(kDelayMS, (time_after_run - time_before_run).InMilliseconds());
211}
212
213void RunTest_PostDelayedTask_InDelayOrder(MessageLoop::Type message_loop_type) {
214 MessageLoop loop(message_loop_type);
215
216 // Test that two tasks with different delays run in the right order.
217
218 int num_tasks = 2;
219 Time run_time1, run_time2;
220
221 loop.PostDelayedTask(
222 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 200);
223 // If we get a large pause in execution (due to a context switch) here, this
224 // test could fail.
225 loop.PostDelayedTask(
226 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10);
227
228 loop.Run();
229 EXPECT_EQ(0, num_tasks);
230
231 EXPECT_TRUE(run_time2 < run_time1);
232}
233
234void RunTest_PostDelayedTask_InPostOrder(MessageLoop::Type message_loop_type) {
235 MessageLoop loop(message_loop_type);
236
237 // Test that two tasks with the same delay run in the order in which they
238 // were posted.
239 //
240 // NOTE: This is actually an approximate test since the API only takes a
241 // "delay" parameter, so we are not exactly simulating two tasks that get
242 // posted at the exact same time. It would be nice if the API allowed us to
243 // specify the desired run time.
244
245 const int kDelayMS = 100;
246
247 int num_tasks = 2;
248 Time run_time1, run_time2;
249
250 loop.PostDelayedTask(
251 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), kDelayMS);
252 loop.PostDelayedTask(
253 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), kDelayMS);
254
255 loop.Run();
256 EXPECT_EQ(0, num_tasks);
257
258 EXPECT_TRUE(run_time1 < run_time2);
259}
260
[email protected]32cda29d2008-10-09 23:58:43261void RunTest_PostDelayedTask_InPostOrder_2(
262 MessageLoop::Type message_loop_type) {
[email protected]752578562008-09-07 08:08:29263 MessageLoop loop(message_loop_type);
264
265 // Test that a delayed task still runs after a normal tasks even if the
266 // normal tasks take a long time to run.
267
268 const int kPauseMS = 50;
269
270 int num_tasks = 2;
271 Time run_time;
272
273 loop.PostTask(
274 FROM_HERE, new SlowTask(kPauseMS, &num_tasks));
275 loop.PostDelayedTask(
276 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 10);
277
278 Time time_before_run = Time::Now();
279 loop.Run();
280 Time time_after_run = Time::Now();
281
282 EXPECT_EQ(0, num_tasks);
283
284 EXPECT_LT(kPauseMS, (time_after_run - time_before_run).InMilliseconds());
285}
286
[email protected]32cda29d2008-10-09 23:58:43287void RunTest_PostDelayedTask_InPostOrder_3(
288 MessageLoop::Type message_loop_type) {
[email protected]752578562008-09-07 08:08:29289 MessageLoop loop(message_loop_type);
290
291 // Test that a delayed task still runs after a pile of normal tasks. The key
292 // difference between this test and the previous one is that here we return
293 // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
294 // to maybe run the delayed task. It should know not to do so until the
295 // delayed task's delay has passed.
296
297 int num_tasks = 11;
298 Time run_time1, run_time2;
299
300 // Clutter the ML with tasks.
301 for (int i = 1; i < num_tasks; ++i)
302 loop.PostTask(FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks));
303
304 loop.PostDelayedTask(
305 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 1);
306
307 loop.Run();
308 EXPECT_EQ(0, num_tasks);
309
310 EXPECT_TRUE(run_time2 > run_time1);
311}
312
[email protected]72deacd2008-09-23 19:19:20313void RunTest_PostDelayedTask_SharedTimer(MessageLoop::Type message_loop_type) {
314 MessageLoop loop(message_loop_type);
315
316 // Test that the interval of the timer, used to run the next delayed task, is
317 // set to a value corresponding to when the next delayed task should run.
318
319 // By setting num_tasks to 1, we ensure that the first task to run causes the
320 // run loop to exit.
321 int num_tasks = 1;
322 Time run_time1, run_time2;
323
324 loop.PostDelayedTask(
325 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 1000000);
326 loop.PostDelayedTask(
327 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10);
328
329 Time start_time = Time::Now();
330
331 loop.Run();
332 EXPECT_EQ(0, num_tasks);
333
334 // Ensure that we ran in far less time than the slower timer.
[email protected]4615f1982008-09-23 19:22:33335 TimeDelta total_time = Time::Now() - start_time;
336 EXPECT_GT(5000, total_time.InMilliseconds());
[email protected]32cda29d2008-10-09 23:58:43337
[email protected]72deacd2008-09-23 19:19:20338 // In case both timers somehow run at nearly the same time, sleep a little
339 // and then run all pending to force them both to have run. This is just
340 // encouraging flakiness if there is any.
341 PlatformThread::Sleep(100);
342 loop.RunAllPending();
343
344 EXPECT_TRUE(run_time1.is_null());
345 EXPECT_FALSE(run_time2.is_null());
346}
347
348#if defined(OS_WIN)
349
350class SubPumpTask : public Task {
351 public:
352 virtual void Run() {
353 MessageLoop::current()->SetNestableTasksAllowed(true);
354 MSG msg;
[email protected]32cda29d2008-10-09 23:58:43355 while (GetMessage(&msg, NULL, 0, 0)) {
[email protected]72deacd2008-09-23 19:19:20356 TranslateMessage(&msg);
357 DispatchMessage(&msg);
358 }
359 MessageLoop::current()->Quit();
360 }
361};
362
363class SubPumpQuitTask : public Task {
364 public:
365 SubPumpQuitTask() {
366 }
367 virtual void Run() {
368 PostQuitMessage(0);
369 }
370};
371
372void RunTest_PostDelayedTask_SharedTimer_SubPump() {
373 MessageLoop loop(MessageLoop::TYPE_UI);
374
375 // Test that the interval of the timer, used to run the next delayed task, is
376 // set to a value corresponding to when the next delayed task should run.
377
378 // By setting num_tasks to 1, we ensure that the first task to run causes the
379 // run loop to exit.
380 int num_tasks = 1;
381 Time run_time;
382
383 loop.PostTask(FROM_HERE, new SubPumpTask());
384
385 // This very delayed task should never run.
386 loop.PostDelayedTask(
387 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 1000000);
388
389 // This slightly delayed task should run from within SubPumpTask::Run().
390 loop.PostDelayedTask(
391 FROM_HERE, new SubPumpQuitTask(), 10);
392
393 Time start_time = Time::Now();
394
395 loop.Run();
396 EXPECT_EQ(1, num_tasks);
397
398 // Ensure that we ran in far less time than the slower timer.
[email protected]4615f1982008-09-23 19:22:33399 TimeDelta total_time = Time::Now() - start_time;
400 EXPECT_GT(5000, total_time.InMilliseconds());
[email protected]72deacd2008-09-23 19:19:20401
402 // In case both timers somehow run at nearly the same time, sleep a little
403 // and then run all pending to force them both to have run. This is just
404 // encouraging flakiness if there is any.
405 PlatformThread::Sleep(100);
406 loop.RunAllPending();
407
408 EXPECT_TRUE(run_time.is_null());
409}
410
411#endif // defined(OS_WIN)
412
[email protected]001747c2008-09-10 00:37:07413class RecordDeletionTask : public Task {
414 public:
415 RecordDeletionTask(Task* post_on_delete, bool* was_deleted)
416 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
417 }
418 ~RecordDeletionTask() {
419 *was_deleted_ = true;
420 if (post_on_delete_)
421 MessageLoop::current()->PostTask(FROM_HERE, post_on_delete_);
422 }
423 virtual void Run() {}
424 private:
425 Task* post_on_delete_;
426 bool* was_deleted_;
427};
428
429void RunTest_EnsureTaskDeletion(MessageLoop::Type message_loop_type) {
430 bool a_was_deleted = false;
431 bool b_was_deleted = false;
432 {
433 MessageLoop loop(message_loop_type);
434 loop.PostTask(
435 FROM_HERE, new RecordDeletionTask(NULL, &a_was_deleted));
436 loop.PostDelayedTask(
437 FROM_HERE, new RecordDeletionTask(NULL, &b_was_deleted), 1000);
438 }
439 EXPECT_TRUE(a_was_deleted);
440 EXPECT_TRUE(b_was_deleted);
441}
442
443void RunTest_EnsureTaskDeletion_Chain(MessageLoop::Type message_loop_type) {
444 bool a_was_deleted = false;
445 bool b_was_deleted = false;
446 bool c_was_deleted = false;
447 {
448 MessageLoop loop(message_loop_type);
449 RecordDeletionTask* a = new RecordDeletionTask(NULL, &a_was_deleted);
450 RecordDeletionTask* b = new RecordDeletionTask(a, &b_was_deleted);
451 RecordDeletionTask* c = new RecordDeletionTask(b, &c_was_deleted);
452 loop.PostTask(FROM_HERE, c);
453 }
454 EXPECT_TRUE(a_was_deleted);
455 EXPECT_TRUE(b_was_deleted);
456 EXPECT_TRUE(c_was_deleted);
457}
458
initial.commitd7cae122008-07-26 21:49:38459class NestingTest : public Task {
460 public:
461 explicit NestingTest(int* depth) : depth_(depth) {
462 }
463 void Run() {
464 if (*depth_ > 0) {
465 *depth_ -= 1;
466 MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(depth_));
467
468 MessageLoop::current()->SetNestableTasksAllowed(true);
469 MessageLoop::current()->Run();
470 }
471 MessageLoop::current()->Quit();
472 }
473 private:
474 int* depth_;
475};
476
[email protected]b16ef312008-08-19 18:36:23477#if defined(OS_WIN)
478
initial.commitd7cae122008-07-26 21:49:38479LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
480 ADD_FAILURE() << "bad exception handler";
481 ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode);
482 return EXCEPTION_EXECUTE_HANDLER;
483}
484
485// This task throws an SEH exception: initially write to an invalid address.
486// If the right SEH filter is installed, it will fix the error.
487class CrasherTask : public Task {
488 public:
489 // Ctor. If trash_SEH_handler is true, the task will override the unhandled
490 // exception handler with one sure to crash this test.
491 explicit CrasherTask(bool trash_SEH_handler)
492 : trash_SEH_handler_(trash_SEH_handler) {
493 }
494 void Run() {
[email protected]b16ef312008-08-19 18:36:23495 PlatformThread::Sleep(1);
initial.commitd7cae122008-07-26 21:49:38496 if (trash_SEH_handler_)
497 ::SetUnhandledExceptionFilter(&BadExceptionHandler);
498 // Generate a SEH fault. We do it in asm to make sure we know how to undo
499 // the damage.
[email protected]c88873922008-07-30 13:02:03500
501#if defined(_M_IX86)
502
initial.commitd7cae122008-07-26 21:49:38503 __asm {
504 mov eax, dword ptr [CrasherTask::bad_array_]
505 mov byte ptr [eax], 66
506 }
[email protected]c88873922008-07-30 13:02:03507
508#elif defined(_M_X64)
509
510 bad_array_[0] = 66;
511
[email protected]b16ef312008-08-19 18:36:23512#else
513#error "needs architecture support"
[email protected]c88873922008-07-30 13:02:03514#endif
515
initial.commitd7cae122008-07-26 21:49:38516 MessageLoop::current()->Quit();
517 }
518 // Points the bad array to a valid memory location.
519 static void FixError() {
520 bad_array_ = &valid_store_;
521 }
522
523 private:
524 bool trash_SEH_handler_;
525 static volatile char* bad_array_;
526 static char valid_store_;
527};
528
529volatile char* CrasherTask::bad_array_ = 0;
530char CrasherTask::valid_store_ = 0;
531
532// This SEH filter fixes the problem and retries execution. Fixing requires
533// that the last instruction: mov eax, [CrasherTask::bad_array_] to be retried
534// so we move the instruction pointer 5 bytes back.
535LONG WINAPI HandleCrasherTaskException(EXCEPTION_POINTERS *ex_info) {
536 if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
537 return EXCEPTION_EXECUTE_HANDLER;
538
539 CrasherTask::FixError();
[email protected]c88873922008-07-30 13:02:03540
541#if defined(_M_IX86)
542
initial.commitd7cae122008-07-26 21:49:38543 ex_info->ContextRecord->Eip -= 5;
[email protected]c88873922008-07-30 13:02:03544
545#elif defined(_M_X64)
546
547 ex_info->ContextRecord->Rip -= 5;
548
549#endif
550
initial.commitd7cae122008-07-26 21:49:38551 return EXCEPTION_CONTINUE_EXECUTION;
552}
553
[email protected]4d9bdfaf2008-08-26 05:53:57554void RunTest_Crasher(MessageLoop::Type message_loop_type) {
555 MessageLoop loop(message_loop_type);
[email protected]b16ef312008-08-19 18:36:23556
initial.commitd7cae122008-07-26 21:49:38557 if (::IsDebuggerPresent())
558 return;
559
560 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
561 ::SetUnhandledExceptionFilter(&HandleCrasherTaskException);
562
563 MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(false));
564 MessageLoop::current()->set_exception_restoration(true);
565 MessageLoop::current()->Run();
566 MessageLoop::current()->set_exception_restoration(false);
567
568 ::SetUnhandledExceptionFilter(old_SEH_filter);
569}
570
[email protected]4d9bdfaf2008-08-26 05:53:57571void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
572 MessageLoop loop(message_loop_type);
[email protected]32cda29d2008-10-09 23:58:43573
initial.commitd7cae122008-07-26 21:49:38574 if (::IsDebuggerPresent())
575 return;
576
577 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
578 ::SetUnhandledExceptionFilter(&HandleCrasherTaskException);
579
580 MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(true));
581 MessageLoop::current()->set_exception_restoration(true);
582 MessageLoop::current()->Run();
583 MessageLoop::current()->set_exception_restoration(false);
584
585 ::SetUnhandledExceptionFilter(old_SEH_filter);
586}
587
[email protected]295039bd2008-08-15 04:32:57588#endif // defined(OS_WIN)
589
[email protected]4d9bdfaf2008-08-26 05:53:57590void RunTest_Nesting(MessageLoop::Type message_loop_type) {
591 MessageLoop loop(message_loop_type);
[email protected]c88873922008-07-30 13:02:03592
initial.commitd7cae122008-07-26 21:49:38593 int depth = 100;
594 MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(&depth));
595 MessageLoop::current()->Run();
596 EXPECT_EQ(depth, 0);
597}
598
initial.commitd7cae122008-07-26 21:49:38599const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test";
600
601enum TaskType {
602 MESSAGEBOX,
603 ENDDIALOG,
604 RECURSIVE,
605 TIMEDMESSAGELOOP,
606 QUITMESSAGELOOP,
607 ORDERERD,
608 PUMPS,
[email protected]c4280a92009-06-25 19:23:11609 SLEEP,
initial.commitd7cae122008-07-26 21:49:38610};
611
612// Saves the order in which the tasks executed.
613struct TaskItem {
614 TaskItem(TaskType t, int c, bool s)
615 : type(t),
616 cookie(c),
617 start(s) {
618 }
619
620 TaskType type;
621 int cookie;
622 bool start;
623
624 bool operator == (const TaskItem& other) const {
625 return type == other.type && cookie == other.cookie && start == other.start;
626 }
627};
628
629typedef std::vector<TaskItem> TaskList;
630
631std::ostream& operator <<(std::ostream& os, TaskType type) {
632 switch (type) {
633 case MESSAGEBOX: os << "MESSAGEBOX"; break;
634 case ENDDIALOG: os << "ENDDIALOG"; break;
635 case RECURSIVE: os << "RECURSIVE"; break;
636 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break;
637 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break;
638 case ORDERERD: os << "ORDERERD"; break;
639 case PUMPS: os << "PUMPS"; break;
[email protected]c4280a92009-06-25 19:23:11640 case SLEEP: os << "SLEEP"; break;
initial.commitd7cae122008-07-26 21:49:38641 default:
642 NOTREACHED();
643 os << "Unknown TaskType";
644 break;
645 }
646 return os;
647}
648
649std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
650 if (item.start)
651 return os << item.type << " " << item.cookie << " starts";
652 else
653 return os << item.type << " " << item.cookie << " ends";
654}
655
656// Saves the order the tasks ran.
657class OrderedTasks : public Task {
658 public:
659 OrderedTasks(TaskList* order, int cookie)
660 : order_(order),
661 type_(ORDERERD),
662 cookie_(cookie) {
663 }
664 OrderedTasks(TaskList* order, TaskType type, int cookie)
665 : order_(order),
666 type_(type),
667 cookie_(cookie) {
668 }
669
670 void RunStart() {
671 TaskItem item(type_, cookie_, true);
[email protected]b026e35d2010-10-19 02:31:03672 DVLOG(1) << item;
initial.commitd7cae122008-07-26 21:49:38673 order_->push_back(item);
674 }
675 void RunEnd() {
676 TaskItem item(type_, cookie_, false);
[email protected]b026e35d2010-10-19 02:31:03677 DVLOG(1) << item;
initial.commitd7cae122008-07-26 21:49:38678 order_->push_back(item);
679 }
680
681 virtual void Run() {
682 RunStart();
683 RunEnd();
684 }
685
686 protected:
687 TaskList* order() const {
688 return order_;
689 }
690
691 int cookie() const {
692 return cookie_;
693 }
694
695 private:
696 TaskList* order_;
697 TaskType type_;
698 int cookie_;
699};
700
[email protected]b16ef312008-08-19 18:36:23701#if defined(OS_WIN)
702
initial.commitd7cae122008-07-26 21:49:38703// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
704// common controls (like OpenFile) and StartDoc printing function can cause
705// implicit message loops.
706class MessageBoxTask : public OrderedTasks {
707 public:
708 MessageBoxTask(TaskList* order, int cookie, bool is_reentrant)
709 : OrderedTasks(order, MESSAGEBOX, cookie),
710 is_reentrant_(is_reentrant) {
711 }
712
713 virtual void Run() {
714 RunStart();
715 if (is_reentrant_)
716 MessageLoop::current()->SetNestableTasksAllowed(true);
717 MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
718 RunEnd();
719 }
720
721 private:
722 bool is_reentrant_;
723};
724
725// Will end the MessageBox.
726class EndDialogTask : public OrderedTasks {
727 public:
728 EndDialogTask(TaskList* order, int cookie)
729 : OrderedTasks(order, ENDDIALOG, cookie) {
730 }
731
732 virtual void Run() {
733 RunStart();
734 HWND window = GetActiveWindow();
735 if (window != NULL) {
736 EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
737 // Cheap way to signal that the window wasn't found if RunEnd() isn't
738 // called.
739 RunEnd();
740 }
741 }
742};
743
[email protected]b16ef312008-08-19 18:36:23744#endif // defined(OS_WIN)
745
initial.commitd7cae122008-07-26 21:49:38746class RecursiveTask : public OrderedTasks {
747 public:
748 RecursiveTask(int depth, TaskList* order, int cookie, bool is_reentrant)
749 : OrderedTasks(order, RECURSIVE, cookie),
750 depth_(depth),
751 is_reentrant_(is_reentrant) {
752 }
753
754 virtual void Run() {
755 RunStart();
756 if (depth_ > 0) {
757 if (is_reentrant_)
758 MessageLoop::current()->SetNestableTasksAllowed(true);
759 MessageLoop::current()->PostTask(FROM_HERE,
760 new RecursiveTask(depth_ - 1, order(), cookie(), is_reentrant_));
761 }
762 RunEnd();
763 }
764
765 private:
766 int depth_;
767 bool is_reentrant_;
768};
769
770class QuitTask : public OrderedTasks {
771 public:
772 QuitTask(TaskList* order, int cookie)
773 : OrderedTasks(order, QUITMESSAGELOOP, cookie) {
774 }
775
776 virtual void Run() {
777 RunStart();
778 MessageLoop::current()->Quit();
779 RunEnd();
780 }
781};
782
[email protected]c4280a92009-06-25 19:23:11783class SleepTask : public OrderedTasks {
784 public:
785 SleepTask(TaskList* order, int cookie, int ms)
786 : OrderedTasks(order, SLEEP, cookie), ms_(ms) {
787 }
788
789 virtual void Run() {
790 RunStart();
791 PlatformThread::Sleep(ms_);
792 RunEnd();
793 }
794
795 private:
796 int ms_;
797};
798
[email protected]295039bd2008-08-15 04:32:57799#if defined(OS_WIN)
800
initial.commitd7cae122008-07-26 21:49:38801class Recursive2Tasks : public Task {
802 public:
803 Recursive2Tasks(MessageLoop* target,
804 HANDLE event,
805 bool expect_window,
806 TaskList* order,
807 bool is_reentrant)
808 : target_(target),
809 event_(event),
810 expect_window_(expect_window),
811 order_(order),
812 is_reentrant_(is_reentrant) {
813 }
814
815 virtual void Run() {
816 target_->PostTask(FROM_HERE,
817 new RecursiveTask(2, order_, 1, is_reentrant_));
818 target_->PostTask(FROM_HERE,
819 new MessageBoxTask(order_, 2, is_reentrant_));
820 target_->PostTask(FROM_HERE,
821 new RecursiveTask(2, order_, 3, is_reentrant_));
822 // The trick here is that for recursive task processing, this task will be
823 // ran _inside_ the MessageBox message loop, dismissing the MessageBox
824 // without a chance.
825 // For non-recursive task processing, this will be executed _after_ the
826 // MessageBox will have been dismissed by the code below, where
827 // expect_window_ is true.
828 target_->PostTask(FROM_HERE, new EndDialogTask(order_, 4));
829 target_->PostTask(FROM_HERE, new QuitTask(order_, 5));
830
831 // Enforce that every tasks are sent before starting to run the main thread
832 // message loop.
833 ASSERT_TRUE(SetEvent(event_));
834
835 // Poll for the MessageBox. Don't do this at home! At the speed we do it,
836 // you will never realize one MessageBox was shown.
837 for (; expect_window_;) {
838 HWND window = FindWindow(L"#32770", kMessageBoxTitle);
839 if (window) {
840 // Dismiss it.
841 for (;;) {
842 HWND button = FindWindowEx(window, NULL, L"Button", NULL);
843 if (button != NULL) {
[email protected]b7243c42010-07-23 05:23:13844 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
845 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
initial.commitd7cae122008-07-26 21:49:38846 break;
847 }
848 }
849 break;
850 }
851 }
852 }
853
854 private:
855 MessageLoop* target_;
856 HANDLE event_;
857 TaskList* order_;
858 bool expect_window_;
859 bool is_reentrant_;
860};
861
[email protected]295039bd2008-08-15 04:32:57862#endif // defined(OS_WIN)
863
[email protected]4d9bdfaf2008-08-26 05:53:57864void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
865 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:38866
initial.commitd7cae122008-07-26 21:49:38867 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
868 TaskList order;
869 MessageLoop::current()->PostTask(FROM_HERE,
870 new RecursiveTask(2, &order, 1, false));
871 MessageLoop::current()->PostTask(FROM_HERE,
872 new RecursiveTask(2, &order, 2, false));
873 MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3));
874
875 MessageLoop::current()->Run();
876
877 // FIFO order.
[email protected]b16ef312008-08-19 18:36:23878 ASSERT_EQ(14U, order.size());
initial.commitd7cae122008-07-26 21:49:38879 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
880 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
881 EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
882 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
883 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
884 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
885 EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true));
886 EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false));
887 EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
888 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
889 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
890 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
891 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true));
892 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
893}
894
[email protected]4d9bdfaf2008-08-26 05:53:57895void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
896 MessageLoop loop(message_loop_type);
[email protected]32cda29d2008-10-09 23:58:43897
initial.commitd7cae122008-07-26 21:49:38898 TaskList order;
899 MessageLoop::current()->PostTask(FROM_HERE,
900 new RecursiveTask(2, &order, 1, true));
901 MessageLoop::current()->PostTask(FROM_HERE,
902 new RecursiveTask(2, &order, 2, true));
903 MessageLoop::current()->PostTask(FROM_HERE,
904 new QuitTask(&order, 3));
905
906 MessageLoop::current()->Run();
907
908 // FIFO order.
[email protected]b16ef312008-08-19 18:36:23909 ASSERT_EQ(14U, order.size());
initial.commitd7cae122008-07-26 21:49:38910 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
911 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
912 EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
913 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
914 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
915 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
916 EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true));
917 EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false));
918 EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
919 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
920 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
921 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
922 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true));
923 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
924}
925
[email protected]295039bd2008-08-15 04:32:57926#if defined(OS_WIN)
927// TODO(darin): These tests need to be ported since they test critical
928// message loop functionality.
929
initial.commitd7cae122008-07-26 21:49:38930// A side effect of this test is the generation a beep. Sorry.
[email protected]4d9bdfaf2008-08-26 05:53:57931void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
932 MessageLoop loop(message_loop_type);
933
initial.commitd7cae122008-07-26 21:49:38934 Thread worker("RecursiveDenial2_worker");
[email protected]4d9bdfaf2008-08-26 05:53:57935 Thread::Options options;
936 options.message_loop_type = message_loop_type;
937 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commitd7cae122008-07-26 21:49:38938 TaskList order;
939 ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
940 worker.message_loop()->PostTask(FROM_HERE,
941 new Recursive2Tasks(MessageLoop::current(),
942 event,
943 true,
944 &order,
945 false));
946 // Let the other thread execute.
947 WaitForSingleObject(event, INFINITE);
948 MessageLoop::current()->Run();
949
950 ASSERT_EQ(order.size(), 17);
951 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
952 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
953 EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true));
954 EXPECT_EQ(order[ 3], TaskItem(MESSAGEBOX, 2, false));
955 EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, true));
956 EXPECT_EQ(order[ 5], TaskItem(RECURSIVE, 3, false));
957 // When EndDialogTask is processed, the window is already dismissed, hence no
958 // "end" entry.
959 EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, true));
960 EXPECT_EQ(order[ 7], TaskItem(QUITMESSAGELOOP, 5, true));
961 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, false));
962 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 1, true));
963 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, false));
964 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 3, true));
965 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, false));
966 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 1, true));
967 EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, false));
968 EXPECT_EQ(order[15], TaskItem(RECURSIVE, 3, true));
969 EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, false));
970}
971
[email protected]4d9bdfaf2008-08-26 05:53:57972// A side effect of this test is the generation a beep. Sorry. This test also
973// needs to process windows messages on the current thread.
974void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
975 MessageLoop loop(message_loop_type);
976
initial.commitd7cae122008-07-26 21:49:38977 Thread worker("RecursiveSupport2_worker");
[email protected]4d9bdfaf2008-08-26 05:53:57978 Thread::Options options;
979 options.message_loop_type = message_loop_type;
980 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commitd7cae122008-07-26 21:49:38981 TaskList order;
982 ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
983 worker.message_loop()->PostTask(FROM_HERE,
984 new Recursive2Tasks(MessageLoop::current(),
985 event,
986 false,
987 &order,
988 true));
989 // Let the other thread execute.
990 WaitForSingleObject(event, INFINITE);
991 MessageLoop::current()->Run();
992
993 ASSERT_EQ(order.size(), 18);
994 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
995 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
996 EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true));
997 // Note that this executes in the MessageBox modal loop.
998 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 3, true));
999 EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, false));
1000 EXPECT_EQ(order[ 5], TaskItem(ENDDIALOG, 4, true));
1001 EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, false));
1002 EXPECT_EQ(order[ 7], TaskItem(MESSAGEBOX, 2, false));
1003 /* The order can subtly change here. The reason is that when RecursiveTask(1)
1004 is called in the main thread, if it is faster than getting to the
1005 PostTask(FROM_HERE, QuitTask) execution, the order of task execution can
1006 change. We don't care anyway that the order isn't correct.
1007 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, true));
1008 EXPECT_EQ(order[ 9], TaskItem(QUITMESSAGELOOP, 5, false));
1009 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
1010 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
1011 */
1012 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, true));
1013 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 3, false));
1014 EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, true));
1015 EXPECT_EQ(order[15], TaskItem(RECURSIVE, 1, false));
1016 EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, true));
1017 EXPECT_EQ(order[17], TaskItem(RECURSIVE, 3, false));
1018}
1019
[email protected]295039bd2008-08-15 04:32:571020#endif // defined(OS_WIN)
1021
initial.commitd7cae122008-07-26 21:49:381022class TaskThatPumps : public OrderedTasks {
1023 public:
1024 TaskThatPumps(TaskList* order, int cookie)
1025 : OrderedTasks(order, PUMPS, cookie) {
1026 }
1027
1028 virtual void Run() {
1029 RunStart();
1030 bool old_state = MessageLoop::current()->NestableTasksAllowed();
initial.commitd7cae122008-07-26 21:49:381031 MessageLoop::current()->SetNestableTasksAllowed(true);
[email protected]295039bd2008-08-15 04:32:571032 MessageLoop::current()->RunAllPending();
initial.commitd7cae122008-07-26 21:49:381033 MessageLoop::current()->SetNestableTasksAllowed(old_state);
1034 RunEnd();
1035 }
initial.commitd7cae122008-07-26 21:49:381036};
1037
initial.commitd7cae122008-07-26 21:49:381038// Tests that non nestable tasks run in FIFO if there are no nested loops.
[email protected]4d9bdfaf2008-08-26 05:53:571039void RunTest_NonNestableWithNoNesting(MessageLoop::Type message_loop_type) {
1040 MessageLoop loop(message_loop_type);
1041
initial.commitd7cae122008-07-26 21:49:381042 TaskList order;
1043
1044 Task* task = new OrderedTasks(&order, 1);
[email protected]752578562008-09-07 08:08:291045 MessageLoop::current()->PostNonNestableTask(FROM_HERE, task);
initial.commitd7cae122008-07-26 21:49:381046 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 2));
1047 MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3));
1048 MessageLoop::current()->Run();
1049
1050 // FIFO order.
[email protected]b16ef312008-08-19 18:36:231051 ASSERT_EQ(6U, order.size());
initial.commitd7cae122008-07-26 21:49:381052 EXPECT_EQ(order[ 0], TaskItem(ORDERERD, 1, true));
1053 EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 1, false));
1054 EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 2, true));
1055 EXPECT_EQ(order[ 3], TaskItem(ORDERERD, 2, false));
1056 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
1057 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
1058}
1059
1060// Tests that non nestable tasks don't run when there's code in the call stack.
[email protected]c4280a92009-06-25 19:23:111061void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type,
1062 bool use_delayed) {
[email protected]4d9bdfaf2008-08-26 05:53:571063 MessageLoop loop(message_loop_type);
1064
initial.commitd7cae122008-07-26 21:49:381065 TaskList order;
1066
1067 MessageLoop::current()->PostTask(FROM_HERE,
1068 new TaskThatPumps(&order, 1));
1069 Task* task = new OrderedTasks(&order, 2);
[email protected]c4280a92009-06-25 19:23:111070 if (use_delayed) {
1071 MessageLoop::current()->PostNonNestableDelayedTask(FROM_HERE, task, 1);
1072 } else {
1073 MessageLoop::current()->PostNonNestableTask(FROM_HERE, task);
1074 }
initial.commitd7cae122008-07-26 21:49:381075 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 3));
[email protected]c4280a92009-06-25 19:23:111076 MessageLoop::current()->PostTask(FROM_HERE, new SleepTask(&order, 4, 50));
1077 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 5));
1078 Task* non_nestable_quit = new QuitTask(&order, 6);
1079 if (use_delayed) {
1080 MessageLoop::current()->PostNonNestableDelayedTask(FROM_HERE,
1081 non_nestable_quit,
1082 2);
1083 } else {
1084 MessageLoop::current()->PostNonNestableTask(FROM_HERE, non_nestable_quit);
1085 }
initial.commitd7cae122008-07-26 21:49:381086
initial.commitd7cae122008-07-26 21:49:381087 MessageLoop::current()->Run();
1088
1089 // FIFO order.
[email protected]c4280a92009-06-25 19:23:111090 ASSERT_EQ(12U, order.size());
initial.commitd7cae122008-07-26 21:49:381091 EXPECT_EQ(order[ 0], TaskItem(PUMPS, 1, true));
1092 EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 3, true));
1093 EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 3, false));
[email protected]c4280a92009-06-25 19:23:111094 EXPECT_EQ(order[ 3], TaskItem(SLEEP, 4, true));
1095 EXPECT_EQ(order[ 4], TaskItem(SLEEP, 4, false));
1096 EXPECT_EQ(order[ 5], TaskItem(ORDERERD, 5, true));
1097 EXPECT_EQ(order[ 6], TaskItem(ORDERERD, 5, false));
1098 EXPECT_EQ(order[ 7], TaskItem(PUMPS, 1, false));
1099 EXPECT_EQ(order[ 8], TaskItem(ORDERERD, 2, true));
1100 EXPECT_EQ(order[ 9], TaskItem(ORDERERD, 2, false));
1101 EXPECT_EQ(order[10], TaskItem(QUITMESSAGELOOP, 6, true));
1102 EXPECT_EQ(order[11], TaskItem(QUITMESSAGELOOP, 6, false));
initial.commitd7cae122008-07-26 21:49:381103}
1104
[email protected]295039bd2008-08-15 04:32:571105#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:381106
[email protected]4d9bdfaf2008-08-26 05:53:571107class DispatcherImpl : public MessageLoopForUI::Dispatcher {
initial.commitd7cae122008-07-26 21:49:381108 public:
1109 DispatcherImpl() : dispatch_count_(0) {}
1110
1111 virtual bool Dispatch(const MSG& msg) {
1112 ::TranslateMessage(&msg);
1113 ::DispatchMessage(&msg);
[email protected]6aa4a1c02010-01-15 18:49:581114 // Do not count WM_TIMER since it is not what we post and it will cause
1115 // flakiness.
1116 if (msg.message != WM_TIMER)
1117 ++dispatch_count_;
1118 // We treat WM_LBUTTONUP as the last message.
1119 return msg.message != WM_LBUTTONUP;
initial.commitd7cae122008-07-26 21:49:381120 }
1121
1122 int dispatch_count_;
1123};
1124
[email protected]4d9bdfaf2008-08-26 05:53:571125void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
1126 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:381127
initial.commitd7cae122008-07-26 21:49:381128 class MyTask : public Task {
1129 public:
1130 virtual void Run() {
1131 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
1132 PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
1133 }
1134 };
1135 Task* task = new MyTask();
1136 MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100);
1137 DispatcherImpl dispatcher;
[email protected]4d9bdfaf2008-08-26 05:53:571138 MessageLoopForUI::current()->Run(&dispatcher);
initial.commitd7cae122008-07-26 21:49:381139 ASSERT_EQ(2, dispatcher.dispatch_count_);
1140}
[email protected]295039bd2008-08-15 04:32:571141
[email protected]6aa4a1c02010-01-15 18:49:581142LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
1143 if (code == base::MessagePumpForUI::kMessageFilterCode) {
1144 MSG* msg = reinterpret_cast<MSG*>(lparam);
1145 if (msg->message == WM_LBUTTONDOWN)
1146 return TRUE;
1147 }
1148 return FALSE;
1149}
1150
1151void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
1152 MessageLoop loop(message_loop_type);
1153
1154 class MyTask : public Task {
1155 public:
1156 virtual void Run() {
1157 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
1158 PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
1159 }
1160 };
1161 Task* task = new MyTask();
1162 MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100);
1163 HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
1164 MsgFilterProc,
1165 NULL,
1166 GetCurrentThreadId());
1167 DispatcherImpl dispatcher;
1168 MessageLoopForUI::current()->Run(&dispatcher);
1169 ASSERT_EQ(1, dispatcher.dispatch_count_);
1170 UnhookWindowsHookEx(msg_hook);
1171}
1172
[email protected]32cda29d2008-10-09 23:58:431173class TestIOHandler : public MessageLoopForIO::IOHandler {
1174 public:
[email protected]17b89142008-11-07 21:52:151175 TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
[email protected]32cda29d2008-10-09 23:58:431176
[email protected]17b89142008-11-07 21:52:151177 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
1178 DWORD bytes_transfered, DWORD error);
[email protected]32cda29d2008-10-09 23:58:431179
[email protected]17b89142008-11-07 21:52:151180 void Init();
1181 void WaitForIO();
1182 OVERLAPPED* context() { return &context_.overlapped; }
[email protected]32cda29d2008-10-09 23:58:431183 DWORD size() { return sizeof(buffer_); }
1184
1185 private:
1186 char buffer_[48];
[email protected]17b89142008-11-07 21:52:151187 MessageLoopForIO::IOContext context_;
[email protected]32cda29d2008-10-09 23:58:431188 HANDLE signal_;
1189 ScopedHandle file_;
[email protected]17b89142008-11-07 21:52:151190 bool wait_;
[email protected]32cda29d2008-10-09 23:58:431191};
1192
[email protected]17b89142008-11-07 21:52:151193TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
1194 : signal_(signal), wait_(wait) {
[email protected]32cda29d2008-10-09 23:58:431195 memset(buffer_, 0, sizeof(buffer_));
1196 memset(&context_, 0, sizeof(context_));
[email protected]17b89142008-11-07 21:52:151197 context_.handler = this;
[email protected]32cda29d2008-10-09 23:58:431198
1199 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1200 FILE_FLAG_OVERLAPPED, NULL));
1201 EXPECT_TRUE(file_.IsValid());
1202}
1203
[email protected]17b89142008-11-07 21:52:151204void TestIOHandler::Init() {
1205 MessageLoopForIO::current()->RegisterIOHandler(file_, this);
1206
1207 DWORD read;
1208 EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context()));
1209 EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
1210 if (wait_)
1211 WaitForIO();
1212}
1213
1214void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
1215 DWORD bytes_transfered, DWORD error) {
[email protected]32cda29d2008-10-09 23:58:431216 ASSERT_TRUE(context == &context_);
[email protected]32cda29d2008-10-09 23:58:431217 ASSERT_TRUE(SetEvent(signal_));
1218}
1219
[email protected]17b89142008-11-07 21:52:151220void TestIOHandler::WaitForIO() {
1221 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
1222 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
1223}
1224
[email protected]32cda29d2008-10-09 23:58:431225class IOHandlerTask : public Task {
1226 public:
1227 explicit IOHandlerTask(TestIOHandler* handler) : handler_(handler) {}
[email protected]17b89142008-11-07 21:52:151228 virtual void Run() {
1229 handler_->Init();
1230 }
[email protected]32cda29d2008-10-09 23:58:431231
1232 private:
1233 TestIOHandler* handler_;
1234};
1235
[email protected]32cda29d2008-10-09 23:58:431236void RunTest_IOHandler() {
[email protected]32cda29d2008-10-09 23:58:431237 ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
1238 ASSERT_TRUE(callback_called.IsValid());
1239
1240 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
1241 ScopedHandle server(CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1,
1242 0, 0, 0, NULL));
1243 ASSERT_TRUE(server.IsValid());
1244
1245 Thread thread("IOHandler test");
1246 Thread::Options options;
1247 options.message_loop_type = MessageLoop::TYPE_IO;
1248 ASSERT_TRUE(thread.StartWithOptions(options));
1249
1250 MessageLoop* thread_loop = thread.message_loop();
1251 ASSERT_TRUE(NULL != thread_loop);
1252
[email protected]17b89142008-11-07 21:52:151253 TestIOHandler handler(kPipeName, callback_called, false);
[email protected]32cda29d2008-10-09 23:58:431254 IOHandlerTask* task = new IOHandlerTask(&handler);
1255 thread_loop->PostTask(FROM_HERE, task);
1256 Sleep(100); // Make sure the thread runs and sleeps for lack of work.
1257
1258 const char buffer[] = "Hello there!";
1259 DWORD written;
1260 EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL));
1261
1262 DWORD result = WaitForSingleObject(callback_called, 1000);
1263 EXPECT_EQ(WAIT_OBJECT_0, result);
1264
1265 thread.Stop();
1266}
1267
[email protected]17b89142008-11-07 21:52:151268void RunTest_WaitForIO() {
1269 ScopedHandle callback1_called(CreateEvent(NULL, TRUE, FALSE, NULL));
1270 ScopedHandle callback2_called(CreateEvent(NULL, TRUE, FALSE, NULL));
1271 ASSERT_TRUE(callback1_called.IsValid());
1272 ASSERT_TRUE(callback2_called.IsValid());
1273
1274 const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
1275 const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
1276 ScopedHandle server1(CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1,
1277 0, 0, 0, NULL));
1278 ScopedHandle server2(CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1,
1279 0, 0, 0, NULL));
1280 ASSERT_TRUE(server1.IsValid());
1281 ASSERT_TRUE(server2.IsValid());
1282
1283 Thread thread("IOHandler test");
1284 Thread::Options options;
1285 options.message_loop_type = MessageLoop::TYPE_IO;
1286 ASSERT_TRUE(thread.StartWithOptions(options));
1287
1288 MessageLoop* thread_loop = thread.message_loop();
1289 ASSERT_TRUE(NULL != thread_loop);
1290
1291 TestIOHandler handler1(kPipeName1, callback1_called, false);
1292 TestIOHandler handler2(kPipeName2, callback2_called, true);
1293 IOHandlerTask* task1 = new IOHandlerTask(&handler1);
1294 IOHandlerTask* task2 = new IOHandlerTask(&handler2);
1295 thread_loop->PostTask(FROM_HERE, task1);
1296 Sleep(100); // Make sure the thread runs and sleeps for lack of work.
1297 thread_loop->PostTask(FROM_HERE, task2);
1298 Sleep(100);
1299
1300 // At this time handler1 is waiting to be called, and the thread is waiting
1301 // on the Init method of handler2, filtering only handler2 callbacks.
1302
1303 const char buffer[] = "Hello there!";
1304 DWORD written;
1305 EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL));
1306 Sleep(200);
1307 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) <<
1308 "handler1 has not been called";
1309
1310 EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL));
1311
1312 HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
1313 DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
1314 EXPECT_EQ(WAIT_OBJECT_0, result);
1315
1316 thread.Stop();
1317}
1318
[email protected]4d9bdfaf2008-08-26 05:53:571319#endif // defined(OS_WIN)
license.botbf09a502008-08-24 00:55:551320
[email protected]4d9bdfaf2008-08-26 05:53:571321} // namespace
1322
1323//-----------------------------------------------------------------------------
1324// Each test is run against each type of MessageLoop. That way we are sure
1325// that message loops work properly in all configurations. Of course, in some
1326// cases, a unit test may only be for a particular type of loop.
1327
1328TEST(MessageLoopTest, PostTask) {
1329 RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
1330 RunTest_PostTask(MessageLoop::TYPE_UI);
1331 RunTest_PostTask(MessageLoop::TYPE_IO);
1332}
1333
1334TEST(MessageLoopTest, PostTask_SEH) {
1335 RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT);
1336 RunTest_PostTask_SEH(MessageLoop::TYPE_UI);
1337 RunTest_PostTask_SEH(MessageLoop::TYPE_IO);
1338}
1339
[email protected]752578562008-09-07 08:08:291340TEST(MessageLoopTest, PostDelayedTask_Basic) {
1341 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT);
1342 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI);
1343 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO);
1344}
1345
1346TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) {
1347 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT);
1348 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI);
1349 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO);
1350}
1351
1352TEST(MessageLoopTest, PostDelayedTask_InPostOrder) {
1353 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT);
1354 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI);
1355 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO);
1356}
1357
1358TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) {
1359 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT);
1360 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI);
1361 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO);
1362}
1363
1364TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) {
1365 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT);
1366 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI);
1367 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO);
1368}
1369
[email protected]72deacd2008-09-23 19:19:201370TEST(MessageLoopTest, PostDelayedTask_SharedTimer) {
1371 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT);
1372 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI);
1373 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO);
1374}
1375
1376#if defined(OS_WIN)
1377TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
1378 RunTest_PostDelayedTask_SharedTimer_SubPump();
1379}
1380#endif
1381
[email protected]5affb7e2010-05-25 20:13:361382// TODO(darin): MessageLoop does not support deleting all tasks in the
1383// destructor.
[email protected]2f861b32010-07-26 21:23:181384// Fails, http://crbug.com/50272.
[email protected]5affb7e2010-05-25 20:13:361385TEST(MessageLoopTest, FAILS_EnsureTaskDeletion) {
[email protected]001747c2008-09-10 00:37:071386 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_DEFAULT);
1387 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_UI);
1388 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_IO);
1389}
1390
[email protected]5affb7e2010-05-25 20:13:361391// TODO(darin): MessageLoop does not support deleting all tasks in the
1392// destructor.
[email protected]2f861b32010-07-26 21:23:181393// Fails, http://crbug.com/50272.
[email protected]5affb7e2010-05-25 20:13:361394TEST(MessageLoopTest, FAILS_EnsureTaskDeletion_Chain) {
[email protected]001747c2008-09-10 00:37:071395 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_DEFAULT);
1396 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_UI);
1397 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_IO);
1398}
1399
[email protected]4d9bdfaf2008-08-26 05:53:571400#if defined(OS_WIN)
1401TEST(MessageLoopTest, Crasher) {
1402 RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
1403 RunTest_Crasher(MessageLoop::TYPE_UI);
1404 RunTest_Crasher(MessageLoop::TYPE_IO);
1405}
1406
1407TEST(MessageLoopTest, CrasherNasty) {
1408 RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
1409 RunTest_CrasherNasty(MessageLoop::TYPE_UI);
1410 RunTest_CrasherNasty(MessageLoop::TYPE_IO);
1411}
1412#endif // defined(OS_WIN)
1413
1414TEST(MessageLoopTest, Nesting) {
1415 RunTest_Nesting(MessageLoop::TYPE_DEFAULT);
1416 RunTest_Nesting(MessageLoop::TYPE_UI);
1417 RunTest_Nesting(MessageLoop::TYPE_IO);
1418}
1419
1420TEST(MessageLoopTest, RecursiveDenial1) {
1421 RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT);
1422 RunTest_RecursiveDenial1(MessageLoop::TYPE_UI);
1423 RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
1424}
1425
1426TEST(MessageLoopTest, RecursiveSupport1) {
1427 RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
1428 RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
1429 RunTest_RecursiveSupport1(MessageLoop::TYPE_IO);
1430}
1431
1432#if defined(OS_WIN)
[email protected]85f39f82010-05-19 14:33:441433// This test occasionally hangs http://crbug.com/44567
1434TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
[email protected]4d9bdfaf2008-08-26 05:53:571435 RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
1436 RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
1437 RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
1438}
1439
1440TEST(MessageLoopTest, RecursiveSupport2) {
1441 // This test requires a UI loop
1442 RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
1443}
1444#endif // defined(OS_WIN)
1445
1446TEST(MessageLoopTest, NonNestableWithNoNesting) {
1447 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT);
1448 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI);
1449 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO);
1450}
1451
1452TEST(MessageLoopTest, NonNestableInNestedLoop) {
[email protected]c4280a92009-06-25 19:23:111453 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false);
1454 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false);
1455 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false);
1456}
1457
1458TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) {
1459 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true);
1460 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true);
1461 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true);
[email protected]4d9bdfaf2008-08-26 05:53:571462}
1463
[email protected]9cfb89a2010-06-09 21:20:411464class DummyTask : public Task {
1465 public:
[email protected]b7243c42010-07-23 05:23:131466 explicit DummyTask(int num_tasks) : num_tasks_(num_tasks) {}
[email protected]9cfb89a2010-06-09 21:20:411467
1468 virtual void Run() {
1469 if (num_tasks_ > 1) {
1470 MessageLoop::current()->PostTask(
1471 FROM_HERE,
1472 new DummyTask(num_tasks_ - 1));
1473 } else {
1474 MessageLoop::current()->Quit();
1475 }
1476 }
1477
1478 private:
1479 const int num_tasks_;
1480};
1481
1482class DummyTaskObserver : public MessageLoop::TaskObserver {
1483 public:
[email protected]b7243c42010-07-23 05:23:131484 explicit DummyTaskObserver(int num_tasks)
[email protected]9cfb89a2010-06-09 21:20:411485 : num_tasks_started_(0),
1486 num_tasks_processed_(0),
1487 num_tasks_(num_tasks) {}
1488
1489 virtual ~DummyTaskObserver() {}
1490
[email protected]024686682010-10-26 23:40:481491 virtual void WillProcessTask(const Task* task) {
[email protected]9cfb89a2010-06-09 21:20:411492 num_tasks_started_++;
[email protected]024686682010-10-26 23:40:481493 EXPECT_TRUE(task != NULL);
[email protected]9cfb89a2010-06-09 21:20:411494 EXPECT_LE(num_tasks_started_, num_tasks_);
1495 EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
1496 }
1497
[email protected]024686682010-10-26 23:40:481498 virtual void DidProcessTask(const Task* task) {
[email protected]9cfb89a2010-06-09 21:20:411499 num_tasks_processed_++;
[email protected]024686682010-10-26 23:40:481500 EXPECT_TRUE(task != NULL);
[email protected]9cfb89a2010-06-09 21:20:411501 EXPECT_LE(num_tasks_started_, num_tasks_);
1502 EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
1503 }
1504
1505 int num_tasks_started() const { return num_tasks_started_; }
1506 int num_tasks_processed() const { return num_tasks_processed_; }
1507
1508 private:
1509 int num_tasks_started_;
1510 int num_tasks_processed_;
1511 const int num_tasks_;
1512
1513 DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
1514};
1515
1516TEST(MessageLoopTest, TaskObserver) {
1517 const int kNumTasks = 6;
1518 DummyTaskObserver observer(kNumTasks);
1519
1520 MessageLoop loop;
1521 loop.AddTaskObserver(&observer);
1522 loop.PostTask(FROM_HERE, new DummyTask(kNumTasks));
1523 loop.Run();
1524 loop.RemoveTaskObserver(&observer);
1525
1526 EXPECT_EQ(kNumTasks, observer.num_tasks_started());
1527 EXPECT_EQ(kNumTasks, observer.num_tasks_processed());
1528}
1529
[email protected]4d9bdfaf2008-08-26 05:53:571530#if defined(OS_WIN)
[email protected]4d9bdfaf2008-08-26 05:53:571531TEST(MessageLoopTest, Dispatcher) {
1532 // This test requires a UI loop
1533 RunTest_Dispatcher(MessageLoop::TYPE_UI);
1534}
[email protected]32cda29d2008-10-09 23:58:431535
[email protected]6aa4a1c02010-01-15 18:49:581536TEST(MessageLoopTest, DispatcherWithMessageHook) {
1537 // This test requires a UI loop
1538 RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
1539}
1540
[email protected]32cda29d2008-10-09 23:58:431541TEST(MessageLoopTest, IOHandler) {
1542 RunTest_IOHandler();
1543}
[email protected]17b89142008-11-07 21:52:151544
1545TEST(MessageLoopTest, WaitForIO) {
1546 RunTest_WaitForIO();
1547}
[email protected]57f030a2010-06-29 04:58:151548
1549TEST(MessageLoopTest, HighResolutionTimer) {
1550 MessageLoop loop;
1551
1552 const int kFastTimerMs = 5;
1553 const int kSlowTimerMs = 100;
1554
1555 EXPECT_EQ(false, loop.high_resolution_timers_enabled());
1556
1557 // Post a fast task to enable the high resolution timers.
1558 loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kFastTimerMs);
1559 loop.Run();
1560 EXPECT_EQ(true, loop.high_resolution_timers_enabled());
1561
1562 // Post a slow task and verify high resolution timers
1563 // are still enabled.
1564 loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs);
1565 loop.Run();
1566 EXPECT_EQ(true, loop.high_resolution_timers_enabled());
1567
1568 // Wait for a while so that high-resolution mode elapses.
1569 Sleep(MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
1570
1571 // Post a slow task to disable the high resolution timers.
1572 loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs);
1573 loop.Run();
1574 EXPECT_EQ(false, loop.high_resolution_timers_enabled());
1575}
1576
[email protected]4d9bdfaf2008-08-26 05:53:571577#endif // defined(OS_WIN)
[email protected]f74c8962009-04-22 20:01:361578
[email protected]5cffdfd2010-12-01 08:45:511579#if defined(OS_POSIX) && !defined(OS_NACL)
[email protected]f74c8962009-04-22 20:01:361580
1581namespace {
1582
[email protected]9cfb89a2010-06-09 21:20:411583class QuitDelegate : public base::MessagePumpLibevent::Watcher {
[email protected]f74c8962009-04-22 20:01:361584 public:
1585 virtual void OnFileCanWriteWithoutBlocking(int fd) {
1586 MessageLoop::current()->Quit();
1587 }
1588 virtual void OnFileCanReadWithoutBlocking(int fd) {
1589 MessageLoop::current()->Quit();
1590 }
1591};
1592
[email protected]f45213772010-06-11 00:06:191593TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
[email protected]f74c8962009-04-22 20:01:361594 // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
1595 // This could happen when people use the Singleton pattern or atexit.
[email protected]f74c8962009-04-22 20:01:361596
1597 // Create a file descriptor. Doesn't need to be readable or writable,
1598 // as we don't need to actually get any notifications.
1599 // pipe() is just the easiest way to do it.
1600 int pipefds[2];
1601 int err = pipe(pipefds);
[email protected]b7243c42010-07-23 05:23:131602 ASSERT_EQ(0, err);
[email protected]f74c8962009-04-22 20:01:361603 int fd = pipefds[1];
1604 {
1605 // Arrange for controller to live longer than message loop.
1606 base::MessagePumpLibevent::FileDescriptorWatcher controller;
1607 {
1608 MessageLoopForIO message_loop;
1609
1610 QuitDelegate delegate;
1611 message_loop.WatchFileDescriptor(fd,
1612 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
1613 // and don't run the message loop, just destroy it.
1614 }
1615 }
[email protected]70eb6572010-06-23 00:37:461616 if (HANDLE_EINTR(close(pipefds[0])) < 0)
1617 PLOG(ERROR) << "close";
1618 if (HANDLE_EINTR(close(pipefds[1])) < 0)
1619 PLOG(ERROR) << "close";
[email protected]f74c8962009-04-22 20:01:361620}
1621
1622TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
1623 // Verify that it's ok to call StopWatchingFileDescriptor().
1624 // (Errors only showed up in valgrind.)
1625 int pipefds[2];
1626 int err = pipe(pipefds);
[email protected]b7243c42010-07-23 05:23:131627 ASSERT_EQ(0, err);
[email protected]f74c8962009-04-22 20:01:361628 int fd = pipefds[1];
1629 {
1630 // Arrange for message loop to live longer than controller.
1631 MessageLoopForIO message_loop;
1632 {
1633 base::MessagePumpLibevent::FileDescriptorWatcher controller;
1634
1635 QuitDelegate delegate;
1636 message_loop.WatchFileDescriptor(fd,
1637 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
1638 controller.StopWatchingFileDescriptor();
1639 }
1640 }
[email protected]70eb6572010-06-23 00:37:461641 if (HANDLE_EINTR(close(pipefds[0])) < 0)
1642 PLOG(ERROR) << "close";
1643 if (HANDLE_EINTR(close(pipefds[1])) < 0)
1644 PLOG(ERROR) << "close";
[email protected]f74c8962009-04-22 20:01:361645}
1646
[email protected]9cfb89a2010-06-09 21:20:411647} // namespace
1648
[email protected]5cffdfd2010-12-01 08:45:511649#endif // defined(OS_POSIX) && !defined(OS_NACL)
[email protected]582384772010-11-30 00:25:291650
1651namespace {
1652class RunAtDestructionTask : public Task {
1653 public:
1654 RunAtDestructionTask(bool* task_destroyed, bool* destruction_observer_called)
1655 : task_destroyed_(task_destroyed),
1656 destruction_observer_called_(destruction_observer_called) {
1657 }
1658 ~RunAtDestructionTask() {
1659 EXPECT_FALSE(*destruction_observer_called_);
1660 *task_destroyed_ = true;
1661 }
1662 virtual void Run() {
1663 // This task should never run.
1664 ADD_FAILURE();
1665 }
1666 private:
1667 bool* task_destroyed_;
1668 bool* destruction_observer_called_;
1669};
1670
1671class MLDestructionObserver : public MessageLoop::DestructionObserver {
1672 public:
1673 MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
1674 : task_destroyed_(task_destroyed),
1675 destruction_observer_called_(destruction_observer_called),
1676 task_destroyed_before_message_loop_(false) {
1677 }
1678 virtual void WillDestroyCurrentMessageLoop() {
1679 task_destroyed_before_message_loop_ = *task_destroyed_;
1680 *destruction_observer_called_ = true;
1681 }
1682 bool task_destroyed_before_message_loop() const {
1683 return task_destroyed_before_message_loop_;
1684 }
1685 private:
1686 bool* task_destroyed_;
1687 bool* destruction_observer_called_;
1688 bool task_destroyed_before_message_loop_;
1689};
1690
1691} // namespace
1692
1693TEST(MessageLoopTest, DestructionObserverTest) {
1694 // Verify that the destruction observer gets called at the very end (after
1695 // all the pending tasks have been destroyed).
1696 MessageLoop* loop = new MessageLoop;
1697 const int kDelayMS = 100;
1698
1699 bool task_destroyed = false;
1700 bool destruction_observer_called = false;
1701
1702 MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
1703 loop->AddDestructionObserver(&observer);
1704 loop->PostDelayedTask(
1705 FROM_HERE,
1706 new RunAtDestructionTask(&task_destroyed, &destruction_observer_called),
1707 kDelayMS);
1708 delete loop;
1709 EXPECT_TRUE(observer.task_destroyed_before_message_loop());
1710 // The task should have been destroyed when we deleted the loop.
1711 EXPECT_TRUE(task_destroyed);
1712 EXPECT_TRUE(destruction_observer_called);
1713}