Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2011 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 <string>
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/file_path.h"
      9 #include "base/sys_info.h"
     10 #include "base/utf_string_conversions.h"
     11 #include "chrome/app/chrome_command_ids.h"
     12 #include "chrome/browser/defaults.h"
     13 #include "chrome/browser/extensions/extension_browsertest.h"
     14 #include "chrome/browser/extensions/extension_service.h"
     15 #include "chrome/browser/extensions/extension_tab_helper.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/tabs/pinned_tab_codec.h"
     18 #include "chrome/browser/tabs/tab_strip_model.h"
     19 #include "chrome/browser/translate/translate_tab_helper.h"
     20 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
     21 #include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
     22 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_init.h"
     25 #include "chrome/browser/ui/browser_list.h"
     26 #include "chrome/browser/ui/browser_navigator.h"
     27 #include "chrome/browser/ui/browser_window.h"
     28 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     29 #include "chrome/common/chrome_switches.h"
     30 #include "chrome/common/extensions/extension.h"
     31 #include "chrome/common/url_constants.h"
     32 #include "chrome/test/in_process_browser_test.h"
     33 #include "chrome/test/ui_test_utils.h"
     34 #include "content/browser/renderer_host/render_process_host.h"
     35 #include "content/browser/renderer_host/render_view_host.h"
     36 #include "content/browser/tab_contents/tab_contents.h"
     37 #include "content/common/notification_source.h"
     38 #include "content/common/page_transition_types.h"
     39 #include "grit/chromium_strings.h"
     40 #include "grit/generated_resources.h"
     41 #include "net/base/mock_host_resolver.h"
     42 #include "net/test/test_server.h"
     43 #include "ui/base/l10n/l10n_util.h"
     44 
     45 #if defined(OS_WIN)
     46 #include "base/i18n/rtl.h"
     47 #include "chrome/browser/browser_process.h"
     48 #endif
     49 
     50 namespace {
     51 
     52 const char* kBeforeUnloadHTML =
     53     "<html><head><title>beforeunload</title></head><body>"
     54     "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
     55     "</body></html>";
     56 
     57 const char* kOpenNewBeforeUnloadPage =
     58     "w=window.open(); w.onbeforeunload=function(e){return 'foo'};";
     59 
     60 const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
     61 const FilePath::CharType* kTitle2File = FILE_PATH_LITERAL("title2.html");
     62 
     63 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
     64 
     65 // Given a page title, returns the expected window caption string.
     66 std::wstring WindowCaptionFromPageTitle(std::wstring page_title) {
     67 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
     68   // On Mac or ChromeOS, we don't want to suffix the page title with
     69   // the application name.
     70   if (page_title.empty()) {
     71     return UTF16ToWideHack(
     72         l10n_util::GetStringUTF16(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED));
     73   }
     74   return page_title;
     75 #else
     76   if (page_title.empty())
     77     return UTF16ToWideHack(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
     78 
     79   return UTF16ToWideHack(
     80       l10n_util::GetStringFUTF16(IDS_BROWSER_WINDOW_TITLE_FORMAT,
     81                                  WideToUTF16Hack(page_title)));
     82 #endif
     83 }
     84 
     85 // Returns the number of active RenderProcessHosts.
     86 int CountRenderProcessHosts() {
     87   int result = 0;
     88   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
     89        !i.IsAtEnd(); i.Advance())
     90     ++result;
     91   return result;
     92 }
     93 
     94 class MockTabStripModelObserver : public TabStripModelObserver {
     95  public:
     96   MockTabStripModelObserver() : closing_count_(0) {}
     97 
     98   virtual void TabClosingAt(TabStripModel* tab_strip_model,
     99                             TabContentsWrapper* contents,
    100                             int index) {
    101     closing_count_++;
    102   }
    103 
    104   int closing_count() const { return closing_count_; }
    105 
    106  private:
    107   int closing_count_;
    108 
    109   DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver);
    110 };
    111 
    112 // Used by CloseWithAppMenuOpen. Invokes CloseWindow on the supplied browser.
    113 class CloseWindowTask : public Task {
    114  public:
    115   explicit CloseWindowTask(Browser* browser) : browser_(browser) {}
    116 
    117   virtual void Run() {
    118     browser_->CloseWindow();
    119   }
    120 
    121  private:
    122   Browser* browser_;
    123 
    124   DISALLOW_COPY_AND_ASSIGN(CloseWindowTask);
    125 };
    126 
    127 // Used by CloseWithAppMenuOpen. Posts a CloseWindowTask and shows the app menu.
    128 class RunCloseWithAppMenuTask : public Task {
    129  public:
    130   explicit RunCloseWithAppMenuTask(Browser* browser) : browser_(browser) {}
    131 
    132   virtual void Run() {
    133     // ShowAppMenu is modal under views. Schedule a task that closes the window.
    134     MessageLoop::current()->PostTask(FROM_HERE, new CloseWindowTask(browser_));
    135     browser_->ShowAppMenu();
    136   }
    137 
    138  private:
    139   Browser* browser_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(RunCloseWithAppMenuTask);
    142 };
    143 
    144 }  // namespace
    145 
    146 class BrowserTest : public ExtensionBrowserTest {
    147  protected:
    148   // In RTL locales wrap the page title with RTL embedding characters so that it
    149   // matches the value returned by GetWindowTitle().
    150   std::wstring LocaleWindowCaptionFromPageTitle(
    151       const std::wstring& expected_title) {
    152     std::wstring page_title = WindowCaptionFromPageTitle(expected_title);
    153 #if defined(OS_WIN)
    154     std::string locale = g_browser_process->GetApplicationLocale();
    155     if (base::i18n::GetTextDirectionForLocale(locale.c_str()) ==
    156         base::i18n::RIGHT_TO_LEFT) {
    157       base::i18n::WrapStringWithLTRFormatting(&page_title);
    158     }
    159 
    160     return page_title;
    161 #else
    162     // Do we need to use the above code on POSIX as well?
    163     return page_title;
    164 #endif
    165   }
    166 
    167   // Returns the app extension aptly named "App Test".
    168   const Extension* GetExtension() {
    169     const ExtensionList* extensions =
    170         browser()->profile()->GetExtensionService()->extensions();
    171     for (size_t i = 0; i < extensions->size(); ++i) {
    172       if ((*extensions)[i]->name() == "App Test")
    173         return (*extensions)[i];
    174     }
    175     NOTREACHED();
    176     return NULL;
    177   }
    178 };
    179 
    180 // Launch the app on a page with no title, check that the app title was set
    181 // correctly.
    182 IN_PROC_BROWSER_TEST_F(BrowserTest, NoTitle) {
    183   ui_test_utils::NavigateToURL(browser(),
    184       ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    185                                 FilePath(kTitle1File)));
    186   EXPECT_EQ(LocaleWindowCaptionFromPageTitle(L"title1.html"),
    187             UTF16ToWideHack(browser()->GetWindowTitleForCurrentTab()));
    188   string16 tab_title;
    189   ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title));
    190   EXPECT_EQ(ASCIIToUTF16("title1.html"), tab_title);
    191 }
    192 
    193 // Launch the app, navigate to a page with a title, check that the app title
    194 // was set correctly.
    195 IN_PROC_BROWSER_TEST_F(BrowserTest, Title) {
    196   ui_test_utils::NavigateToURL(browser(),
    197       ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    198                                 FilePath(kTitle2File)));
    199   const std::wstring test_title(L"Title Of Awesomeness");
    200   EXPECT_EQ(LocaleWindowCaptionFromPageTitle(test_title),
    201             UTF16ToWideHack(browser()->GetWindowTitleForCurrentTab()));
    202   string16 tab_title;
    203   ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title));
    204   EXPECT_EQ(WideToUTF16(test_title), tab_title);
    205 }
    206 
    207 IN_PROC_BROWSER_TEST_F(BrowserTest, JavascriptAlertActivatesTab) {
    208   GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    209                                      FilePath(kTitle1File)));
    210   ui_test_utils::NavigateToURL(browser(), url);
    211   AddTabAtIndex(0, url, PageTransition::TYPED);
    212   EXPECT_EQ(2, browser()->tab_count());
    213   EXPECT_EQ(0, browser()->active_index());
    214   TabContents* second_tab = browser()->GetTabContentsAt(1);
    215   ASSERT_TRUE(second_tab);
    216   second_tab->render_view_host()->ExecuteJavascriptInWebFrame(
    217       string16(),
    218       ASCIIToUTF16("alert('Activate!');"));
    219   AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog();
    220   alert->CloseModalDialog();
    221   EXPECT_EQ(2, browser()->tab_count());
    222   EXPECT_EQ(1, browser()->active_index());
    223 }
    224 
    225 
    226 
    227 #if defined(OS_WIN)
    228 // http://crbug.com/75274. On XP crashes inside
    229 // URLFetcher::Core::Registry::RemoveURLFetcherCore.
    230 #define MAYBE_ThirtyFourTabs FLAKY_ThirtyFourTabs
    231 #else
    232 #define MAYBE_ThirtyFourTabs ThirtyFourTabs
    233 #endif
    234 
    235 // Create 34 tabs and verify that a lot of processes have been created. The
    236 // exact number of processes depends on the amount of memory. Previously we
    237 // had a hard limit of 31 processes and this test is mainly directed at
    238 // verifying that we don't crash when we pass this limit.
    239 // Warning: this test can take >30 seconds when running on a slow (low
    240 // memory?) Mac builder.
    241 IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_ThirtyFourTabs) {
    242   GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    243                                      FilePath(kTitle2File)));
    244 
    245   // There is one initial tab.
    246   for (int ix = 0; ix != 33; ++ix)
    247     browser()->AddSelectedTabWithURL(url, PageTransition::TYPED);
    248   EXPECT_EQ(34, browser()->tab_count());
    249 
    250   // See browser\renderer_host\render_process_host.cc for the algorithm to
    251   // decide how many processes to create.
    252   if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) {
    253     EXPECT_GE(CountRenderProcessHosts(), 24);
    254   } else {
    255     EXPECT_LE(CountRenderProcessHosts(), 23);
    256   }
    257 }
    258 
    259 // Test for crbug.com/22004.  Reloading a page with a before unload handler and
    260 // then canceling the dialog should not leave the throbber spinning.
    261 IN_PROC_BROWSER_TEST_F(BrowserTest, ReloadThenCancelBeforeUnload) {
    262   GURL url(std::string("data:text/html,") + kBeforeUnloadHTML);
    263   ui_test_utils::NavigateToURL(browser(), url);
    264 
    265   // Navigate to another page, but click cancel in the dialog.  Make sure that
    266   // the throbber stops spinning.
    267   browser()->Reload(CURRENT_TAB);
    268   AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog();
    269   alert->CloseModalDialog();
    270   EXPECT_FALSE(browser()->GetSelectedTabContents()->is_loading());
    271 
    272   // Clear the beforeunload handler so the test can easily exit.
    273   browser()->GetSelectedTabContents()->render_view_host()->
    274       ExecuteJavascriptInWebFrame(string16(),
    275                                   ASCIIToUTF16("onbeforeunload=null;"));
    276 }
    277 
    278 // Crashy on mac.  http://crbug.com/38522
    279 #if defined(OS_MACOSX)
    280 #define MAYBE_SingleBeforeUnloadAfterWindowClose \
    281         DISABLED_SingleBeforeUnloadAfterWindowClose
    282 #else
    283 #define MAYBE_SingleBeforeUnloadAfterWindowClose \
    284         SingleBeforeUnloadAfterWindowClose
    285 #endif
    286 
    287 // Test for crbug.com/11647.  A page closed with window.close() should not have
    288 // two beforeunload dialogs shown.
    289 IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_SingleBeforeUnloadAfterWindowClose) {
    290   browser()->GetSelectedTabContents()->render_view_host()->
    291       ExecuteJavascriptInWebFrame(string16(),
    292                                   ASCIIToUTF16(kOpenNewBeforeUnloadPage));
    293 
    294   // Close the new window with JavaScript, which should show a single
    295   // beforeunload dialog.  Then show another alert, to make it easy to verify
    296   // that a second beforeunload dialog isn't shown.
    297   browser()->GetTabContentsAt(0)->render_view_host()->
    298       ExecuteJavascriptInWebFrame(string16(),
    299                                   ASCIIToUTF16("w.close(); alert('bar');"));
    300   AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog();
    301   alert->native_dialog()->AcceptAppModalDialog();
    302 
    303   alert = ui_test_utils::WaitForAppModalDialog();
    304   EXPECT_FALSE(static_cast<JavaScriptAppModalDialog*>(alert)->
    305                    is_before_unload_dialog());
    306   alert->native_dialog()->AcceptAppModalDialog();
    307 }
    308 
    309 // Test that get_process_idle_time() returns reasonable values when compared
    310 // with time deltas measured locally.
    311 IN_PROC_BROWSER_TEST_F(BrowserTest, RenderIdleTime) {
    312   base::TimeTicks start = base::TimeTicks::Now();
    313   ui_test_utils::NavigateToURL(browser(),
    314       ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    315                                 FilePath(kTitle1File)));
    316   RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
    317   for (; !it.IsAtEnd(); it.Advance()) {
    318     base::TimeDelta renderer_td =
    319         it.GetCurrentValue()->get_child_process_idle_time();
    320     base::TimeDelta browser_td = base::TimeTicks::Now() - start;
    321     EXPECT_TRUE(browser_td >= renderer_td);
    322   }
    323 }
    324 
    325 // Test IDC_CREATE_SHORTCUTS command is enabled for url scheme file, ftp, http
    326 // and https and disabled for chrome://, about:// etc.
    327 // TODO(pinkerton): Disable app-mode in the model until we implement it
    328 // on the Mac. http://crbug.com/13148
    329 #if !defined(OS_MACOSX)
    330 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFile) {
    331   CommandUpdater* command_updater = browser()->command_updater();
    332 
    333   static const FilePath::CharType* kEmptyFile = FILE_PATH_LITERAL("empty.html");
    334   GURL file_url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    335                                           FilePath(kEmptyFile)));
    336   ASSERT_TRUE(file_url.SchemeIs(chrome::kFileScheme));
    337   ui_test_utils::NavigateToURL(browser(), file_url);
    338   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    339 }
    340 
    341 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttp) {
    342   CommandUpdater* command_updater = browser()->command_updater();
    343 
    344   ASSERT_TRUE(test_server()->Start());
    345   GURL http_url(test_server()->GetURL(""));
    346   ASSERT_TRUE(http_url.SchemeIs(chrome::kHttpScheme));
    347   ui_test_utils::NavigateToURL(browser(), http_url);
    348   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    349 }
    350 
    351 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttps) {
    352   CommandUpdater* command_updater = browser()->command_updater();
    353 
    354   net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath(kDocRoot));
    355   ASSERT_TRUE(test_server.Start());
    356   GURL https_url(test_server.GetURL("/"));
    357   ASSERT_TRUE(https_url.SchemeIs(chrome::kHttpsScheme));
    358   ui_test_utils::NavigateToURL(browser(), https_url);
    359   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    360 }
    361 
    362 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFtp) {
    363   CommandUpdater* command_updater = browser()->command_updater();
    364 
    365   net::TestServer test_server(net::TestServer::TYPE_FTP, FilePath(kDocRoot));
    366   ASSERT_TRUE(test_server.Start());
    367   GURL ftp_url(test_server.GetURL(""));
    368   ASSERT_TRUE(ftp_url.SchemeIs(chrome::kFtpScheme));
    369   ui_test_utils::NavigateToURL(browser(), ftp_url);
    370   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    371 }
    372 
    373 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutInvalid) {
    374   CommandUpdater* command_updater = browser()->command_updater();
    375 
    376   // Urls that should not have shortcuts.
    377   GURL new_tab_url(chrome::kChromeUINewTabURL);
    378   ui_test_utils::NavigateToURL(browser(), new_tab_url);
    379   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    380 
    381   GURL history_url(chrome::kChromeUIHistoryURL);
    382   ui_test_utils::NavigateToURL(browser(), history_url);
    383   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    384 
    385   GURL downloads_url(chrome::kChromeUIDownloadsURL);
    386   ui_test_utils::NavigateToURL(browser(), downloads_url);
    387   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    388 
    389   GURL blank_url(chrome::kAboutBlankURL);
    390   ui_test_utils::NavigateToURL(browser(), blank_url);
    391   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
    392 }
    393 
    394 // Change a tab into an application window.
    395 // DISABLED: http://crbug.com/72310
    396 IN_PROC_BROWSER_TEST_F(BrowserTest, DISABLED_ConvertTabToAppShortcut) {
    397   ASSERT_TRUE(test_server()->Start());
    398   GURL http_url(test_server()->GetURL(""));
    399   ASSERT_TRUE(http_url.SchemeIs(chrome::kHttpScheme));
    400 
    401   ASSERT_EQ(1, browser()->tab_count());
    402   TabContents* initial_tab = browser()->GetTabContentsAt(0);
    403   TabContents* app_tab = browser()->AddSelectedTabWithURL(
    404       http_url, PageTransition::TYPED)->tab_contents();
    405   ASSERT_EQ(2, browser()->tab_count());
    406   ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
    407 
    408   // Normal tabs should accept load drops.
    409   EXPECT_TRUE(initial_tab->GetMutableRendererPrefs()->can_accept_load_drops);
    410   EXPECT_TRUE(app_tab->GetMutableRendererPrefs()->can_accept_load_drops);
    411 
    412   // Turn |app_tab| into a tab in an app panel.
    413   browser()->ConvertContentsToApplication(app_tab);
    414 
    415   // The launch should have created a new browser.
    416   ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile()));
    417 
    418   // Find the new browser.
    419   Browser* app_browser = NULL;
    420   for (BrowserList::const_iterator i = BrowserList::begin();
    421        i != BrowserList::end() && !app_browser; ++i) {
    422     if (*i != browser())
    423       app_browser = *i;
    424   }
    425   ASSERT_TRUE(app_browser);
    426 
    427   // Check that the tab contents is in the new browser, and not in the old.
    428   ASSERT_EQ(1, browser()->tab_count());
    429   ASSERT_EQ(initial_tab, browser()->GetTabContentsAt(0));
    430 
    431   // Check that the appliaction browser has a single tab, and that tab contains
    432   // the content that we app-ified.
    433   ASSERT_EQ(1, app_browser->tab_count());
    434   ASSERT_EQ(app_tab, app_browser->GetTabContentsAt(0));
    435 
    436   // Normal tabs should accept load drops.
    437   EXPECT_TRUE(initial_tab->GetMutableRendererPrefs()->can_accept_load_drops);
    438 
    439   // The tab in an app window should not.
    440   EXPECT_FALSE(app_tab->GetMutableRendererPrefs()->can_accept_load_drops);
    441 }
    442 
    443 #endif  // !defined(OS_MACOSX)
    444 
    445 // Test RenderView correctly send back favicon url for web page that redirects
    446 // to an anchor in javascript body.onload handler.
    447 IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconOfOnloadRedirectToAnchorPage) {
    448   ASSERT_TRUE(test_server()->Start());
    449   GURL url(test_server()->GetURL("files/onload_redirect_to_anchor.html"));
    450   GURL expected_favicon_url(test_server()->GetURL("files/test.png"));
    451 
    452   ui_test_utils::NavigateToURL(browser(), url);
    453 
    454   NavigationEntry* entry = browser()->GetSelectedTabContents()->
    455       controller().GetActiveEntry();
    456   EXPECT_EQ(expected_favicon_url.spec(), entry->favicon().url().spec());
    457 }
    458 
    459 // Test that an icon can be changed from JS.
    460 IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconChange) {
    461   static const FilePath::CharType* kFile =
    462       FILE_PATH_LITERAL("onload_change_favicon.html");
    463   GURL file_url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    464                                           FilePath(kFile)));
    465   ASSERT_TRUE(file_url.SchemeIs(chrome::kFileScheme));
    466   ui_test_utils::NavigateToURL(browser(), file_url);
    467 
    468   NavigationEntry* entry = browser()->GetSelectedTabContents()->
    469       controller().GetActiveEntry();
    470   static const FilePath::CharType* kIcon =
    471       FILE_PATH_LITERAL("test1.png");
    472   GURL expected_favicon_url(
    473       ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
    474                                          FilePath(kIcon)));
    475   EXPECT_EQ(expected_favicon_url.spec(), entry->favicon().url().spec());
    476 }
    477 
    478 // Makes sure TabClosing is sent when uninstalling an extension that is an app
    479 // tab.
    480 IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) {
    481   ASSERT_TRUE(test_server()->Start());
    482   host_resolver()->AddRule("www.example.com", "127.0.0.1");
    483   GURL url(test_server()->GetURL("empty.html"));
    484   TabStripModel* model = browser()->tabstrip_model();
    485 
    486   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
    487 
    488   const Extension* extension_app = GetExtension();
    489 
    490   ui_test_utils::NavigateToURL(browser(), url);
    491 
    492   TabContentsWrapper* app_contents =
    493       Browser::TabContentsFactory(browser()->profile(), NULL,
    494                                   MSG_ROUTING_NONE, NULL, NULL);
    495   app_contents->extension_tab_helper()->SetExtensionApp(extension_app);
    496 
    497   model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE);
    498   model->SetTabPinned(0, true);
    499   ui_test_utils::NavigateToURL(browser(), url);
    500 
    501   MockTabStripModelObserver observer;
    502   model->AddObserver(&observer);
    503 
    504   // Uninstall the extension and make sure TabClosing is sent.
    505   ExtensionService* service = browser()->profile()->GetExtensionService();
    506   service->UninstallExtension(GetExtension()->id(), false, NULL);
    507   EXPECT_EQ(1, observer.closing_count());
    508 
    509   model->RemoveObserver(&observer);
    510 
    511   // There should only be one tab now.
    512   ASSERT_EQ(1, browser()->tab_count());
    513 }
    514 
    515 #if !defined(OS_MACOSX)
    516 // Open with --app-id=<id>, and see that an app window opens.
    517 IN_PROC_BROWSER_TEST_F(BrowserTest, AppIdSwitch) {
    518   ASSERT_TRUE(test_server()->Start());
    519 
    520   // Load an app.
    521   host_resolver()->AddRule("www.example.com", "127.0.0.1");
    522   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
    523   const Extension* extension_app = GetExtension();
    524 
    525   CommandLine command_line(CommandLine::NO_PROGRAM);
    526   command_line.AppendSwitchASCII(switches::kAppId, extension_app->id());
    527 
    528   BrowserInit::LaunchWithProfile launch(FilePath(), command_line);
    529   ASSERT_TRUE(launch.OpenApplicationWindow(browser()->profile()));
    530 
    531   // Check that the new browser has an app name.
    532   // The launch should have created a new browser.
    533   ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile()));
    534 
    535   // Find the new browser.
    536   Browser* new_browser = NULL;
    537   for (BrowserList::const_iterator i = BrowserList::begin();
    538        i != BrowserList::end() && !new_browser; ++i) {
    539     if (*i != browser())
    540       new_browser = *i;
    541   }
    542   ASSERT_TRUE(new_browser);
    543   ASSERT_TRUE(new_browser != browser());
    544 
    545   // The browser's app_name should include the app's ID.
    546   ASSERT_NE(
    547       new_browser->app_name_.find(extension_app->id()),
    548       std::string::npos) << new_browser->app_name_;
    549 
    550 }
    551 #endif
    552 
    553 #if defined(OS_WIN)
    554 // http://crbug.com/46198. On XP/Vista, the failure rate is 5 ~ 6%.
    555 #define MAYBE_PageLanguageDetection FLAKY_PageLanguageDetection
    556 #else
    557 #define MAYBE_PageLanguageDetection PageLanguageDetection
    558 #endif
    559 // Tests that the CLD (Compact Language Detection) works properly.
    560 IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) {
    561   ASSERT_TRUE(test_server()->Start());
    562 
    563   TabContents* current_tab = browser()->GetSelectedTabContents();
    564   TabContentsWrapper* wrapper = browser()->GetSelectedTabContentsWrapper();
    565   TranslateTabHelper* helper = wrapper->translate_tab_helper();
    566   Source<TabContents> source(current_tab);
    567 
    568   // Navigate to a page in English.
    569   ui_test_utils::WindowedNotificationObserverWithDetails<std::string>
    570       en_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED,
    571                                   source);
    572   ui_test_utils::NavigateToURL(
    573       browser(), GURL(test_server()->GetURL("files/english_page.html")));
    574   EXPECT_TRUE(helper->language_state().original_language().empty());
    575   en_language_detected_signal.Wait();
    576   std::string lang;
    577   EXPECT_TRUE(en_language_detected_signal.GetDetailsFor(
    578         source.map_key(), &lang));
    579   EXPECT_EQ("en", lang);
    580   EXPECT_EQ("en", helper->language_state().original_language());
    581 
    582   // Now navigate to a page in French.
    583   ui_test_utils::WindowedNotificationObserverWithDetails<std::string>
    584       fr_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED,
    585                                   source);
    586   ui_test_utils::NavigateToURL(
    587       browser(), GURL(test_server()->GetURL("files/french_page.html")));
    588   EXPECT_TRUE(helper->language_state().original_language().empty());
    589   fr_language_detected_signal.Wait();
    590   lang.clear();
    591   EXPECT_TRUE(fr_language_detected_signal.GetDetailsFor(
    592         source.map_key(), &lang));
    593   EXPECT_EQ("fr", lang);
    594   EXPECT_EQ("fr", helper->language_state().original_language());
    595 }
    596 
    597 // Chromeos defaults to restoring the last session, so this test isn't
    598 // applicable.
    599 #if !defined(OS_CHROMEOS)
    600 #if defined(OS_MACOSX)
    601 // Crashy, http://crbug.com/38522
    602 #define RestorePinnedTabs DISABLED_RestorePinnedTabs
    603 #endif
    604 // Makes sure pinned tabs are restored correctly on start.
    605 IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) {
    606   ASSERT_TRUE(test_server()->Start());
    607 
    608   // Add an pinned app tab.
    609   host_resolver()->AddRule("www.example.com", "127.0.0.1");
    610   GURL url(test_server()->GetURL("empty.html"));
    611   TabStripModel* model = browser()->tabstrip_model();
    612   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
    613   const Extension* extension_app = GetExtension();
    614   ui_test_utils::NavigateToURL(browser(), url);
    615   TabContentsWrapper* app_contents =
    616     Browser::TabContentsFactory(browser()->profile(), NULL,
    617                                 MSG_ROUTING_NONE, NULL, NULL);
    618   app_contents->extension_tab_helper()->SetExtensionApp(extension_app);
    619   model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE);
    620   model->SetTabPinned(0, true);
    621   ui_test_utils::NavigateToURL(browser(), url);
    622 
    623   // Add a non pinned tab.
    624   browser()->NewTab();
    625 
    626   // Add a pinned non-app tab.
    627   browser()->NewTab();
    628   ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
    629   model->SetTabPinned(2, true);
    630 
    631   // Write out the pinned tabs.
    632   PinnedTabCodec::WritePinnedTabs(browser()->profile());
    633 
    634   // Simulate launching again.
    635   CommandLine dummy(CommandLine::NO_PROGRAM);
    636   BrowserInit::LaunchWithProfile launch(FilePath(), dummy);
    637   launch.profile_ = browser()->profile();
    638   launch.ProcessStartupURLs(std::vector<GURL>());
    639 
    640   // The launch should have created a new browser.
    641   ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile()));
    642 
    643   // Find the new browser.
    644   Browser* new_browser = NULL;
    645   for (BrowserList::const_iterator i = BrowserList::begin();
    646        i != BrowserList::end() && !new_browser; ++i) {
    647     if (*i != browser())
    648       new_browser = *i;
    649   }
    650   ASSERT_TRUE(new_browser);
    651   ASSERT_TRUE(new_browser != browser());
    652 
    653   // We should get back an additional tab for the app, and another for the
    654   // default home page.
    655   ASSERT_EQ(3, new_browser->tab_count());
    656 
    657   // Make sure the state matches.
    658   TabStripModel* new_model = new_browser->tabstrip_model();
    659   EXPECT_TRUE(new_model->IsAppTab(0));
    660   EXPECT_FALSE(new_model->IsAppTab(1));
    661   EXPECT_FALSE(new_model->IsAppTab(2));
    662 
    663   EXPECT_TRUE(new_model->IsTabPinned(0));
    664   EXPECT_TRUE(new_model->IsTabPinned(1));
    665   EXPECT_FALSE(new_model->IsTabPinned(2));
    666 
    667   EXPECT_EQ(browser()->GetHomePage(),
    668       new_model->GetTabContentsAt(2)->tab_contents()->GetURL());
    669 
    670   EXPECT_TRUE(
    671       new_model->GetTabContentsAt(0)->extension_tab_helper()->extension_app() ==
    672           extension_app);
    673 }
    674 #endif  // !defined(OS_CHROMEOS)
    675 
    676 // This test verifies we don't crash when closing the last window and the app
    677 // menu is showing.
    678 IN_PROC_BROWSER_TEST_F(BrowserTest, CloseWithAppMenuOpen) {
    679   if (browser_defaults::kBrowserAliveWithNoWindows)
    680     return;
    681 
    682   // We need a message loop running for menus on windows.
    683   MessageLoop::current()->PostTask(FROM_HERE,
    684                                    new RunCloseWithAppMenuTask(browser()));
    685 }
    686 
    687 #if !defined(OS_MACOSX)
    688 IN_PROC_BROWSER_TEST_F(BrowserTest, OpenAppWindowLikeNtp) {
    689   ASSERT_TRUE(test_server()->Start());
    690 
    691   // Load an app
    692   host_resolver()->AddRule("www.example.com", "127.0.0.1");
    693   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
    694   const Extension* extension_app = GetExtension();
    695 
    696   // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would.
    697   TabContents* app_window = Browser::OpenApplication(
    698       browser()->profile(), extension_app, extension_misc::LAUNCH_WINDOW, NULL);
    699   ASSERT_TRUE(app_window);
    700 
    701   // Apps launched in a window from the NTP do not have extension_app set in
    702   // tab contents.
    703   TabContentsWrapper* wrapper =
    704           TabContentsWrapper::GetCurrentWrapperForContents(app_window);
    705   EXPECT_FALSE(wrapper->extension_tab_helper()->extension_app());
    706   EXPECT_EQ(extension_app->GetFullLaunchURL(), app_window->GetURL());
    707 
    708   // The launch should have created a new browser.
    709   ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile()));
    710 
    711   // Find the new browser.
    712   Browser* new_browser = NULL;
    713   for (BrowserList::const_iterator i = BrowserList::begin();
    714        i != BrowserList::end() && !new_browser; ++i) {
    715     if (*i != browser())
    716       new_browser = *i;
    717   }
    718   ASSERT_TRUE(new_browser);
    719   ASSERT_TRUE(new_browser != browser());
    720 
    721   EXPECT_EQ(Browser::TYPE_APP, new_browser->type());
    722 
    723   // The browser's app name should include the extension's id.
    724   std::string app_name = new_browser->app_name_;
    725   EXPECT_NE(app_name.find(extension_app->id()), std::string::npos)
    726       << "Name " << app_name << " should contain id "<< extension_app->id();
    727 }
    728 #endif  // !defined(OS_MACOSX)
    729 
    730 // TODO(ben): this test was never enabled. It has bit-rotted since being added.
    731 // It originally lived in browser_unittest.cc, but has been moved here to make
    732 // room for real browser unit tests.
    733 #if 0
    734 class BrowserTest2 : public InProcessBrowserTest {
    735  public:
    736   BrowserTest2() {
    737     host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL);
    738     // Avoid making external DNS lookups. In this test we don't need this
    739     // to succeed.
    740     host_resolver_proc_->AddSimulatedFailure("*.google.com");
    741     scoped_host_resolver_proc_.Init(host_resolver_proc_.get());
    742   }
    743 
    744  private:
    745   scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_;
    746   net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
    747 };
    748 
    749 IN_PROC_BROWSER_TEST_F(BrowserTest2, NoTabsInPopups) {
    750   Browser::RegisterAppPrefs(L"Test");
    751 
    752   // We start with a normal browser with one tab.
    753   EXPECT_EQ(1, browser()->tab_count());
    754 
    755   // Open a popup browser with a single blank foreground tab.
    756   Browser* popup_browser = browser()->CreateForType(Browser::TYPE_POPUP,
    757                                                     browser()->profile());
    758   popup_browser->AddBlankTab(true);
    759   EXPECT_EQ(1, popup_browser->tab_count());
    760 
    761   // Now try opening another tab in the popup browser.
    762   AddTabWithURLParams params1(url, PageTransition::TYPED);
    763   popup_browser->AddTabWithURL(&params1);
    764   EXPECT_EQ(popup_browser, params1.target);
    765 
    766   // The popup should still only have one tab.
    767   EXPECT_EQ(1, popup_browser->tab_count());
    768 
    769   // The normal browser should now have two.
    770   EXPECT_EQ(2, browser()->tab_count());
    771 
    772   // Open an app frame browser with a single blank foreground tab.
    773   Browser* app_browser =
    774       browser()->CreateForApp(L"Test", browser()->profile(), false);
    775   app_browser->AddBlankTab(true);
    776   EXPECT_EQ(1, app_browser->tab_count());
    777 
    778   // Now try opening another tab in the app browser.
    779   AddTabWithURLParams params2(GURL(chrome::kAboutBlankURL),
    780                               PageTransition::TYPED);
    781   app_browser->AddTabWithURL(&params2);
    782   EXPECT_EQ(app_browser, params2.target);
    783 
    784   // The popup should still only have one tab.
    785   EXPECT_EQ(1, app_browser->tab_count());
    786 
    787   // The normal browser should now have three.
    788   EXPECT_EQ(3, browser()->tab_count());
    789 
    790   // Open an app frame popup browser with a single blank foreground tab.
    791   Browser* app_popup_browser =
    792       browser()->CreateForApp(L"Test", browser()->profile(), false);
    793   app_popup_browser->AddBlankTab(true);
    794   EXPECT_EQ(1, app_popup_browser->tab_count());
    795 
    796   // Now try opening another tab in the app popup browser.
    797   AddTabWithURLParams params3(GURL(chrome::kAboutBlankURL),
    798                               PageTransition::TYPED);
    799   app_popup_browser->AddTabWithURL(&params3);
    800   EXPECT_EQ(app_popup_browser, params3.target);
    801 
    802   // The popup should still only have one tab.
    803   EXPECT_EQ(1, app_popup_browser->tab_count());
    804 
    805   // The normal browser should now have four.
    806   EXPECT_EQ(4, browser()->tab_count());
    807 
    808   // Close the additional browsers.
    809   popup_browser->CloseAllTabs();
    810   app_browser->CloseAllTabs();
    811   app_popup_browser->CloseAllTabs();
    812 }
    813 #endif
    814