test_utils.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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 "content/public/test/test_utils.h"
6
7#include "base/bind.h"
8#include "base/message_loop.h"
9#include "base/run_loop.h"
10#include "content/public/browser/notification_service.h"
11#include "content/public/test/test_launcher.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace content {
15
16namespace {
17
18// Number of times to repost a Quit task so that the MessageLoop finishes up
19// pending tasks and tasks posted by those pending tasks without risking the
20// potential hang behavior of MessageLoop::QuitWhenIdle.
21// The criteria for choosing this number: it should be high enough to make the
22// quit act like QuitWhenIdle, while taking into account that any page which is
23// animating may be rendering another frame for each quit deferral. For an
24// animating page, the potential delay to quitting the RunLoop would be
25// kNumQuitDeferrals * frame_render_time. Some perf tests run slow, such as
26// 200ms/frame.
27static const int kNumQuitDeferrals = 10;
28
29static void DeferredQuitRunLoop(const base::Closure& quit_task,
30                                int num_quit_deferrals) {
31  if (num_quit_deferrals <= 0) {
32    quit_task.Run();
33  } else {
34    MessageLoop::current()->PostTask(FROM_HERE,
35        base::Bind(&DeferredQuitRunLoop, quit_task, num_quit_deferrals - 1));
36  }
37}
38
39void RunAllPendingMessageAndSendQuit(BrowserThread::ID thread_id,
40                                     const base::Closure& quit_task) {
41  RunAllPendingInMessageLoop();
42  BrowserThread::PostTask(thread_id, FROM_HERE, quit_task);
43}
44
45}  // namespace
46
47void RunMessageLoop() {
48  base::RunLoop run_loop;
49  RunThisRunLoop(&run_loop);
50}
51
52void RunThisRunLoop(base::RunLoop* run_loop) {
53  MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
54
55  // If we're running inside a browser test, we might need to allow the test
56  // launcher to do extra work before/after running a nested message loop.
57  TestLauncherDelegate* delegate = GetCurrentTestLauncherDelegate();
58  if (delegate)
59    delegate->PreRunMessageLoop(run_loop);
60  run_loop->Run();
61  if (delegate)
62    delegate->PostRunMessageLoop();
63}
64
65void RunAllPendingInMessageLoop() {
66  MessageLoop::current()->PostTask(FROM_HERE,
67                                   MessageLoop::QuitWhenIdleClosure());
68  RunMessageLoop();
69}
70
71void RunAllPendingInMessageLoop(BrowserThread::ID thread_id) {
72  if (BrowserThread::CurrentlyOn(thread_id)) {
73    RunAllPendingInMessageLoop();
74    return;
75  }
76  BrowserThread::ID current_thread_id;
77  if (!BrowserThread::GetCurrentThreadIdentifier(&current_thread_id)) {
78    NOTREACHED();
79    return;
80  }
81
82  base::RunLoop run_loop;
83  BrowserThread::PostTask(thread_id, FROM_HERE,
84      base::Bind(&RunAllPendingMessageAndSendQuit, current_thread_id,
85                 run_loop.QuitClosure()));
86  RunThisRunLoop(&run_loop);
87}
88
89base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) {
90  return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(),
91                    kNumQuitDeferrals);
92}
93
94MessageLoopRunner::MessageLoopRunner() {
95}
96
97MessageLoopRunner::~MessageLoopRunner() {
98}
99
100void MessageLoopRunner::Run() {
101  RunThisRunLoop(&run_loop_);
102}
103
104base::Closure MessageLoopRunner::QuitClosure() {
105  return base::Bind(&MessageLoopRunner::Quit, this);
106}
107
108void MessageLoopRunner::Quit() {
109  GetQuitTaskForRunLoop(&run_loop_).Run();
110}
111
112WindowedNotificationObserver::WindowedNotificationObserver(
113    int notification_type,
114    const NotificationSource& source)
115    : seen_(false),
116      running_(false),
117      source_(NotificationService::AllSources()) {
118  registrar_.Add(this, notification_type, source);
119}
120
121WindowedNotificationObserver::~WindowedNotificationObserver() {}
122
123void WindowedNotificationObserver::Wait() {
124  if (seen_)
125    return;
126
127  running_ = true;
128  message_loop_runner_ = new MessageLoopRunner;
129  message_loop_runner_->Run();
130  EXPECT_TRUE(seen_);
131}
132
133void WindowedNotificationObserver::Observe(
134    int type,
135    const NotificationSource& source,
136    const NotificationDetails& details) {
137  source_ = source;
138  details_ = details;
139  seen_ = true;
140  if (!running_)
141    return;
142
143  message_loop_runner_->Quit();
144  running_ = false;
145}
146
147}  // namespace content
148