• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/test/base/in_process_browser_test.h"
6 
7 #include "base/auto_reset.h"
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/files/file_path.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"
52 
53 #if defined(OS_MACOSX)
54 #include "base/mac/scoped_nsautorelease_pool.h"
55 #endif
56 
57 #if defined(OS_WIN)
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"
63 #endif
64 
65 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
66 #include "chrome/browser/captive_portal/captive_portal_service.h"
67 #endif
68 
69 #if !defined(OS_ANDROID) && !defined(OS_IOS)
70 #include "components/storage_monitor/test_storage_monitor.h"
71 #endif
72 
73 namespace {
74 
75 // Passed as value of kTestType.
76 const char kBrowserTestType[] = "browser";
77 
78 // A BrowserListObserver that makes sure that all browsers created are on the
79 // |allowed_desktop_|.
80 class SingleDesktopTestObserver : public chrome::BrowserListObserver,
81                                   public base::NonThreadSafe {
82  public:
83   explicit SingleDesktopTestObserver(chrome::HostDesktopType allowed_desktop);
84   virtual ~SingleDesktopTestObserver();
85 
86   // chrome::BrowserListObserver:
87   virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
88 
89  private:
90   chrome::HostDesktopType allowed_desktop_;
91 
92   DISALLOW_COPY_AND_ASSIGN(SingleDesktopTestObserver);
93 };
94 
SingleDesktopTestObserver(chrome::HostDesktopType allowed_desktop)95 SingleDesktopTestObserver::SingleDesktopTestObserver(
96     chrome::HostDesktopType allowed_desktop)
97         : allowed_desktop_(allowed_desktop) {
98   BrowserList::AddObserver(this);
99 }
100 
~SingleDesktopTestObserver()101 SingleDesktopTestObserver::~SingleDesktopTestObserver() {
102   BrowserList::RemoveObserver(this);
103 }
104 
OnBrowserAdded(Browser * browser)105 void SingleDesktopTestObserver::OnBrowserAdded(Browser* browser) {
106   CHECK(CalledOnValidThread());
107   CHECK_EQ(browser->host_desktop_type(), allowed_desktop_);
108 }
109 
110 }  // namespace
111 
InProcessBrowserTest()112 InProcessBrowserTest::InProcessBrowserTest()
113     : browser_(NULL),
114       exit_when_last_browser_closes_(true),
115       multi_desktop_test_(false)
116 #if defined(OS_MACOSX)
117       , autorelease_pool_(NULL)
118 #endif  // OS_MACOSX
119     {
120 #if defined(OS_MACOSX)
121   // TODO(phajdan.jr): Make browser_tests self-contained on Mac, remove this.
122   // Before we run the browser, we have to hack the path to the exe to match
123   // what it would be if Chrome was running, because it is used to fork renderer
124   // processes, on Linux at least (failure to do so will cause a browser_test to
125   // be run instead of a renderer).
126   base::FilePath chrome_path;
127   CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
128   chrome_path = chrome_path.DirName();
129   chrome_path = chrome_path.Append(chrome::kBrowserProcessExecutablePath);
130   CHECK(PathService::Override(base::FILE_EXE, chrome_path));
131 #endif  // defined(OS_MACOSX)
132 
133   CreateTestServer(base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
134   base::FilePath src_dir;
135   CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
136   base::FilePath test_data_dir = src_dir.AppendASCII("chrome/test/data");
137   embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
138 
139   // chrome::DIR_TEST_DATA isn't going to be setup until after we call
140   // ContentMain. However that is after tests' constructors or SetUp methods,
141   // which sometimes need it. So just override it.
142   CHECK(PathService::Override(chrome::DIR_TEST_DATA, test_data_dir));
143 }
144 
~InProcessBrowserTest()145 InProcessBrowserTest::~InProcessBrowserTest() {
146 }
147 
SetUp()148 void InProcessBrowserTest::SetUp() {
149   // Browser tests will create their own g_browser_process later.
150   DCHECK(!g_browser_process);
151 
152   CommandLine* command_line = CommandLine::ForCurrentProcess();
153 
154   // Auto-reload breaks many browser tests, which assume error pages won't be
155   // reloaded out from under them. Tests that expect or desire this behavior can
156   // append switches::kEnableOfflineAutoReload, which will override the disable
157   // here.
158   command_line->AppendSwitch(switches::kDisableOfflineAutoReload);
159 
160   // Allow subclasses to change the command line before running any tests.
161   SetUpCommandLine(command_line);
162   // Add command line arguments that are used by all InProcessBrowserTests.
163   PrepareTestCommandLine(command_line);
164 
165   // Create a temporary user data directory if required.
166   ASSERT_TRUE(CreateUserDataDirectory())
167       << "Could not create user data directory.";
168 
169   // Allow subclasses the opportunity to make changes to the default user data
170   // dir before running any tests.
171   ASSERT_TRUE(SetUpUserDataDirectory())
172       << "Could not set up user data directory.";
173 
174 #if defined(OS_CHROMEOS)
175   // Make sure that the log directory exists.
176   base::FilePath log_dir = logging::GetSessionLogFile(*command_line).DirName();
177   base::CreateDirectory(log_dir);
178 #endif  // defined(OS_CHROMEOS)
179 
180 #if defined(OS_MACOSX)
181   // Always use the MockKeychain if OS encription is used (which is when
182   // anything sensitive gets stored, including Cookies).  Without this,
183   // many tests will hang waiting for a user to approve KeyChain access.
184   OSCrypt::UseMockKeychain(true);
185 #endif
186 
187 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
188   CaptivePortalService::set_state_for_testing(
189       CaptivePortalService::DISABLED_FOR_TESTING);
190 #endif
191 
192   chrome_browser_net::NetErrorTabHelper::set_state_for_testing(
193       chrome_browser_net::NetErrorTabHelper::TESTING_FORCE_DISABLED);
194 
195   google_util::SetMockLinkDoctorBaseURLForTesting();
196 
197 #if defined(OS_WIN)
198   base::win::Version version = base::win::GetVersion();
199   // Although Ash officially is only supported for users on Win7+, we still run
200   // ash_unittests on Vista builders, so we still need to initialize COM.
201   if (version >= base::win::VERSION_VISTA &&
202       CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) {
203     com_initializer_.reset(new base::win::ScopedCOMInitializer());
204     ui::win::CreateATLModuleIfNeeded();
205     if (version >= base::win::VERSION_WIN8)
206       ASSERT_TRUE(win8::MakeTestDefaultBrowserSynchronously());
207   }
208 #endif
209 
210   BrowserTestBase::SetUp();
211 }
212 
PrepareTestCommandLine(CommandLine * command_line)213 void InProcessBrowserTest::PrepareTestCommandLine(CommandLine* command_line) {
214   // Propagate commandline settings from test_launcher_utils.
215   test_launcher_utils::PrepareBrowserCommandLineForTests(command_line);
216 
217   // This is a Browser test.
218   command_line->AppendSwitchASCII(switches::kTestType, kBrowserTestType);
219 
220 #if defined(OS_WIN)
221   if (command_line->HasSwitch(switches::kAshBrowserTests)) {
222     command_line->AppendSwitchNative(switches::kViewerLaunchViaAppId,
223                                      win8::test::kDefaultTestAppUserModelId);
224     // Ash already launches with a single browser opened, add kSilentLaunch to
225     // make sure StartupBrowserCreator doesn't attempt to launch a browser on
226     // the native desktop on startup.
227     command_line->AppendSwitch(switches::kSilentLaunch);
228   }
229 #endif
230 
231 #if defined(OS_MACOSX)
232   // Explicitly set the path of the binary used for child processes, otherwise
233   // they'll try to use browser_tests which doesn't contain ChromeMain.
234   base::FilePath subprocess_path;
235   PathService::Get(base::FILE_EXE, &subprocess_path);
236   // Recreate the real environment, run the helper within the app bundle.
237   subprocess_path = subprocess_path.DirName().DirName();
238   DCHECK_EQ(subprocess_path.BaseName().value(), "Contents");
239   subprocess_path =
240       subprocess_path.Append("Versions").Append(chrome::kChromeVersion);
241   subprocess_path =
242       subprocess_path.Append(chrome::kHelperProcessExecutablePath);
243   command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
244                                  subprocess_path);
245 #endif
246 
247   // TODO(pkotwicz): Investigate if we can remove this switch.
248   if (exit_when_last_browser_closes_)
249     command_line->AppendSwitch(switches::kDisableZeroBrowsersOpenForTests);
250 
251   if (command_line->GetArgs().empty())
252     command_line->AppendArg(url::kAboutBlankURL);
253 }
254 
CreateUserDataDirectory()255 bool InProcessBrowserTest::CreateUserDataDirectory() {
256   CommandLine* command_line = CommandLine::ForCurrentProcess();
257   base::FilePath user_data_dir =
258       command_line->GetSwitchValuePath(switches::kUserDataDir);
259   if (user_data_dir.empty()) {
260     if (temp_user_data_dir_.CreateUniqueTempDir() &&
261         temp_user_data_dir_.IsValid()) {
262       user_data_dir = temp_user_data_dir_.path();
263     } else {
264       LOG(ERROR) << "Could not create temporary user data directory \""
265                  << temp_user_data_dir_.path().value() << "\".";
266       return false;
267     }
268   }
269   return test_launcher_utils::OverrideUserDataDir(user_data_dir);
270 }
271 
TearDown()272 void InProcessBrowserTest::TearDown() {
273   DCHECK(!g_browser_process);
274 #if defined(OS_WIN)
275   com_initializer_.reset();
276 #endif
277   BrowserTestBase::TearDown();
278 }
279 
AddTabAtIndexToBrowser(Browser * browser,int index,const GURL & url,content::PageTransition transition)280 void InProcessBrowserTest::AddTabAtIndexToBrowser(
281     Browser* browser,
282     int index,
283     const GURL& url,
284     content::PageTransition transition) {
285   chrome::NavigateParams params(browser, url, transition);
286   params.tabstrip_index = index;
287   params.disposition = NEW_FOREGROUND_TAB;
288   chrome::Navigate(&params);
289 
290   content::WaitForLoadStop(params.target_contents);
291 }
292 
AddTabAtIndex(int index,const GURL & url,content::PageTransition transition)293 void InProcessBrowserTest::AddTabAtIndex(
294     int index,
295     const GURL& url,
296     content::PageTransition transition) {
297   AddTabAtIndexToBrowser(browser(), index, url, transition);
298 }
299 
SetUpUserDataDirectory()300 bool InProcessBrowserTest::SetUpUserDataDirectory() {
301   return true;
302 }
303 
304 // Creates a browser with a single tab (about:blank), waits for the tab to
305 // finish loading and shows the browser.
CreateBrowser(Profile * profile)306 Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
307   Browser* browser = new Browser(
308       Browser::CreateParams(profile, chrome::GetActiveDesktop()));
309   AddBlankTabAndShow(browser);
310   return browser;
311 }
312 
CreateIncognitoBrowser()313 Browser* InProcessBrowserTest::CreateIncognitoBrowser() {
314   // Create a new browser with using the incognito profile.
315   Browser* incognito = new Browser(
316       Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile(),
317                             chrome::GetActiveDesktop()));
318   AddBlankTabAndShow(incognito);
319   return incognito;
320 }
321 
CreateBrowserForPopup(Profile * profile)322 Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) {
323   Browser* browser =
324       new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile,
325                   chrome::GetActiveDesktop()));
326   AddBlankTabAndShow(browser);
327   return browser;
328 }
329 
CreateBrowserForApp(const std::string & app_name,Profile * profile)330 Browser* InProcessBrowserTest::CreateBrowserForApp(
331     const std::string& app_name,
332     Profile* profile) {
333   Browser* browser = new Browser(
334       Browser::CreateParams::CreateForApp(
335           app_name, false /* trusted_source */, gfx::Rect(), profile,
336           chrome::GetActiveDesktop()));
337   AddBlankTabAndShow(browser);
338   return browser;
339 }
340 
AddBlankTabAndShow(Browser * browser)341 void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) {
342   content::WindowedNotificationObserver observer(
343       content::NOTIFICATION_LOAD_STOP,
344       content::NotificationService::AllSources());
345   chrome::AddSelectedTabWithURL(browser,
346                                 GURL(url::kAboutBlankURL),
347                                 content::PAGE_TRANSITION_AUTO_TOPLEVEL);
348   observer.Wait();
349 
350   browser->window()->Show();
351 }
352 
353 #if !defined(OS_MACOSX)
GetCommandLineForRelaunch()354 CommandLine InProcessBrowserTest::GetCommandLineForRelaunch() {
355   CommandLine new_command_line(CommandLine::ForCurrentProcess()->GetProgram());
356   CommandLine::SwitchMap switches =
357       CommandLine::ForCurrentProcess()->GetSwitches();
358   switches.erase(switches::kUserDataDir);
359   switches.erase(content::kSingleProcessTestsFlag);
360   switches.erase(switches::kSingleProcess);
361   new_command_line.AppendSwitch(content::kLaunchAsBrowser);
362 
363   base::FilePath user_data_dir;
364   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
365   new_command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
366 
367   for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
368         iter != switches.end(); ++iter) {
369     new_command_line.AppendSwitchNative((*iter).first, (*iter).second);
370   }
371   return new_command_line;
372 }
373 #endif
374 
RunTestOnMainThreadLoop()375 void InProcessBrowserTest::RunTestOnMainThreadLoop() {
376   // Pump startup related events.
377   content::RunAllPendingInMessageLoop();
378 
379   chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
380   // Self-adds/removes itself from the BrowserList observers.
381   scoped_ptr<SingleDesktopTestObserver> single_desktop_test_observer;
382   if (!multi_desktop_test_) {
383     single_desktop_test_observer.reset(
384         new SingleDesktopTestObserver(active_desktop));
385   }
386 
387   const BrowserList* active_browser_list =
388       BrowserList::GetInstance(active_desktop);
389   if (!active_browser_list->empty()) {
390     browser_ = active_browser_list->get(0);
391 #if defined(USE_ASH)
392     // There are cases where windows get created maximized by default.
393     if (browser_->window()->IsMaximized())
394       browser_->window()->Restore();
395 #endif
396     content::WaitForLoadStop(
397         browser_->tab_strip_model()->GetActiveWebContents());
398   }
399 
400 #if !defined(OS_ANDROID) && !defined(OS_IOS)
401   // Do not use the real StorageMonitor for tests, which introduces another
402   // source of variability and potential slowness.
403   ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateForBrowserTests());
404 #endif
405 
406 #if defined(OS_MACOSX)
407   // On Mac, without the following autorelease pool, code which is directly
408   // executed (as opposed to executed inside a message loop) would autorelease
409   // objects into a higher-level pool. This pool is not recycled in-sync with
410   // the message loops' pools and causes problems with code relying on
411   // deallocation via an autorelease pool (such as browser window closure and
412   // browser shutdown). To avoid this, the following pool is recycled after each
413   // time code is directly executed.
414   autorelease_pool_ = new base::mac::ScopedNSAutoreleasePool;
415 #endif
416 
417   // Pump any pending events that were created as a result of creating a
418   // browser.
419   content::RunAllPendingInMessageLoop();
420 
421   SetUpOnMainThread();
422 #if defined(OS_MACOSX)
423   autorelease_pool_->Recycle();
424 #endif
425 
426   if (!HasFatalFailure())
427     RunTestOnMainThread();
428 #if defined(OS_MACOSX)
429   autorelease_pool_->Recycle();
430 #endif
431 
432   // Invoke cleanup and quit even if there are failures. This is similar to
433   // gtest in that it invokes TearDown even if Setup fails.
434   CleanUpOnMainThread();
435 #if defined(OS_MACOSX)
436   autorelease_pool_->Recycle();
437 #endif
438 
439   // Sometimes tests leave Quit tasks in the MessageLoop (for shame), so let's
440   // run all pending messages here to avoid preempting the QuitBrowsers tasks.
441   // TODO(jbates) Once crbug.com/134753 is fixed, this can be removed because it
442   // will not be possible to post Quit tasks.
443   content::RunAllPendingInMessageLoop();
444 
445   QuitBrowsers();
446   // All BrowserLists should be empty at this point.
447   for (chrome::HostDesktopType t = chrome::HOST_DESKTOP_TYPE_FIRST;
448        t < chrome::HOST_DESKTOP_TYPE_COUNT;
449        t = static_cast<chrome::HostDesktopType>(t + 1)) {
450     CHECK(BrowserList::GetInstance(t)->empty()) << t;
451   }
452 }
453 
QuitBrowsers()454 void InProcessBrowserTest::QuitBrowsers() {
455   if (chrome::GetTotalBrowserCount() == 0) {
456     chrome::NotifyAppTerminating();
457     return;
458   }
459 
460   // Invoke AttemptExit on a running message loop.
461   // AttemptExit exits the message loop after everything has been
462   // shut down properly.
463   base::MessageLoopForUI::current()->PostTask(FROM_HERE,
464                                               base::Bind(&chrome::AttemptExit));
465   content::RunMessageLoop();
466 
467 #if defined(OS_MACOSX)
468   // chrome::AttemptExit() will attempt to close all browsers by deleting
469   // their tab contents. The last tab contents being removed triggers closing of
470   // the browser window.
471   //
472   // On the Mac, this eventually reaches
473   // -[BrowserWindowController windowWillClose:], which will post a deferred
474   // -autorelease on itself to ultimately destroy the Browser object. The line
475   // below is necessary to pump these pending messages to ensure all Browsers
476   // get deleted.
477   content::RunAllPendingInMessageLoop();
478   delete autorelease_pool_;
479   autorelease_pool_ = NULL;
480 #endif
481 }
482