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