blob: 292ae8e09f41c3469d050092af9a7733e027add4 [file] [log] [blame]
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/in_process_browser_test.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#if defined(OS_WIN)
#include "chrome/browser/views/frame/browser_view.h"
#endif
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/main_function_params.h"
#include "chrome/test/testing_browser_process.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/host_resolver_unittest.h"
#include "sandbox/src/dep.h"
extern int BrowserMain(const MainFunctionParams&);
const wchar_t kUnitTestShowWindows[] = L"show-windows";
// Delay for the time-out at which we stop the inner-message loop the first
// time.
const int kInitialTimeoutInMS = 30000;
// Delay for sub-sequent time-outs once the initial time-out happened.
const int kSubsequentTimeoutInMS = 5000;
namespace {
bool DieFileDie(const std::wstring& file, bool recurse) {
if (!file_util::PathExists(file))
return true;
// Sometimes Delete fails, so try a few more times.
for (int i = 0; i < 10; ++i) {
if (file_util::Delete(file, recurse))
return true;
PlatformThread::Sleep(100);
}
return false;
}
} // namespace
InProcessBrowserTest::InProcessBrowserTest()
: browser_(NULL),
show_window_(false),
dom_automation_enabled_(false),
single_process_(false),
original_single_process_(false) {
}
void InProcessBrowserTest::SetUp() {
// Cleanup the user data dir.
std::wstring user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
ASSERT_LT(10, static_cast<int>(user_data_dir.size())) <<
"The user data directory name passed into this test was too "
"short to delete safely. Please check the user-data-dir "
"argument and try again.";
ASSERT_TRUE(DieFileDie(user_data_dir, true));
// The unit test suite creates a testingbrowser, but we want the real thing.
// Delete the current one. We'll install the testing one in TearDown.
delete g_browser_process;
// Don't delete the resources when BrowserMain returns. Many ui classes
// cache SkBitmaps in a static field so that if we delete the resource
// bundle we'll crash.
browser_shutdown::delete_resources_on_shutdown = false;
CommandLine* command_line = CommandLine::ForCurrentProcessMutable();
original_command_line_.reset(new CommandLine(*command_line));
SetUpCommandLine(command_line);
#if defined(OS_WIN)
// Hide windows on show.
if (!command_line->HasSwitch(kUnitTestShowWindows) && !show_window_)
BrowserView::SetShowState(SW_HIDE);
#endif
if (dom_automation_enabled_)
command_line->AppendSwitch(switches::kDomAutomationController);
if (single_process_)
command_line->AppendSwitch(switches::kSingleProcess);
command_line->AppendSwitchWithValue(switches::kUserDataDir, user_data_dir);
// For some reason the sandbox wasn't happy running in test mode. These
// tests aren't intended to test the sandbox, so we turn it off.
command_line->AppendSwitch(switches::kNoSandbox);
// Single-process mode is not set in BrowserMain so it needs to be processed
// explicitlty.
original_single_process_ = RenderProcessHost::run_renderer_in_process();
if (command_line->HasSwitch(switches::kSingleProcess))
RenderProcessHost::set_run_renderer_in_process(true);
// Explicitly set the path of the exe used for the renderer and plugin,
// otherwise they'll try to use unit_test.exe.
std::wstring subprocess_path;
PathService::Get(base::FILE_EXE, &subprocess_path);
FilePath fp_subprocess_path = FilePath::FromWStringHack(subprocess_path);
subprocess_path = fp_subprocess_path.DirName().ToWStringHack();
file_util::AppendToPath(&subprocess_path,
chrome::kBrowserProcessExecutablePath);
command_line->AppendSwitchWithValue(switches::kBrowserSubprocessPath,
subprocess_path);
// Enable warning level logging so that we can see when bad stuff happens.
command_line->AppendSwitch(switches::kEnableLogging);
command_line->AppendSwitchWithValue(switches::kLoggingLevel,
IntToWString(1)); // warning
SandboxInitWrapper sandbox_wrapper;
MainFunctionParams params(*command_line, sandbox_wrapper, NULL);
params.ui_task =
NewRunnableMethod(this, &InProcessBrowserTest::RunTestOnMainThreadLoop);
scoped_refptr<net::RuleBasedHostMapper> host_mapper(
new net::RuleBasedHostMapper());
ConfigureHostMapper(host_mapper.get());
net::ScopedHostMapper scoped_host_mapper(host_mapper.get());
BrowserMain(params);
}
void InProcessBrowserTest::TearDown() {
// Reinstall testing browser process.
delete g_browser_process;
g_browser_process = new TestingBrowserProcess();
browser_shutdown::delete_resources_on_shutdown = true;
#if defined(WIN)
BrowserView::SetShowState(-1);
#endif
*CommandLine::ForCurrentProcessMutable() = *original_command_line_;
RenderProcessHost::set_run_renderer_in_process(original_single_process_);
}
HTTPTestServer* InProcessBrowserTest::StartHTTPServer() {
// The HTTPServer must run on the IO thread.
DCHECK(!http_server_.get());
http_server_ = HTTPTestServer::CreateServer(
L"chrome/test/data",
g_browser_process->io_thread()->message_loop());
return http_server_.get();
}
// Creates a browser with a single tab (about:blank), waits for the tab to
// finish loading and shows the browser.
Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
Browser* browser = Browser::Create(profile);
browser->AddTabWithURL(
GURL("about:blank"), GURL(), PageTransition::START_PAGE, true, -1, false,
NULL);
// Wait for the page to finish loading.
ui_test_utils::WaitForNavigation(
&browser->GetSelectedTabContents()->controller());
browser->window()->Show();
return browser;
}
void InProcessBrowserTest::RunTestOnMainThreadLoop() {
// In the long term it would be great if we could use a TestingProfile
// here and only enable services you want tested, but that requires all
// consumers of Profile to handle NULL services.
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
ProfileManager* profile_manager = g_browser_process->profile_manager();
Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
if (!profile) {
// We should only be able to get here if the profile already exists and
// has been created.
NOTREACHED();
MessageLoopForUI::current()->Quit();
return;
}
// Before we run the browser, we have to hack the path to the exe to match
// what it would be if Chrome was running, because it is used to fork renderer
// processes, on Linux at least (failure to do so will cause a browser_test to
// be run instead of a renderer).
FilePath chrome_path;
CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
chrome_path = chrome_path.DirName();
#if defined(OS_WIN)
chrome_path = chrome_path.Append(chrome::kBrowserProcessExecutablePath);
#elif defined(OS_POSIX)
chrome_path = chrome_path.Append(
WideToASCII(chrome::kBrowserProcessExecutablePath));
#endif
CHECK(PathService::Override(base::FILE_EXE, chrome_path));
browser_ = CreateBrowser(profile);
// Start the timeout timer to prevent hangs.
MessageLoopForUI::current()->PostDelayedTask(FROM_HERE,
NewRunnableMethod(this, &InProcessBrowserTest::TimedOut),
kInitialTimeoutInMS);
RunTestOnMainThread();
CleanUpOnMainThread();
BrowserList::const_iterator browser = BrowserList::begin();
for (; browser != BrowserList::end(); ++browser)
(*browser)->CloseAllTabs();
// Stop the HTTP server.
http_server_ = NULL;
MessageLoopForUI::current()->Quit();
}
void InProcessBrowserTest::ConfigureHostMapper(
net::RuleBasedHostMapper* host_mapper) {
host_mapper->AllowDirectLookup("*.google.com");
// See http://en.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol
// We don't want the test code to use it.
host_mapper->AddSimulatedFailure("wpad");
}
void InProcessBrowserTest::TimedOut() {
DCHECK(MessageLoopForUI::current()->IsNested());
GTEST_NONFATAL_FAILURE_("Timed-out");
// Start the timeout timer to prevent hangs.
MessageLoopForUI::current()->PostDelayedTask(FROM_HERE,
NewRunnableMethod(this, &InProcessBrowserTest::TimedOut),
kSubsequentTimeoutInMS);
MessageLoopForUI::current()->Quit();
}