blob: 5815fad3c828583510f437b25e3ea8086f1b9f93 [file] [log] [blame]
[email protected]c4ff4952010-01-08 19:12:471// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]d4515eb2009-01-30 00:40:432// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/test/in_process_browser_test.h"
6
7#include "base/command_line.h"
[email protected]d8412052009-04-21 22:01:018#include "base/file_path.h"
[email protected]d4515eb2009-01-30 00:40:439#include "base/file_util.h"
[email protected]c2818d42010-10-18 02:47:3910#include "base/mac/scoped_nsautorelease_pool.h"
[email protected]d4515eb2009-01-30 00:40:4311#include "base/path_service.h"
[email protected]528c56d2010-07-30 19:28:4412#include "base/string_number_conversions.h"
[email protected]fb895c62009-10-09 18:20:3013#include "base/test/test_file_util.h"
[email protected]b6e38ef2009-06-16 00:43:2314#include "chrome/browser/browser_list.h"
[email protected]d4515eb2009-01-30 00:40:4315#include "chrome/browser/browser_process.h"
16#include "chrome/browser/browser_shutdown.h"
[email protected]8281e48e2010-10-12 18:54:4917#include "chrome/browser/browser_thread.h"
[email protected]108c2a12009-06-05 22:18:0918#include "chrome/browser/browser_window.h"
[email protected]c4ff4952010-01-08 19:12:4719#include "chrome/browser/intranet_redirect_detector.h"
[email protected]0ac83682010-01-22 17:46:2720#include "chrome/browser/io_thread.h"
[email protected]cec4a272009-07-31 21:55:0321#include "chrome/browser/net/url_request_mock_util.h"
[email protected]8ecad5e2010-12-02 21:18:3322#include "chrome/browser/profiles/profile.h"
23#include "chrome/browser/profiles/profile_manager.h"
[email protected]8bcdec92009-02-25 16:15:1824#include "chrome/browser/renderer_host/render_process_host.h"
[email protected]5c238752009-06-13 10:29:0725#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]c848d3d92010-09-16 21:57:4526#include "chrome/browser/tabs/tab_strip_model.h"
[email protected]f46be6e2010-11-16 03:52:3227#include "chrome/browser/ui/browser.h"
[email protected]339d6dd2010-11-12 00:41:5828#include "chrome/browser/ui/browser_navigator.h"
[email protected]d4515eb2009-01-30 00:40:4329#include "chrome/common/chrome_constants.h"
30#include "chrome/common/chrome_paths.h"
31#include "chrome/common/chrome_switches.h"
[email protected]0750b1442010-11-02 21:59:3732#include "chrome/common/logging_chrome.h"
[email protected]d4515eb2009-01-30 00:40:4333#include "chrome/common/main_function_params.h"
[email protected]ad1f9bd2009-07-30 20:23:1534#include "chrome/common/notification_registrar.h"
35#include "chrome/common/notification_type.h"
[email protected]e0d481582009-09-15 21:06:2536#include "chrome/common/url_constants.h"
[email protected]470f7a52010-09-23 20:20:3837#include "chrome/test/test_launcher_utils.h"
[email protected]d4515eb2009-01-30 00:40:4338#include "chrome/test/testing_browser_process.h"
39#include "chrome/test/ui_test_utils.h"
[email protected]c4ff4952010-01-08 19:12:4740#include "net/base/mock_host_resolver.h"
[email protected]3985ba82010-07-29 21:44:1241#include "net/test/test_server.h"
[email protected]d4515eb2009-01-30 00:40:4342#include "sandbox/src/dep.h"
43
[email protected]7fac8882010-11-15 19:52:5244#if defined(OS_MACOSX)
[email protected]0378bf42011-01-01 18:20:1445#include "base/mac/mac_util.h"
[email protected]7fac8882010-11-15 19:52:5246#endif
47
48#if defined(OS_WIN)
49#include "chrome/browser/views/frame/browser_view.h"
50#endif
51
[email protected]e1c10f182010-09-30 08:53:0652namespace {
53
54void InitializeBrowser(Browser* browser) {
[email protected]cecc93a2010-10-05 15:58:5555 browser->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL),
56 PageTransition::START_PAGE);
[email protected]e1c10f182010-09-30 08:53:0657
58 // Wait for the page to finish loading.
59 ui_test_utils::WaitForNavigation(
60 &browser->GetSelectedTabContents()->controller());
61
62 browser->window()->Show();
63}
64
65} // namespace
66
[email protected]d4515eb2009-01-30 00:40:4367extern int BrowserMain(const MainFunctionParams&);
68
[email protected]711a3532010-12-08 22:18:3769const char kUnitTestShowWindows[] = "show-windows";
[email protected]d4515eb2009-01-30 00:40:4370
[email protected]ddf8a4b02010-03-22 23:08:3071// Passed as value of kTestType.
72static const char kBrowserTestType[] = "browser";
73
[email protected]8bcdec92009-02-25 16:15:1874InProcessBrowserTest::InProcessBrowserTest()
75 : browser_(NULL),
76 show_window_(false),
[email protected]56cdae32009-03-12 19:58:2077 dom_automation_enabled_(false),
[email protected]0b4d3382010-07-14 16:13:0478 tab_closeable_state_watcher_enabled_(false),
[email protected]4b614a62010-10-06 15:33:1079 original_single_process_(false) {
[email protected]7fac8882010-11-15 19:52:5280#if defined(OS_MACOSX)
[email protected]0378bf42011-01-01 18:20:1481 base::mac::SetOverrideAmIBundled(true);
[email protected]7fac8882010-11-15 19:52:5282#endif
83
84 // Before we run the browser, we have to hack the path to the exe to match
85 // what it would be if Chrome was running, because it is used to fork renderer
86 // processes, on Linux at least (failure to do so will cause a browser_test to
87 // be run instead of a renderer).
88 FilePath chrome_path;
89 CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
90 chrome_path = chrome_path.DirName();
[email protected]7fac8882010-11-15 19:52:5291 chrome_path = chrome_path.Append(chrome::kBrowserProcessExecutablePath);
[email protected]7fac8882010-11-15 19:52:5292 CHECK(PathService::Override(base::FILE_EXE, chrome_path));
93
94 test_server_.reset(new net::TestServer(
95 net::TestServer::TYPE_HTTP,
96 FilePath(FILE_PATH_LITERAL("chrome/test/data"))));
[email protected]d4515eb2009-01-30 00:40:4397}
98
[email protected]c4ff4952010-01-08 19:12:4799InProcessBrowserTest::~InProcessBrowserTest() {
100}
101
[email protected]d4515eb2009-01-30 00:40:43102void InProcessBrowserTest::SetUp() {
[email protected]470f7a52010-09-23 20:20:38103 // Remember the command line. Normally this doesn't matter, because the test
104 // harness creates a new process for each test, but when the test harness is
105 // running in single process mode, we can't let one test's command-line
106 // changes (e.g. enabling DOM automation) affect other tests.
107 // TODO(phajdan.jr): This save/restore logic is unnecessary. Remove it.
108 CommandLine* command_line = CommandLine::ForCurrentProcessMutable();
109 original_command_line_.reset(new CommandLine(*command_line));
[email protected]d4515eb2009-01-30 00:40:43110
[email protected]fc82ccf02010-10-15 18:12:47111 // Create a temporary user data directory if required.
112 ASSERT_TRUE(CreateUserDataDirectory())
113 << "Could not create user data directory.";
[email protected]4a44bc32010-05-28 22:22:44114
[email protected]d4515eb2009-01-30 00:40:43115 // The unit test suite creates a testingbrowser, but we want the real thing.
116 // Delete the current one. We'll install the testing one in TearDown.
117 delete g_browser_process;
[email protected]298883bc2010-04-30 14:50:58118 g_browser_process = NULL;
119
[email protected]470f7a52010-09-23 20:20:38120 // Allow subclasses the opportunity to make changes to the default user data
121 // dir before running any tests.
[email protected]fc82ccf02010-10-15 18:12:47122 ASSERT_TRUE(SetUpUserDataDirectory())
123 << "Could not set up user data directory.";
[email protected]d4515eb2009-01-30 00:40:43124
125 // Don't delete the resources when BrowserMain returns. Many ui classes
126 // cache SkBitmaps in a static field so that if we delete the resource
127 // bundle we'll crash.
128 browser_shutdown::delete_resources_on_shutdown = false;
129
[email protected]470f7a52010-09-23 20:20:38130 // Allow subclasses the opportunity to make changes to the command line before
131 // running any tests.
[email protected]9665fa62009-04-13 22:15:29132 SetUpCommandLine(command_line);
[email protected]03c79d502010-11-16 00:38:26133 // Add command line arguments that are used by all InProcessBrowserTests.
134 PrepareTestCommandLine(command_line);
[email protected]9665fa62009-04-13 22:15:29135
[email protected]03c79d502010-11-16 00:38:26136 // Save the single process mode state before it was reset in this test. This
137 // state will be recovered in TearDown(). Single-process mode is not set in
138 // BrowserMain so it needs to be processed explicitly.
[email protected]56cdae32009-03-12 19:58:20139 original_single_process_ = RenderProcessHost::run_renderer_in_process();
[email protected]8bcdec92009-02-25 16:15:18140 if (command_line->HasSwitch(switches::kSingleProcess))
141 RenderProcessHost::set_run_renderer_in_process(true);
142
[email protected]02dbca0b2010-09-17 07:44:10143#if defined(OS_CHROMEOS)
[email protected]0750b1442010-11-02 21:59:37144 // Make sure that the log directory exists.
145 FilePath log_dir = logging::GetSessionLogFile(*command_line).DirName();
146 file_util::CreateDirectory(log_dir);
[email protected]02dbca0b2010-09-17 07:44:10147#endif // defined(OS_CHROMEOS)
148
[email protected]d4515eb2009-01-30 00:40:43149 SandboxInitWrapper sandbox_wrapper;
[email protected]7c321082009-02-09 15:35:47150 MainFunctionParams params(*command_line, sandbox_wrapper, NULL);
[email protected]d4515eb2009-01-30 00:40:43151 params.ui_task =
152 NewRunnableMethod(this, &InProcessBrowserTest::RunTestOnMainThreadLoop);
[email protected]13324ed2009-04-03 05:14:19153
[email protected]c4ff4952010-01-08 19:12:47154 host_resolver_ = new net::RuleBasedHostResolverProc(
155 new IntranetRedirectHostResolverProc(NULL));
[email protected]c7ad50f2009-09-11 06:28:15156
157 // Something inside the browser does this lookup implicitly. Make it fail
158 // to avoid external dependency. It won't break the tests.
159 host_resolver_->AddSimulatedFailure("*.google.com");
160
161 // See http://en.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol
162 // We don't want the test code to use it.
163 host_resolver_->AddSimulatedFailure("wpad");
164
[email protected]b59ff372009-07-15 22:04:32165 net::ScopedDefaultHostResolverProc scoped_host_resolver_proc(
[email protected]c7ad50f2009-09-11 06:28:15166 host_resolver_.get());
[email protected]5c5de8c2009-09-23 17:11:26167
168 SetUpInProcessBrowserTestFixture();
[email protected]60a782e2010-02-24 22:41:35169
[email protected]d4515eb2009-01-30 00:40:43170 BrowserMain(params);
[email protected]5c5de8c2009-09-23 17:11:26171 TearDownInProcessBrowserTestFixture();
[email protected]d4515eb2009-01-30 00:40:43172}
173
[email protected]03c79d502010-11-16 00:38:26174void InProcessBrowserTest::PrepareTestCommandLine(
175 CommandLine* command_line) {
176 // Propagate commandline settings from test_launcher_utils.
177 test_launcher_utils::PrepareBrowserCommandLineForTests(command_line);
178
179#if defined(OS_WIN)
180 // Hide windows on show.
181 if (!command_line->HasSwitch(kUnitTestShowWindows) && !show_window_)
182 BrowserView::SetShowState(SW_HIDE);
183#endif
184
185 if (dom_automation_enabled_)
186 command_line->AppendSwitch(switches::kDomAutomationController);
187
188 // This is a Browser test.
189 command_line->AppendSwitchASCII(switches::kTestType, kBrowserTestType);
190
191#if defined(OS_WIN)
192 // The Windows sandbox requires that the browser and child processes are the
193 // same binary. So we launch browser_process.exe which loads chrome.dll
194 command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
195 command_line->GetProgram());
196#else
197 // Explicitly set the path of the binary used for child processes, otherwise
198 // they'll try to use browser_tests which doesn't contain ChromeMain.
199 FilePath subprocess_path;
200 PathService::Get(base::FILE_EXE, &subprocess_path);
201#if defined(OS_MACOSX)
202 // Recreate the real environment, run the helper within the app bundle.
203 subprocess_path = subprocess_path.DirName().DirName();
204 DCHECK_EQ(subprocess_path.BaseName().value(), "Contents");
205 subprocess_path =
206 subprocess_path.Append("Versions").Append(chrome::kChromeVersion);
207 subprocess_path =
208 subprocess_path.Append(chrome::kHelperProcessExecutablePath);
209#endif
210 command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
211 subprocess_path);
212#endif
213
214 // If ncecessary, disable TabCloseableStateWatcher.
215 if (!tab_closeable_state_watcher_enabled_)
216 command_line->AppendSwitch(switches::kDisableTabCloseableStateWatcher);
217}
218
[email protected]fc82ccf02010-10-15 18:12:47219bool InProcessBrowserTest::CreateUserDataDirectory() {
220 CommandLine* command_line = CommandLine::ForCurrentProcessMutable();
221 FilePath user_data_dir =
222 command_line->GetSwitchValuePath(switches::kUserDataDir);
223 if (user_data_dir.empty()) {
224 if (temp_user_data_dir_.CreateUniqueTempDir() &&
225 temp_user_data_dir_.IsValid()) {
226 user_data_dir = temp_user_data_dir_.path();
227 } else {
228 LOG(ERROR) << "Could not create temporary user data directory \""
229 << temp_user_data_dir_.path().value() << "\".";
230 return false;
231 }
232 }
233 return test_launcher_utils::OverrideUserDataDir(user_data_dir);
234}
235
[email protected]d4515eb2009-01-30 00:40:43236void InProcessBrowserTest::TearDown() {
237 // Reinstall testing browser process.
238 delete g_browser_process;
239 g_browser_process = new TestingBrowserProcess();
240
241 browser_shutdown::delete_resources_on_shutdown = true;
242
[email protected]eb1bd832010-05-18 20:39:58243#if defined(OS_WIN)
[email protected]d4515eb2009-01-30 00:40:43244 BrowserView::SetShowState(-1);
[email protected]108c2a12009-06-05 22:18:09245#endif
[email protected]56cdae32009-03-12 19:58:20246
247 *CommandLine::ForCurrentProcessMutable() = *original_command_line_;
248 RenderProcessHost::set_run_renderer_in_process(original_single_process_);
[email protected]d4515eb2009-01-30 00:40:43249}
250
[email protected]616381f02010-11-02 15:15:33251void InProcessBrowserTest::AddTabAtIndexToBrowser(
252 Browser* browser,
253 int index,
254 const GURL& url,
255 PageTransition::Type transition) {
256 browser::NavigateParams params(browser, url, transition);
257 params.tabstrip_index = index;
258 params.disposition = NEW_FOREGROUND_TAB;
259 browser::Navigate(&params);
260}
261
262void InProcessBrowserTest::AddTabAtIndex(
263 int index,
264 const GURL& url,
265 PageTransition::Type transition) {
266 AddTabAtIndexToBrowser(browser(), index, url, transition);
267}
268
[email protected]d4515eb2009-01-30 00:40:43269// Creates a browser with a single tab (about:blank), waits for the tab to
270// finish loading and shows the browser.
271Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
272 Browser* browser = Browser::Create(profile);
[email protected]e1c10f182010-09-30 08:53:06273 InitializeBrowser(browser);
274 return browser;
275}
[email protected]d4515eb2009-01-30 00:40:43276
[email protected]e1c10f182010-09-30 08:53:06277Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) {
[email protected]1b74d2122010-10-06 16:49:16278 Browser* browser = Browser::CreateForType(Browser::TYPE_POPUP, profile);
[email protected]e1c10f182010-09-30 08:53:06279 InitializeBrowser(browser);
[email protected]d4515eb2009-01-30 00:40:43280 return browser;
281}
282
[email protected]64f19312010-04-13 22:30:01283void InProcessBrowserTest::RunTestOnMainThreadLoop() {
[email protected]00d0ac22010-10-05 09:30:00284#if defined(OS_POSIX)
285 // Restore default signal handler for SIGTERM, so when the out-of-process
286 // test runner tries to terminate us, we don't catch it and possibly make it
287 // look like a success (http://crbug.com/57578).
288 signal(SIGTERM, SIG_DFL);
289#endif // defined(OS_POSIX)
290
[email protected]304a3172010-05-04 05:38:44291 // On Mac, without the following autorelease pool, code which is directly
292 // executed (as opposed to executed inside a message loop) would autorelease
293 // objects into a higher-level pool. This pool is not recycled in-sync with
294 // the message loops' pools and causes problems with code relying on
295 // deallocation via an autorelease pool (such as browser window closure and
296 // browser shutdown). To avoid this, the following pool is recycled after each
297 // time code is directly executed.
[email protected]c2818d42010-10-18 02:47:39298 base::mac::ScopedNSAutoreleasePool pool;
[email protected]304a3172010-05-04 05:38:44299
[email protected]64f19312010-04-13 22:30:01300 // Pump startup related events.
301 MessageLoopForUI::current()->RunAllPending();
302
303 // In the long term it would be great if we could use a TestingProfile
304 // here and only enable services you want tested, but that requires all
305 // consumers of Profile to handle NULL services.
306 Profile* profile = ProfileManager::GetDefaultProfile();
307 if (!profile) {
308 // We should only be able to get here if the profile already exists and
309 // has been created.
310 NOTREACHED();
311 return;
312 }
[email protected]304a3172010-05-04 05:38:44313 pool.Recycle();
[email protected]64f19312010-04-13 22:30:01314
[email protected]0c7d74f2010-10-11 11:55:26315 BrowserThread::PostTask(
316 BrowserThread::IO, FROM_HERE,
[email protected]64f19312010-04-13 22:30:01317 NewRunnableFunction(chrome_browser_net::SetUrlRequestMocksEnabled, true));
318
319 browser_ = CreateBrowser(profile);
[email protected]304a3172010-05-04 05:38:44320 pool.Recycle();
[email protected]64f19312010-04-13 22:30:01321
[email protected]64f19312010-04-13 22:30:01322 // Pump any pending events that were created as a result of creating a
323 // browser.
324 MessageLoopForUI::current()->RunAllPending();
325
[email protected]28dabab72011-01-05 03:31:26326 SetUpOnMainThread();
327 pool.Recycle();
328
[email protected]64f19312010-04-13 22:30:01329 RunTestOnMainThread();
[email protected]304a3172010-05-04 05:38:44330 pool.Recycle();
[email protected]64f19312010-04-13 22:30:01331
332 CleanUpOnMainThread();
[email protected]304a3172010-05-04 05:38:44333 pool.Recycle();
[email protected]64f19312010-04-13 22:30:01334
335 QuitBrowsers();
[email protected]304a3172010-05-04 05:38:44336 pool.Recycle();
[email protected]64f19312010-04-13 22:30:01337}
338
339void InProcessBrowserTest::QuitBrowsers() {
340 if (BrowserList::size() == 0)
341 return;
342
343 // Invoke CloseAllBrowsersAndExit on a running message loop.
344 // CloseAllBrowsersAndExit exits the message loop after everything has been
345 // shut down properly.
346 MessageLoopForUI::current()->PostTask(
347 FROM_HERE,
348 NewRunnableFunction(&BrowserList::CloseAllBrowsersAndExit));
349 ui_test_utils::RunMessageLoop();
350}