1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <vector>
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/compiler_specific.h"
10#include "base/logging.h"
11#include "base/memory/ref_counted.h"
12#include "base/message_loop/message_loop.h"
13#include "base/message_loop/message_loop_proxy_impl.h"
14#include "base/message_loop/message_loop_test.h"
15#include "base/pending_task.h"
16#include "base/posix/eintr_wrapper.h"
17#include "base/run_loop.h"
18#include "base/synchronization/waitable_event.h"
19#include "base/thread_task_runner_handle.h"
20#include "base/threading/platform_thread.h"
21#include "base/threading/thread.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24#if defined(OS_WIN)
25#include "base/message_loop/message_pump_win.h"
26#include "base/process/memory.h"
27#include "base/strings/string16.h"
28#include "base/win/scoped_handle.h"
29#endif
30
31namespace base {
32
33// TODO(darin): Platform-specific MessageLoop tests should be grouped together
34// to avoid chopping this file up with so many #ifdefs.
35
36namespace {
37
38MessagePump* TypeDefaultMessagePumpFactory() {
39  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_DEFAULT);
40}
41
42MessagePump* TypeIOMessagePumpFactory() {
43  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_IO);
44}
45
46MessagePump* TypeUIMessagePumpFactory() {
47  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_UI);
48}
49
50class Foo : public RefCounted<Foo> {
51 public:
52  Foo() : test_count_(0) {
53  }
54
55  void Test0() {
56    ++test_count_;
57  }
58
59  void Test1ConstRef(const std::string& a) {
60    ++test_count_;
61    result_.append(a);
62  }
63
64  void Test1Ptr(std::string* a) {
65    ++test_count_;
66    result_.append(*a);
67  }
68
69  void Test1Int(int a) {
70    test_count_ += a;
71  }
72
73  void Test2Ptr(std::string* a, std::string* b) {
74    ++test_count_;
75    result_.append(*a);
76    result_.append(*b);
77  }
78
79  void Test2Mixed(const std::string& a, std::string* b) {
80    ++test_count_;
81    result_.append(a);
82    result_.append(*b);
83  }
84
85  int test_count() const { return test_count_; }
86  const std::string& result() const { return result_; }
87
88 private:
89  friend class RefCounted<Foo>;
90
91  ~Foo() {}
92
93  int test_count_;
94  std::string result_;
95};
96
97#if defined(OS_WIN)
98
99// This function runs slowly to simulate a large amount of work being done.
100static void SlowFunc(TimeDelta pause, int* quit_counter) {
101    PlatformThread::Sleep(pause);
102    if (--(*quit_counter) == 0)
103      MessageLoop::current()->QuitWhenIdle();
104}
105
106// This function records the time when Run was called in a Time object, which is
107// useful for building a variety of MessageLoop tests.
108static void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
109  *run_time = Time::Now();
110
111    // Cause our Run function to take some time to execute.  As a result we can
112    // count on subsequent RecordRunTimeFunc()s running at a future time,
113    // without worry about the resolution of our system clock being an issue.
114  SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
115}
116
117void SubPumpFunc() {
118  MessageLoop::current()->SetNestableTasksAllowed(true);
119  MSG msg;
120  while (GetMessage(&msg, NULL, 0, 0)) {
121    TranslateMessage(&msg);
122    DispatchMessage(&msg);
123  }
124  MessageLoop::current()->QuitWhenIdle();
125}
126
127void RunTest_PostDelayedTask_SharedTimer_SubPump() {
128  MessageLoop loop(MessageLoop::TYPE_UI);
129
130  // Test that the interval of the timer, used to run the next delayed task, is
131  // set to a value corresponding to when the next delayed task should run.
132
133  // By setting num_tasks to 1, we ensure that the first task to run causes the
134  // run loop to exit.
135  int num_tasks = 1;
136  Time run_time;
137
138  loop.PostTask(FROM_HERE, Bind(&SubPumpFunc));
139
140  // This very delayed task should never run.
141  loop.PostDelayedTask(
142      FROM_HERE,
143      Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
144      TimeDelta::FromSeconds(1000));
145
146  // This slightly delayed task should run from within SubPumpFunc).
147  loop.PostDelayedTask(
148      FROM_HERE,
149      Bind(&PostQuitMessage, 0),
150      TimeDelta::FromMilliseconds(10));
151
152  Time start_time = Time::Now();
153
154  loop.Run();
155  EXPECT_EQ(1, num_tasks);
156
157  // Ensure that we ran in far less time than the slower timer.
158  TimeDelta total_time = Time::Now() - start_time;
159  EXPECT_GT(5000, total_time.InMilliseconds());
160
161  // In case both timers somehow run at nearly the same time, sleep a little
162  // and then run all pending to force them both to have run.  This is just
163  // encouraging flakiness if there is any.
164  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
165  RunLoop().RunUntilIdle();
166
167  EXPECT_TRUE(run_time.is_null());
168}
169
170LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
171  ADD_FAILURE() << "bad exception handler";
172  ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode);
173  return EXCEPTION_EXECUTE_HANDLER;
174}
175
176// This task throws an SEH exception: initially write to an invalid address.
177// If the right SEH filter is installed, it will fix the error.
178class Crasher : public RefCounted<Crasher> {
179 public:
180  // Ctor. If trash_SEH_handler is true, the task will override the unhandled
181  // exception handler with one sure to crash this test.
182  explicit Crasher(bool trash_SEH_handler)
183      : trash_SEH_handler_(trash_SEH_handler) {
184  }
185
186  void Run() {
187    PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
188    if (trash_SEH_handler_)
189      ::SetUnhandledExceptionFilter(&BadExceptionHandler);
190    // Generate a SEH fault. We do it in asm to make sure we know how to undo
191    // the damage.
192
193#if defined(_M_IX86)
194
195    __asm {
196      mov eax, dword ptr [Crasher::bad_array_]
197      mov byte ptr [eax], 66
198    }
199
200#elif defined(_M_X64)
201
202    bad_array_[0] = 66;
203
204#else
205#error "needs architecture support"
206#endif
207
208    MessageLoop::current()->QuitWhenIdle();
209  }
210  // Points the bad array to a valid memory location.
211  static void FixError() {
212    bad_array_ = &valid_store_;
213  }
214
215 private:
216  bool trash_SEH_handler_;
217  static volatile char* bad_array_;
218  static char valid_store_;
219};
220
221volatile char* Crasher::bad_array_ = 0;
222char Crasher::valid_store_ = 0;
223
224// This SEH filter fixes the problem and retries execution. Fixing requires
225// that the last instruction: mov eax, [Crasher::bad_array_] to be retried
226// so we move the instruction pointer 5 bytes back.
227LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) {
228  if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
229    return EXCEPTION_EXECUTE_HANDLER;
230
231  Crasher::FixError();
232
233#if defined(_M_IX86)
234
235  ex_info->ContextRecord->Eip -= 5;
236
237#elif defined(_M_X64)
238
239  ex_info->ContextRecord->Rip -= 5;
240
241#endif
242
243  return EXCEPTION_CONTINUE_EXECUTION;
244}
245
246void RunTest_Crasher(MessageLoop::Type message_loop_type) {
247  MessageLoop loop(message_loop_type);
248
249  if (::IsDebuggerPresent())
250    return;
251
252  LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
253      ::SetUnhandledExceptionFilter(&HandleCrasherException);
254
255  MessageLoop::current()->PostTask(
256      FROM_HERE,
257      Bind(&Crasher::Run, new Crasher(false)));
258  MessageLoop::current()->set_exception_restoration(true);
259  MessageLoop::current()->Run();
260  MessageLoop::current()->set_exception_restoration(false);
261
262  ::SetUnhandledExceptionFilter(old_SEH_filter);
263}
264
265void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
266  MessageLoop loop(message_loop_type);
267
268  if (::IsDebuggerPresent())
269    return;
270
271  LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
272      ::SetUnhandledExceptionFilter(&HandleCrasherException);
273
274  MessageLoop::current()->PostTask(
275      FROM_HERE,
276      Bind(&Crasher::Run, new Crasher(true)));
277  MessageLoop::current()->set_exception_restoration(true);
278  MessageLoop::current()->Run();
279  MessageLoop::current()->set_exception_restoration(false);
280
281  ::SetUnhandledExceptionFilter(old_SEH_filter);
282}
283
284const wchar_t kMessageBoxTitle[] = L"MessageLoop Unit Test";
285
286enum TaskType {
287  MESSAGEBOX,
288  ENDDIALOG,
289  RECURSIVE,
290  TIMEDMESSAGELOOP,
291  QUITMESSAGELOOP,
292  ORDERED,
293  PUMPS,
294  SLEEP,
295  RUNS,
296};
297
298// Saves the order in which the tasks executed.
299struct TaskItem {
300  TaskItem(TaskType t, int c, bool s)
301      : type(t),
302        cookie(c),
303        start(s) {
304  }
305
306  TaskType type;
307  int cookie;
308  bool start;
309
310  bool operator == (const TaskItem& other) const {
311    return type == other.type && cookie == other.cookie && start == other.start;
312  }
313};
314
315std::ostream& operator <<(std::ostream& os, TaskType type) {
316  switch (type) {
317  case MESSAGEBOX:        os << "MESSAGEBOX"; break;
318  case ENDDIALOG:         os << "ENDDIALOG"; break;
319  case RECURSIVE:         os << "RECURSIVE"; break;
320  case TIMEDMESSAGELOOP:  os << "TIMEDMESSAGELOOP"; break;
321  case QUITMESSAGELOOP:   os << "QUITMESSAGELOOP"; break;
322  case ORDERED:          os << "ORDERED"; break;
323  case PUMPS:             os << "PUMPS"; break;
324  case SLEEP:             os << "SLEEP"; break;
325  default:
326    NOTREACHED();
327    os << "Unknown TaskType";
328    break;
329  }
330  return os;
331}
332
333std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
334  if (item.start)
335    return os << item.type << " " << item.cookie << " starts";
336  else
337    return os << item.type << " " << item.cookie << " ends";
338}
339
340class TaskList {
341 public:
342  void RecordStart(TaskType type, int cookie) {
343    TaskItem item(type, cookie, true);
344    DVLOG(1) << item;
345    task_list_.push_back(item);
346  }
347
348  void RecordEnd(TaskType type, int cookie) {
349    TaskItem item(type, cookie, false);
350    DVLOG(1) << item;
351    task_list_.push_back(item);
352  }
353
354  size_t Size() {
355    return task_list_.size();
356  }
357
358  TaskItem Get(int n)  {
359    return task_list_[n];
360  }
361
362 private:
363  std::vector<TaskItem> task_list_;
364};
365
366// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
367// common controls (like OpenFile) and StartDoc printing function can cause
368// implicit message loops.
369void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
370  order->RecordStart(MESSAGEBOX, cookie);
371  if (is_reentrant)
372    MessageLoop::current()->SetNestableTasksAllowed(true);
373  MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
374  order->RecordEnd(MESSAGEBOX, cookie);
375}
376
377// Will end the MessageBox.
378void EndDialogFunc(TaskList* order, int cookie) {
379  order->RecordStart(ENDDIALOG, cookie);
380  HWND window = GetActiveWindow();
381  if (window != NULL) {
382    EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
383    // Cheap way to signal that the window wasn't found if RunEnd() isn't
384    // called.
385    order->RecordEnd(ENDDIALOG, cookie);
386  }
387}
388
389void RecursiveFunc(TaskList* order, int cookie, int depth,
390                   bool is_reentrant) {
391  order->RecordStart(RECURSIVE, cookie);
392  if (depth > 0) {
393    if (is_reentrant)
394      MessageLoop::current()->SetNestableTasksAllowed(true);
395    MessageLoop::current()->PostTask(
396        FROM_HERE,
397        Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
398  }
399  order->RecordEnd(RECURSIVE, cookie);
400}
401
402void QuitFunc(TaskList* order, int cookie) {
403  order->RecordStart(QUITMESSAGELOOP, cookie);
404  MessageLoop::current()->QuitWhenIdle();
405  order->RecordEnd(QUITMESSAGELOOP, cookie);
406}
407
408void RecursiveFuncWin(MessageLoop* target,
409                      HANDLE event,
410                      bool expect_window,
411                      TaskList* order,
412                      bool is_reentrant) {
413  target->PostTask(FROM_HERE,
414                   Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
415  target->PostTask(FROM_HERE,
416                   Bind(&MessageBoxFunc, order, 2, is_reentrant));
417  target->PostTask(FROM_HERE,
418                   Bind(&RecursiveFunc, order, 3, 2, is_reentrant));
419  // The trick here is that for recursive task processing, this task will be
420  // ran _inside_ the MessageBox message loop, dismissing the MessageBox
421  // without a chance.
422  // For non-recursive task processing, this will be executed _after_ the
423  // MessageBox will have been dismissed by the code below, where
424  // expect_window_ is true.
425  target->PostTask(FROM_HERE,
426                   Bind(&EndDialogFunc, order, 4));
427  target->PostTask(FROM_HERE,
428                   Bind(&QuitFunc, order, 5));
429
430  // Enforce that every tasks are sent before starting to run the main thread
431  // message loop.
432  ASSERT_TRUE(SetEvent(event));
433
434  // Poll for the MessageBox. Don't do this at home! At the speed we do it,
435  // you will never realize one MessageBox was shown.
436  for (; expect_window;) {
437    HWND window = FindWindow(L"#32770", kMessageBoxTitle);
438    if (window) {
439      // Dismiss it.
440      for (;;) {
441        HWND button = FindWindowEx(window, NULL, L"Button", NULL);
442        if (button != NULL) {
443          EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
444          EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
445          break;
446        }
447      }
448      break;
449    }
450  }
451}
452
453// TODO(darin): These tests need to be ported since they test critical
454// message loop functionality.
455
456// A side effect of this test is the generation a beep. Sorry.
457void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
458  MessageLoop loop(message_loop_type);
459
460  Thread worker("RecursiveDenial2_worker");
461  Thread::Options options;
462  options.message_loop_type = message_loop_type;
463  ASSERT_EQ(true, worker.StartWithOptions(options));
464  TaskList order;
465  win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
466  worker.message_loop()->PostTask(FROM_HERE,
467                                  Bind(&RecursiveFuncWin,
468                                             MessageLoop::current(),
469                                             event.Get(),
470                                             true,
471                                             &order,
472                                             false));
473  // Let the other thread execute.
474  WaitForSingleObject(event, INFINITE);
475  MessageLoop::current()->Run();
476
477  ASSERT_EQ(order.Size(), 17);
478  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
479  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
480  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
481  EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
482  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
483  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
484  // When EndDialogFunc is processed, the window is already dismissed, hence no
485  // "end" entry.
486  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
487  EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
488  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
489  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
490  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
491  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
492  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
493  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
494  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
495  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
496  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
497}
498
499// A side effect of this test is the generation a beep. Sorry.  This test also
500// needs to process windows messages on the current thread.
501void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
502  MessageLoop loop(message_loop_type);
503
504  Thread worker("RecursiveSupport2_worker");
505  Thread::Options options;
506  options.message_loop_type = message_loop_type;
507  ASSERT_EQ(true, worker.StartWithOptions(options));
508  TaskList order;
509  win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
510  worker.message_loop()->PostTask(FROM_HERE,
511                                  Bind(&RecursiveFuncWin,
512                                             MessageLoop::current(),
513                                             event.Get(),
514                                             false,
515                                             &order,
516                                             true));
517  // Let the other thread execute.
518  WaitForSingleObject(event, INFINITE);
519  MessageLoop::current()->Run();
520
521  ASSERT_EQ(order.Size(), 18);
522  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
523  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
524  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
525  // Note that this executes in the MessageBox modal loop.
526  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
527  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
528  EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
529  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
530  EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
531  /* The order can subtly change here. The reason is that when RecursiveFunc(1)
532     is called in the main thread, if it is faster than getting to the
533     PostTask(FROM_HERE, Bind(&QuitFunc) execution, the order of task
534     execution can change. We don't care anyway that the order isn't correct.
535  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
536  EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
537  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
538  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
539  */
540  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
541  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
542  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
543  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
544  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
545  EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
546}
547
548#endif  // defined(OS_WIN)
549
550void PostNTasksThenQuit(int posts_remaining) {
551  if (posts_remaining > 1) {
552    MessageLoop::current()->PostTask(
553        FROM_HERE,
554        Bind(&PostNTasksThenQuit, posts_remaining - 1));
555  } else {
556    MessageLoop::current()->QuitWhenIdle();
557  }
558}
559
560#if defined(OS_WIN)
561
562class DispatcherImpl : public MessageLoopForUI::Dispatcher {
563 public:
564  DispatcherImpl() : dispatch_count_(0) {}
565
566  virtual bool Dispatch(const NativeEvent& msg) OVERRIDE {
567    ::TranslateMessage(&msg);
568    ::DispatchMessage(&msg);
569    // Do not count WM_TIMER since it is not what we post and it will cause
570    // flakiness.
571    if (msg.message != WM_TIMER)
572      ++dispatch_count_;
573    // We treat WM_LBUTTONUP as the last message.
574    return msg.message != WM_LBUTTONUP;
575  }
576
577  int dispatch_count_;
578};
579
580void MouseDownUp() {
581  PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
582  PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
583}
584
585void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
586  MessageLoop loop(message_loop_type);
587
588  MessageLoop::current()->PostDelayedTask(
589      FROM_HERE,
590      Bind(&MouseDownUp),
591      TimeDelta::FromMilliseconds(100));
592  DispatcherImpl dispatcher;
593  RunLoop run_loop(&dispatcher);
594  run_loop.Run();
595  ASSERT_EQ(2, dispatcher.dispatch_count_);
596}
597
598LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
599  if (code == MessagePumpForUI::kMessageFilterCode) {
600    MSG* msg = reinterpret_cast<MSG*>(lparam);
601    if (msg->message == WM_LBUTTONDOWN)
602      return TRUE;
603  }
604  return FALSE;
605}
606
607void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
608  MessageLoop loop(message_loop_type);
609
610  MessageLoop::current()->PostDelayedTask(
611      FROM_HERE,
612      Bind(&MouseDownUp),
613      TimeDelta::FromMilliseconds(100));
614  HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
615                                    MsgFilterProc,
616                                    NULL,
617                                    GetCurrentThreadId());
618  DispatcherImpl dispatcher;
619  RunLoop run_loop(&dispatcher);
620  run_loop.Run();
621  ASSERT_EQ(1, dispatcher.dispatch_count_);
622  UnhookWindowsHookEx(msg_hook);
623}
624
625class TestIOHandler : public MessageLoopForIO::IOHandler {
626 public:
627  TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
628
629  virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
630                             DWORD bytes_transfered, DWORD error);
631
632  void Init();
633  void WaitForIO();
634  OVERLAPPED* context() { return &context_.overlapped; }
635  DWORD size() { return sizeof(buffer_); }
636
637 private:
638  char buffer_[48];
639  MessageLoopForIO::IOContext context_;
640  HANDLE signal_;
641  win::ScopedHandle file_;
642  bool wait_;
643};
644
645TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
646    : signal_(signal), wait_(wait) {
647  memset(buffer_, 0, sizeof(buffer_));
648  memset(&context_, 0, sizeof(context_));
649  context_.handler = this;
650
651  file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
652                       FILE_FLAG_OVERLAPPED, NULL));
653  EXPECT_TRUE(file_.IsValid());
654}
655
656void TestIOHandler::Init() {
657  MessageLoopForIO::current()->RegisterIOHandler(file_, this);
658
659  DWORD read;
660  EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context()));
661  EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
662  if (wait_)
663    WaitForIO();
664}
665
666void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
667                                  DWORD bytes_transfered, DWORD error) {
668  ASSERT_TRUE(context == &context_);
669  ASSERT_TRUE(SetEvent(signal_));
670}
671
672void TestIOHandler::WaitForIO() {
673  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
674  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
675}
676
677void RunTest_IOHandler() {
678  win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
679  ASSERT_TRUE(callback_called.IsValid());
680
681  const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
682  win::ScopedHandle server(
683      CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
684  ASSERT_TRUE(server.IsValid());
685
686  Thread thread("IOHandler test");
687  Thread::Options options;
688  options.message_loop_type = MessageLoop::TYPE_IO;
689  ASSERT_TRUE(thread.StartWithOptions(options));
690
691  MessageLoop* thread_loop = thread.message_loop();
692  ASSERT_TRUE(NULL != thread_loop);
693
694  TestIOHandler handler(kPipeName, callback_called, false);
695  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
696                                              Unretained(&handler)));
697  // Make sure the thread runs and sleeps for lack of work.
698  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
699
700  const char buffer[] = "Hello there!";
701  DWORD written;
702  EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL));
703
704  DWORD result = WaitForSingleObject(callback_called, 1000);
705  EXPECT_EQ(WAIT_OBJECT_0, result);
706
707  thread.Stop();
708}
709
710void RunTest_WaitForIO() {
711  win::ScopedHandle callback1_called(
712      CreateEvent(NULL, TRUE, FALSE, NULL));
713  win::ScopedHandle callback2_called(
714      CreateEvent(NULL, TRUE, FALSE, NULL));
715  ASSERT_TRUE(callback1_called.IsValid());
716  ASSERT_TRUE(callback2_called.IsValid());
717
718  const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
719  const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
720  win::ScopedHandle server1(
721      CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
722  win::ScopedHandle server2(
723      CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
724  ASSERT_TRUE(server1.IsValid());
725  ASSERT_TRUE(server2.IsValid());
726
727  Thread thread("IOHandler test");
728  Thread::Options options;
729  options.message_loop_type = MessageLoop::TYPE_IO;
730  ASSERT_TRUE(thread.StartWithOptions(options));
731
732  MessageLoop* thread_loop = thread.message_loop();
733  ASSERT_TRUE(NULL != thread_loop);
734
735  TestIOHandler handler1(kPipeName1, callback1_called, false);
736  TestIOHandler handler2(kPipeName2, callback2_called, true);
737  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
738                                              Unretained(&handler1)));
739  // TODO(ajwong): Do we really need such long Sleeps in ths function?
740  // Make sure the thread runs and sleeps for lack of work.
741  TimeDelta delay = TimeDelta::FromMilliseconds(100);
742  PlatformThread::Sleep(delay);
743  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
744                                              Unretained(&handler2)));
745  PlatformThread::Sleep(delay);
746
747  // At this time handler1 is waiting to be called, and the thread is waiting
748  // on the Init method of handler2, filtering only handler2 callbacks.
749
750  const char buffer[] = "Hello there!";
751  DWORD written;
752  EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL));
753  PlatformThread::Sleep(2 * delay);
754  EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) <<
755      "handler1 has not been called";
756
757  EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL));
758
759  HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
760  DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
761  EXPECT_EQ(WAIT_OBJECT_0, result);
762
763  thread.Stop();
764}
765
766#endif  // defined(OS_WIN)
767
768}  // namespace
769
770//-----------------------------------------------------------------------------
771// Each test is run against each type of MessageLoop.  That way we are sure
772// that message loops work properly in all configurations.  Of course, in some
773// cases, a unit test may only be for a particular type of loop.
774
775RUN_MESSAGE_LOOP_TESTS(Default, &TypeDefaultMessagePumpFactory);
776RUN_MESSAGE_LOOP_TESTS(UI, &TypeUIMessagePumpFactory);
777RUN_MESSAGE_LOOP_TESTS(IO, &TypeIOMessagePumpFactory);
778
779#if defined(OS_WIN)
780TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
781  RunTest_PostDelayedTask_SharedTimer_SubPump();
782}
783
784TEST(MessageLoopTest, Crasher) {
785  RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
786  RunTest_Crasher(MessageLoop::TYPE_UI);
787  RunTest_Crasher(MessageLoop::TYPE_IO);
788}
789
790TEST(MessageLoopTest, CrasherNasty) {
791  RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
792  RunTest_CrasherNasty(MessageLoop::TYPE_UI);
793  RunTest_CrasherNasty(MessageLoop::TYPE_IO);
794}
795
796// This test occasionally hangs http://crbug.com/44567
797TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
798  RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
799  RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
800  RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
801}
802
803TEST(MessageLoopTest, RecursiveSupport2) {
804  // This test requires a UI loop
805  RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
806}
807#endif  // defined(OS_WIN)
808
809class DummyTaskObserver : public MessageLoop::TaskObserver {
810 public:
811  explicit DummyTaskObserver(int num_tasks)
812      : num_tasks_started_(0),
813        num_tasks_processed_(0),
814        num_tasks_(num_tasks) {}
815
816  virtual ~DummyTaskObserver() {}
817
818  virtual void WillProcessTask(const PendingTask& pending_task) OVERRIDE {
819    num_tasks_started_++;
820    EXPECT_TRUE(pending_task.time_posted != TimeTicks());
821    EXPECT_LE(num_tasks_started_, num_tasks_);
822    EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
823  }
824
825  virtual void DidProcessTask(const PendingTask& pending_task) OVERRIDE {
826    num_tasks_processed_++;
827    EXPECT_TRUE(pending_task.time_posted != TimeTicks());
828    EXPECT_LE(num_tasks_started_, num_tasks_);
829    EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
830  }
831
832  int num_tasks_started() const { return num_tasks_started_; }
833  int num_tasks_processed() const { return num_tasks_processed_; }
834
835 private:
836  int num_tasks_started_;
837  int num_tasks_processed_;
838  const int num_tasks_;
839
840  DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
841};
842
843TEST(MessageLoopTest, TaskObserver) {
844  const int kNumPosts = 6;
845  DummyTaskObserver observer(kNumPosts);
846
847  MessageLoop loop;
848  loop.AddTaskObserver(&observer);
849  loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumPosts));
850  loop.Run();
851  loop.RemoveTaskObserver(&observer);
852
853  EXPECT_EQ(kNumPosts, observer.num_tasks_started());
854  EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
855}
856
857#if defined(OS_WIN)
858TEST(MessageLoopTest, Dispatcher) {
859  // This test requires a UI loop
860  RunTest_Dispatcher(MessageLoop::TYPE_UI);
861}
862
863TEST(MessageLoopTest, DispatcherWithMessageHook) {
864  // This test requires a UI loop
865  RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
866}
867
868TEST(MessageLoopTest, IOHandler) {
869  RunTest_IOHandler();
870}
871
872TEST(MessageLoopTest, WaitForIO) {
873  RunTest_WaitForIO();
874}
875
876TEST(MessageLoopTest, HighResolutionTimer) {
877  MessageLoop loop;
878
879  const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
880  const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
881
882  EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting());
883
884  // Post a fast task to enable the high resolution timers.
885  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
886                       kFastTimer);
887  loop.Run();
888  EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting());
889
890  // Post a slow task and verify high resolution timers
891  // are still enabled.
892  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
893                       kSlowTimer);
894  loop.Run();
895  EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting());
896
897  // Wait for a while so that high-resolution mode elapses.
898  PlatformThread::Sleep(TimeDelta::FromMilliseconds(
899      MessageLoop::kHighResolutionTimerModeLeaseTimeMs));
900
901  // Post a slow task to disable the high resolution timers.
902  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
903                       kSlowTimer);
904  loop.Run();
905  EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting());
906}
907
908#endif  // defined(OS_WIN)
909
910#if defined(OS_POSIX) && !defined(OS_NACL)
911
912namespace {
913
914class QuitDelegate : public MessageLoopForIO::Watcher {
915 public:
916  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
917    MessageLoop::current()->QuitWhenIdle();
918  }
919  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
920    MessageLoop::current()->QuitWhenIdle();
921  }
922};
923
924TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
925  // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
926  // This could happen when people use the Singleton pattern or atexit.
927
928  // Create a file descriptor.  Doesn't need to be readable or writable,
929  // as we don't need to actually get any notifications.
930  // pipe() is just the easiest way to do it.
931  int pipefds[2];
932  int err = pipe(pipefds);
933  ASSERT_EQ(0, err);
934  int fd = pipefds[1];
935  {
936    // Arrange for controller to live longer than message loop.
937    MessageLoopForIO::FileDescriptorWatcher controller;
938    {
939      MessageLoopForIO message_loop;
940
941      QuitDelegate delegate;
942      message_loop.WatchFileDescriptor(fd,
943          true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
944      // and don't run the message loop, just destroy it.
945    }
946  }
947  if (IGNORE_EINTR(close(pipefds[0])) < 0)
948    PLOG(ERROR) << "close";
949  if (IGNORE_EINTR(close(pipefds[1])) < 0)
950    PLOG(ERROR) << "close";
951}
952
953TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
954  // Verify that it's ok to call StopWatchingFileDescriptor().
955  // (Errors only showed up in valgrind.)
956  int pipefds[2];
957  int err = pipe(pipefds);
958  ASSERT_EQ(0, err);
959  int fd = pipefds[1];
960  {
961    // Arrange for message loop to live longer than controller.
962    MessageLoopForIO message_loop;
963    {
964      MessageLoopForIO::FileDescriptorWatcher controller;
965
966      QuitDelegate delegate;
967      message_loop.WatchFileDescriptor(fd,
968          true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
969      controller.StopWatchingFileDescriptor();
970    }
971  }
972  if (IGNORE_EINTR(close(pipefds[0])) < 0)
973    PLOG(ERROR) << "close";
974  if (IGNORE_EINTR(close(pipefds[1])) < 0)
975    PLOG(ERROR) << "close";
976}
977
978}  // namespace
979
980#endif  // defined(OS_POSIX) && !defined(OS_NACL)
981
982namespace {
983// Inject a test point for recording the destructor calls for Closure objects
984// send to MessageLoop::PostTask(). It is awkward usage since we are trying to
985// hook the actual destruction, which is not a common operation.
986class DestructionObserverProbe :
987  public RefCounted<DestructionObserverProbe> {
988 public:
989  DestructionObserverProbe(bool* task_destroyed,
990                           bool* destruction_observer_called)
991      : task_destroyed_(task_destroyed),
992        destruction_observer_called_(destruction_observer_called) {
993  }
994  virtual void Run() {
995    // This task should never run.
996    ADD_FAILURE();
997  }
998 private:
999  friend class RefCounted<DestructionObserverProbe>;
1000
1001  virtual ~DestructionObserverProbe() {
1002    EXPECT_FALSE(*destruction_observer_called_);
1003    *task_destroyed_ = true;
1004  }
1005
1006  bool* task_destroyed_;
1007  bool* destruction_observer_called_;
1008};
1009
1010class MLDestructionObserver : public MessageLoop::DestructionObserver {
1011 public:
1012  MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
1013      : task_destroyed_(task_destroyed),
1014        destruction_observer_called_(destruction_observer_called),
1015        task_destroyed_before_message_loop_(false) {
1016  }
1017  virtual void WillDestroyCurrentMessageLoop() OVERRIDE {
1018    task_destroyed_before_message_loop_ = *task_destroyed_;
1019    *destruction_observer_called_ = true;
1020  }
1021  bool task_destroyed_before_message_loop() const {
1022    return task_destroyed_before_message_loop_;
1023  }
1024 private:
1025  bool* task_destroyed_;
1026  bool* destruction_observer_called_;
1027  bool task_destroyed_before_message_loop_;
1028};
1029
1030}  // namespace
1031
1032TEST(MessageLoopTest, DestructionObserverTest) {
1033  // Verify that the destruction observer gets called at the very end (after
1034  // all the pending tasks have been destroyed).
1035  MessageLoop* loop = new MessageLoop;
1036  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
1037
1038  bool task_destroyed = false;
1039  bool destruction_observer_called = false;
1040
1041  MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
1042  loop->AddDestructionObserver(&observer);
1043  loop->PostDelayedTask(
1044      FROM_HERE,
1045      Bind(&DestructionObserverProbe::Run,
1046                 new DestructionObserverProbe(&task_destroyed,
1047                                              &destruction_observer_called)),
1048      kDelay);
1049  delete loop;
1050  EXPECT_TRUE(observer.task_destroyed_before_message_loop());
1051  // The task should have been destroyed when we deleted the loop.
1052  EXPECT_TRUE(task_destroyed);
1053  EXPECT_TRUE(destruction_observer_called);
1054}
1055
1056
1057// Verify that MessageLoop sets ThreadMainTaskRunner::current() and it
1058// posts tasks on that message loop.
1059TEST(MessageLoopTest, ThreadMainTaskRunner) {
1060  MessageLoop loop;
1061
1062  scoped_refptr<Foo> foo(new Foo());
1063  std::string a("a");
1064  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(
1065      &Foo::Test1ConstRef, foo.get(), a));
1066
1067  // Post quit task;
1068  MessageLoop::current()->PostTask(FROM_HERE, Bind(
1069      &MessageLoop::Quit, Unretained(MessageLoop::current())));
1070
1071  // Now kick things off
1072  MessageLoop::current()->Run();
1073
1074  EXPECT_EQ(foo->test_count(), 1);
1075  EXPECT_EQ(foo->result(), "a");
1076}
1077
1078TEST(MessageLoopTest, IsType) {
1079  MessageLoop loop(MessageLoop::TYPE_UI);
1080  EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI));
1081  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO));
1082  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT));
1083}
1084
1085#if defined(OS_WIN)
1086void EmptyFunction() {}
1087
1088void PostMultipleTasks() {
1089  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction));
1090  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction));
1091}
1092
1093static const int kSignalMsg = WM_USER + 2;
1094
1095void PostWindowsMessage(HWND message_hwnd) {
1096  PostMessage(message_hwnd, kSignalMsg, 0, 2);
1097}
1098
1099void EndTest(bool* did_run, HWND hwnd) {
1100  *did_run = true;
1101  PostMessage(hwnd, WM_CLOSE, 0, 0);
1102}
1103
1104int kMyMessageFilterCode = 0x5002;
1105
1106LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message,
1107                                  WPARAM wparam, LPARAM lparam) {
1108  if (message == WM_CLOSE)
1109    EXPECT_TRUE(DestroyWindow(hwnd));
1110  if (message != kSignalMsg)
1111    return DefWindowProc(hwnd, message, wparam, lparam);
1112
1113  switch (lparam) {
1114  case 1:
1115    // First, we post a task that will post multiple no-op tasks to make sure
1116    // that the pump's incoming task queue does not become empty during the
1117    // test.
1118    MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&PostMultipleTasks));
1119    // Next, we post a task that posts a windows message to trigger the second
1120    // stage of the test.
1121    MessageLoop::current()->PostTask(FROM_HERE,
1122                                     base::Bind(&PostWindowsMessage, hwnd));
1123    break;
1124  case 2:
1125    // Since we're about to enter a modal loop, tell the message loop that we
1126    // intend to nest tasks.
1127    MessageLoop::current()->SetNestableTasksAllowed(true);
1128    bool did_run = false;
1129    MessageLoop::current()->PostTask(FROM_HERE,
1130                                     base::Bind(&EndTest, &did_run, hwnd));
1131    // Run a nested windows-style message loop and verify that our task runs. If
1132    // it doesn't, then we'll loop here until the test times out.
1133    MSG msg;
1134    while (GetMessage(&msg, 0, 0, 0)) {
1135      if (!CallMsgFilter(&msg, kMyMessageFilterCode))
1136        DispatchMessage(&msg);
1137      // If this message is a WM_CLOSE, explicitly exit the modal loop. Posting
1138      // a WM_QUIT should handle this, but unfortunately MessagePumpWin eats
1139      // WM_QUIT messages even when running inside a modal loop.
1140      if (msg.message == WM_CLOSE)
1141        break;
1142    }
1143    EXPECT_TRUE(did_run);
1144    MessageLoop::current()->Quit();
1145    break;
1146  }
1147  return 0;
1148}
1149
1150TEST(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) {
1151  MessageLoop loop(MessageLoop::TYPE_UI);
1152  HINSTANCE instance = GetModuleFromAddress(&TestWndProcThunk);
1153  WNDCLASSEX wc = {0};
1154  wc.cbSize = sizeof(wc);
1155  wc.lpfnWndProc = TestWndProcThunk;
1156  wc.hInstance = instance;
1157  wc.lpszClassName = L"MessageLoopTest_HWND";
1158  ATOM atom = RegisterClassEx(&wc);
1159  ASSERT_TRUE(atom);
1160
1161  HWND message_hwnd = CreateWindow(MAKEINTATOM(atom), 0, 0, 0, 0, 0, 0,
1162                                   HWND_MESSAGE, 0, instance, 0);
1163  ASSERT_TRUE(message_hwnd) << GetLastError();
1164
1165  ASSERT_TRUE(PostMessage(message_hwnd, kSignalMsg, 0, 1));
1166
1167  loop.Run();
1168
1169  ASSERT_TRUE(UnregisterClass(MAKEINTATOM(atom), instance));
1170}
1171#endif  // defined(OS_WIN)
1172
1173}  // namespace base
1174