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.
5 #include "chrome/test/base/in_process_browser_test.h"
7 #include "base/auto_reset.h"
8 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/lazy_instance.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/test/test_file_util.h"
17 #include "base/threading/non_thread_safe.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/lifetime/application_lifetime.h"
20 #include "chrome/browser/net/net_error_tab_helper.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_finder.h"
25 #include "chrome/browser/ui/browser_list.h"
26 #include "chrome/browser/ui/browser_list_observer.h"
27 #include "chrome/browser/ui/browser_navigator.h"
28 #include "chrome/browser/ui/browser_tabstrip.h"
29 #include "chrome/browser/ui/browser_window.h"
30 #include "chrome/browser/ui/host_desktop.h"
31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
32 #include "chrome/common/chrome_constants.h"
33 #include "chrome/common/chrome_paths.h"
34 #include "chrome/common/chrome_switches.h"
35 #include "chrome/common/logging_chrome.h"
36 #include "chrome/common/url_constants.h"
37 #include "chrome/renderer/chrome_content_renderer_client.h"
38 #include "chrome/test/base/chrome_test_suite.h"
39 #include "chrome/test/base/test_launcher_utils.h"
40 #include "chrome/test/base/test_switches.h"
41 #include "chrome/test/base/testing_browser_process.h"
42 #include "chrome/test/base/ui_test_utils.h"
43 #include "components/google/core/browser/google_util.h"
44 #include "components/os_crypt/os_crypt.h"
45 #include "content/public/browser/notification_service.h"
46 #include "content/public/browser/notification_types.h"
47 #include "content/public/test/browser_test_utils.h"
48 #include "content/public/test/test_launcher.h"
49 #include "content/public/test/test_navigation_observer.h"
50 #include "net/test/embedded_test_server/embedded_test_server.h"
51 #include "net/test/spawned_test_server/spawned_test_server.h"
53 #if defined(OS_MACOSX)
54 #include "base/mac/scoped_nsautorelease_pool.h"
58 #include "base/win/scoped_com_initializer.h"
59 #include "base/win/windows_version.h"
60 #include "ui/base/win/atl_module.h"
61 #include "win8/test/metro_registration_helper.h"
62 #include "win8/test/test_registrar_constants.h"
65 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
66 #include "chrome/browser/captive_portal/captive_portal_service.h"
69 #if !defined(OS_ANDROID) && !defined(OS_IOS)
70 #include "components/storage_monitor/test_storage_monitor.h"
73 #if defined(OS_CHROMEOS)
74 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
79 // Passed as value of kTestType.
80 const char kBrowserTestType
[] = "browser";
82 // A BrowserListObserver that makes sure that all browsers created are on the
83 // |allowed_desktop_|.
84 class SingleDesktopTestObserver
: public chrome::BrowserListObserver
,
85 public base::NonThreadSafe
{
87 explicit SingleDesktopTestObserver(chrome::HostDesktopType allowed_desktop
);
88 virtual ~SingleDesktopTestObserver();
90 // chrome::BrowserListObserver:
91 virtual void OnBrowserAdded(Browser
* browser
) override
;
94 chrome::HostDesktopType allowed_desktop_
;
96 DISALLOW_COPY_AND_ASSIGN(SingleDesktopTestObserver
);
99 SingleDesktopTestObserver::SingleDesktopTestObserver(
100 chrome::HostDesktopType allowed_desktop
)
101 : allowed_desktop_(allowed_desktop
) {
102 BrowserList::AddObserver(this);
105 SingleDesktopTestObserver::~SingleDesktopTestObserver() {
106 BrowserList::RemoveObserver(this);
109 void SingleDesktopTestObserver::OnBrowserAdded(Browser
* browser
) {
110 CHECK(CalledOnValidThread());
111 CHECK_EQ(browser
->host_desktop_type(), allowed_desktop_
);
116 InProcessBrowserTest::InProcessBrowserTest()
118 exit_when_last_browser_closes_(true),
119 open_about_blank_on_browser_launch_(true),
120 multi_desktop_test_(false)
121 #if defined(OS_MACOSX)
122 , autorelease_pool_(NULL
)
125 #if defined(OS_MACOSX)
126 // TODO(phajdan.jr): Make browser_tests self-contained on Mac, remove this.
127 // Before we run the browser, we have to hack the path to the exe to match
128 // what it would be if Chrome was running, because it is used to fork renderer
129 // processes, on Linux at least (failure to do so will cause a browser_test to
130 // be run instead of a renderer).
131 base::FilePath chrome_path
;
132 CHECK(PathService::Get(base::FILE_EXE
, &chrome_path
));
133 chrome_path
= chrome_path
.DirName();
134 chrome_path
= chrome_path
.Append(chrome::kBrowserProcessExecutablePath
);
135 CHECK(PathService::Override(base::FILE_EXE
, chrome_path
));
136 #endif // defined(OS_MACOSX)
138 CreateTestServer(base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
139 base::FilePath src_dir
;
140 CHECK(PathService::Get(base::DIR_SOURCE_ROOT
, &src_dir
));
141 base::FilePath test_data_dir
= src_dir
.AppendASCII("chrome/test/data");
142 embedded_test_server()->ServeFilesFromDirectory(test_data_dir
);
144 // chrome::DIR_TEST_DATA isn't going to be setup until after we call
145 // ContentMain. However that is after tests' constructors or SetUp methods,
146 // which sometimes need it. So just override it.
147 CHECK(PathService::Override(chrome::DIR_TEST_DATA
, test_data_dir
));
150 InProcessBrowserTest::~InProcessBrowserTest() {
153 void InProcessBrowserTest::SetUp() {
154 // Browser tests will create their own g_browser_process later.
155 DCHECK(!g_browser_process
);
157 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
159 // Auto-reload breaks many browser tests, which assume error pages won't be
160 // reloaded out from under them. Tests that expect or desire this behavior can
161 // append switches::kEnableOfflineAutoReload, which will override the disable
163 command_line
->AppendSwitch(switches::kDisableOfflineAutoReload
);
165 // Allow subclasses to change the command line before running any tests.
166 SetUpCommandLine(command_line
);
167 // Add command line arguments that are used by all InProcessBrowserTests.
168 PrepareTestCommandLine(command_line
);
170 // Create a temporary user data directory if required.
171 ASSERT_TRUE(CreateUserDataDirectory())
172 << "Could not create user data directory.";
174 // Allow subclasses the opportunity to make changes to the default user data
175 // dir before running any tests.
176 ASSERT_TRUE(SetUpUserDataDirectory())
177 << "Could not set up user data directory.";
179 #if defined(OS_CHROMEOS)
180 // Make sure that the log directory exists.
181 base::FilePath log_dir
= logging::GetSessionLogFile(*command_line
).DirName();
182 base::CreateDirectory(log_dir
);
183 // Disable IME extension loading to avoid many browser tests failures.
184 chromeos::input_method::DisableExtensionLoading();
185 #endif // defined(OS_CHROMEOS)
187 #if defined(OS_MACOSX)
188 // Always use the MockKeychain if OS encription is used (which is when
189 // anything sensitive gets stored, including Cookies). Without this,
190 // many tests will hang waiting for a user to approve KeyChain access.
191 OSCrypt::UseMockKeychain(true);
194 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
195 CaptivePortalService::set_state_for_testing(
196 CaptivePortalService::DISABLED_FOR_TESTING
);
199 chrome_browser_net::NetErrorTabHelper::set_state_for_testing(
200 chrome_browser_net::NetErrorTabHelper::TESTING_FORCE_DISABLED
);
202 google_util::SetMockLinkDoctorBaseURLForTesting();
205 base::win::Version version
= base::win::GetVersion();
206 // Although Ash officially is only supported for users on Win7+, we still run
207 // ash_unittests on Vista builders, so we still need to initialize COM.
208 if (version
>= base::win::VERSION_VISTA
&&
209 CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests
)) {
210 com_initializer_
.reset(new base::win::ScopedCOMInitializer());
211 ui::win::CreateATLModuleIfNeeded();
212 if (version
>= base::win::VERSION_WIN8
)
213 ASSERT_TRUE(win8::MakeTestDefaultBrowserSynchronously());
217 BrowserTestBase::SetUp();
220 void InProcessBrowserTest::PrepareTestCommandLine(CommandLine
* command_line
) {
221 // Propagate commandline settings from test_launcher_utils.
222 test_launcher_utils::PrepareBrowserCommandLineForTests(command_line
);
224 // This is a Browser test.
225 command_line
->AppendSwitchASCII(switches::kTestType
, kBrowserTestType
);
228 if (command_line
->HasSwitch(switches::kAshBrowserTests
)) {
229 command_line
->AppendSwitchNative(switches::kViewerLaunchViaAppId
,
230 win8::test::kDefaultTestAppUserModelId
);
231 // Ash already launches with a single browser opened, add kSilentLaunch to
232 // make sure StartupBrowserCreator doesn't attempt to launch a browser on
233 // the native desktop on startup.
234 command_line
->AppendSwitch(switches::kSilentLaunch
);
238 #if defined(OS_MACOSX)
239 // Explicitly set the path of the binary used for child processes, otherwise
240 // they'll try to use browser_tests which doesn't contain ChromeMain.
241 base::FilePath subprocess_path
;
242 PathService::Get(base::FILE_EXE
, &subprocess_path
);
243 // Recreate the real environment, run the helper within the app bundle.
244 subprocess_path
= subprocess_path
.DirName().DirName();
245 DCHECK_EQ(subprocess_path
.BaseName().value(), "Contents");
247 subprocess_path
.Append("Versions").Append(chrome::kChromeVersion
);
249 subprocess_path
.Append(chrome::kHelperProcessExecutablePath
);
250 command_line
->AppendSwitchPath(switches::kBrowserSubprocessPath
,
254 // TODO(pkotwicz): Investigate if we can remove this switch.
255 if (exit_when_last_browser_closes_
)
256 command_line
->AppendSwitch(switches::kDisableZeroBrowsersOpenForTests
);
258 if (open_about_blank_on_browser_launch_
&& command_line
->GetArgs().empty())
259 command_line
->AppendArg(url::kAboutBlankURL
);
262 bool InProcessBrowserTest::CreateUserDataDirectory() {
263 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
264 base::FilePath user_data_dir
=
265 command_line
->GetSwitchValuePath(switches::kUserDataDir
);
266 if (user_data_dir
.empty()) {
267 if (temp_user_data_dir_
.CreateUniqueTempDir() &&
268 temp_user_data_dir_
.IsValid()) {
269 user_data_dir
= temp_user_data_dir_
.path();
271 LOG(ERROR
) << "Could not create temporary user data directory \""
272 << temp_user_data_dir_
.path().value() << "\".";
276 return test_launcher_utils::OverrideUserDataDir(user_data_dir
);
279 void InProcessBrowserTest::TearDown() {
280 DCHECK(!g_browser_process
);
282 com_initializer_
.reset();
284 BrowserTestBase::TearDown();
287 void InProcessBrowserTest::AddTabAtIndexToBrowser(
291 ui::PageTransition transition
) {
292 chrome::NavigateParams
params(browser
, url
, transition
);
293 params
.tabstrip_index
= index
;
294 params
.disposition
= NEW_FOREGROUND_TAB
;
295 chrome::Navigate(¶ms
);
297 content::WaitForLoadStop(params
.target_contents
);
300 void InProcessBrowserTest::AddTabAtIndex(
303 ui::PageTransition transition
) {
304 AddTabAtIndexToBrowser(browser(), index
, url
, transition
);
307 bool InProcessBrowserTest::SetUpUserDataDirectory() {
311 // Creates a browser with a single tab (about:blank), waits for the tab to
312 // finish loading and shows the browser.
313 Browser
* InProcessBrowserTest::CreateBrowser(Profile
* profile
) {
314 Browser
* browser
= new Browser(
315 Browser::CreateParams(profile
, chrome::GetActiveDesktop()));
316 AddBlankTabAndShow(browser
);
320 Browser
* InProcessBrowserTest::CreateIncognitoBrowser() {
321 // Create a new browser with using the incognito profile.
322 Browser
* incognito
= new Browser(
323 Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile(),
324 chrome::GetActiveDesktop()));
325 AddBlankTabAndShow(incognito
);
329 Browser
* InProcessBrowserTest::CreateBrowserForPopup(Profile
* profile
) {
331 new Browser(Browser::CreateParams(Browser::TYPE_POPUP
, profile
,
332 chrome::GetActiveDesktop()));
333 AddBlankTabAndShow(browser
);
337 Browser
* InProcessBrowserTest::CreateBrowserForApp(
338 const std::string
& app_name
,
340 Browser
* browser
= new Browser(
341 Browser::CreateParams::CreateForApp(
342 app_name
, false /* trusted_source */, gfx::Rect(), profile
,
343 chrome::GetActiveDesktop()));
344 AddBlankTabAndShow(browser
);
348 void InProcessBrowserTest::AddBlankTabAndShow(Browser
* browser
) {
349 content::WindowedNotificationObserver
observer(
350 content::NOTIFICATION_LOAD_STOP
,
351 content::NotificationService::AllSources());
352 chrome::AddSelectedTabWithURL(browser
,
353 GURL(url::kAboutBlankURL
),
354 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
);
357 browser
->window()->Show();
360 #if !defined(OS_MACOSX)
361 CommandLine
InProcessBrowserTest::GetCommandLineForRelaunch() {
362 CommandLine
new_command_line(CommandLine::ForCurrentProcess()->GetProgram());
363 CommandLine::SwitchMap switches
=
364 CommandLine::ForCurrentProcess()->GetSwitches();
365 switches
.erase(switches::kUserDataDir
);
366 switches
.erase(content::kSingleProcessTestsFlag
);
367 switches
.erase(switches::kSingleProcess
);
368 new_command_line
.AppendSwitch(content::kLaunchAsBrowser
);
370 base::FilePath user_data_dir
;
371 PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir
);
372 new_command_line
.AppendSwitchPath(switches::kUserDataDir
, user_data_dir
);
374 for (CommandLine::SwitchMap::const_iterator iter
= switches
.begin();
375 iter
!= switches
.end(); ++iter
) {
376 new_command_line
.AppendSwitchNative((*iter
).first
, (*iter
).second
);
378 return new_command_line
;
382 void InProcessBrowserTest::RunTestOnMainThreadLoop() {
383 // Pump startup related events.
384 content::RunAllPendingInMessageLoop();
386 chrome::HostDesktopType active_desktop
= chrome::GetActiveDesktop();
387 // Self-adds/removes itself from the BrowserList observers.
388 scoped_ptr
<SingleDesktopTestObserver
> single_desktop_test_observer
;
389 if (!multi_desktop_test_
) {
390 single_desktop_test_observer
.reset(
391 new SingleDesktopTestObserver(active_desktop
));
394 const BrowserList
* active_browser_list
=
395 BrowserList::GetInstance(active_desktop
);
396 if (!active_browser_list
->empty()) {
397 browser_
= active_browser_list
->get(0);
399 // There are cases where windows get created maximized by default.
400 if (browser_
->window()->IsMaximized())
401 browser_
->window()->Restore();
403 content::WaitForLoadStop(
404 browser_
->tab_strip_model()->GetActiveWebContents());
407 #if !defined(OS_ANDROID) && !defined(OS_IOS)
408 // Do not use the real StorageMonitor for tests, which introduces another
409 // source of variability and potential slowness.
410 ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateForBrowserTests());
413 #if defined(OS_MACOSX)
414 // On Mac, without the following autorelease pool, code which is directly
415 // executed (as opposed to executed inside a message loop) would autorelease
416 // objects into a higher-level pool. This pool is not recycled in-sync with
417 // the message loops' pools and causes problems with code relying on
418 // deallocation via an autorelease pool (such as browser window closure and
419 // browser shutdown). To avoid this, the following pool is recycled after each
420 // time code is directly executed.
421 autorelease_pool_
= new base::mac::ScopedNSAutoreleasePool
;
424 // Pump any pending events that were created as a result of creating a
426 content::RunAllPendingInMessageLoop();
429 #if defined(OS_MACOSX)
430 autorelease_pool_
->Recycle();
433 if (!HasFatalFailure())
434 RunTestOnMainThread();
435 #if defined(OS_MACOSX)
436 autorelease_pool_
->Recycle();
439 // Invoke cleanup and quit even if there are failures. This is similar to
440 // gtest in that it invokes TearDown even if Setup fails.
441 TearDownOnMainThread();
442 #if defined(OS_MACOSX)
443 autorelease_pool_
->Recycle();
446 // Sometimes tests leave Quit tasks in the MessageLoop (for shame), so let's
447 // run all pending messages here to avoid preempting the QuitBrowsers tasks.
448 // TODO(jbates) Once crbug.com/134753 is fixed, this can be removed because it
449 // will not be possible to post Quit tasks.
450 content::RunAllPendingInMessageLoop();
453 // All BrowserLists should be empty at this point.
454 for (chrome::HostDesktopType t
= chrome::HOST_DESKTOP_TYPE_FIRST
;
455 t
< chrome::HOST_DESKTOP_TYPE_COUNT
;
456 t
= static_cast<chrome::HostDesktopType
>(t
+ 1)) {
457 CHECK(BrowserList::GetInstance(t
)->empty()) << t
;
461 void InProcessBrowserTest::QuitBrowsers() {
462 if (chrome::GetTotalBrowserCount() == 0) {
463 chrome::NotifyAppTerminating();
467 // Invoke AttemptExit on a running message loop.
468 // AttemptExit exits the message loop after everything has been
469 // shut down properly.
470 base::MessageLoopForUI::current()->PostTask(FROM_HERE
,
471 base::Bind(&chrome::AttemptExit
));
472 content::RunMessageLoop();
474 #if defined(OS_MACOSX)
475 // chrome::AttemptExit() will attempt to close all browsers by deleting
476 // their tab contents. The last tab contents being removed triggers closing of
477 // the browser window.
479 // On the Mac, this eventually reaches
480 // -[BrowserWindowController windowWillClose:], which will post a deferred
481 // -autorelease on itself to ultimately destroy the Browser object. The line
482 // below is necessary to pump these pending messages to ensure all Browsers
484 content::RunAllPendingInMessageLoop();
485 delete autorelease_pool_
;
486 autorelease_pool_
= NULL
;