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 "base/file_path.h" 6#include "chrome/browser/defaults.h" 7#include "chrome/browser/profiles/profile.h" 8#include "chrome/browser/sessions/tab_restore_service.h" 9#include "chrome/browser/tabs/tab_strip_model.h" 10#include "chrome/browser/ui/browser.h" 11#include "chrome/browser/ui/browser_list.h" 12#include "chrome/browser/ui/browser_window.h" 13#include "chrome/test/in_process_browser_test.h" 14#include "chrome/test/ui_test_utils.h" 15#include "content/browser/tab_contents/tab_contents.h" 16#include "content/common/page_transition_types.h" 17 18namespace { 19 20// BrowserList::Observer implementation that waits for a browser to be 21// removed. 22class BrowserListObserverImpl : public BrowserList::Observer { 23 public: 24 BrowserListObserverImpl() : did_remove_(false), running_(false) { 25 BrowserList::AddObserver(this); 26 } 27 28 ~BrowserListObserverImpl() { 29 BrowserList::RemoveObserver(this); 30 } 31 32 // Returns when a browser has been removed. 33 void Run() { 34 running_ = true; 35 if (!did_remove_) 36 ui_test_utils::RunMessageLoop(); 37 } 38 39 // BrowserList::Observer 40 virtual void OnBrowserAdded(const Browser* browser) OVERRIDE { 41 } 42 virtual void OnBrowserRemoved(const Browser* browser) OVERRIDE { 43 did_remove_ = true; 44 if (running_) 45 MessageLoop::current()->Quit(); 46 } 47 48 private: 49 // Was OnBrowserRemoved invoked? 50 bool did_remove_; 51 52 // Was Run invoked? 53 bool running_; 54 55 DISALLOW_COPY_AND_ASSIGN(BrowserListObserverImpl); 56}; 57 58} // namespace 59 60typedef InProcessBrowserTest SessionRestoreTest; 61 62#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS) 63// Crashes on Linux Views: http://crbug.com/39476 64#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \ 65 DISABLED_RestoreOnNewWindowWithNoTabbedBrowsers 66#else 67#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \ 68 RestoreOnNewWindowWithNoTabbedBrowsers 69#endif 70 71// Makes sure when session restore is triggered in the same process we don't end 72// up with an extra tab. 73IN_PROC_BROWSER_TEST_F(SessionRestoreTest, 74 MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers) { 75 if (browser_defaults::kRestorePopups) 76 return; 77 78 const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html"); 79 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 80 FilePath(kTitle1File))); 81 ui_test_utils::NavigateToURL(browser(), url); 82 83 // Turn on session restore. 84 SessionStartupPref::SetStartupPref( 85 browser()->profile(), 86 SessionStartupPref(SessionStartupPref::LAST)); 87 88 // Create a new popup. 89 Profile* profile = browser()->profile(); 90 Browser* popup = Browser::CreateForType(Browser::TYPE_POPUP, profile); 91 popup->window()->Show(); 92 93 // Close the browser. 94 browser()->window()->Close(); 95 96 // Create a new window, which should trigger session restore. 97 popup->NewWindow(); 98 99 Browser* new_browser = ui_test_utils::WaitForNewBrowser(); 100 101 ASSERT_TRUE(new_browser != NULL); 102 103 // The browser should only have one tab. 104 ASSERT_EQ(1, new_browser->tab_count()); 105 106 // And the first url should be url. 107 EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL()); 108} 109 110IN_PROC_BROWSER_TEST_F(SessionRestoreTest, RestoreIndividualTabFromWindow) { 111 GURL url1(ui_test_utils::GetTestUrl( 112 FilePath(FilePath::kCurrentDirectory), 113 FilePath(FILE_PATH_LITERAL("title1.html")))); 114 GURL url2(ui_test_utils::GetTestUrl( 115 FilePath(FilePath::kCurrentDirectory), 116 FilePath(FILE_PATH_LITERAL("title2.html")))); 117 GURL url3(ui_test_utils::GetTestUrl( 118 FilePath(FilePath::kCurrentDirectory), 119 FilePath(FILE_PATH_LITERAL("title3.html")))); 120 121 // Add and navigate three tabs. 122 ui_test_utils::NavigateToURL(browser(), url1); 123 browser()->AddSelectedTabWithURL(url2, PageTransition::LINK); 124 ui_test_utils::WaitForNavigationInCurrentTab(browser()); 125 126 browser()->AddSelectedTabWithURL(url3, PageTransition::LINK); 127 ui_test_utils::WaitForNavigationInCurrentTab(browser()); 128 129 TabRestoreService* service = browser()->profile()->GetTabRestoreService(); 130 service->ClearEntries(); 131 132 browser()->window()->Close(); 133 134 // Expect a window with three tabs. 135 EXPECT_EQ(1U, service->entries().size()); 136 ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type); 137 const TabRestoreService::Window* window = 138 static_cast<TabRestoreService::Window*>(service->entries().front()); 139 EXPECT_EQ(3U, window->tabs.size()); 140 141 // Find the SessionID for entry2. Since the session service was destroyed, 142 // there is no guarantee that the SessionID for the tab has remained the same. 143 std::vector<TabRestoreService::Tab>::const_iterator it = window->tabs.begin(); 144 for ( ; it != window->tabs.end(); ++it) { 145 const TabRestoreService::Tab& tab = *it; 146 // If this tab held url2, then restore this single tab. 147 if (tab.navigations[0].virtual_url() == url2) { 148 service->RestoreEntryById(NULL, tab.id, false); 149 break; 150 } 151 } 152 153 // Make sure that the Window got updated. 154 EXPECT_EQ(1U, service->entries().size()); 155 ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type); 156 window = static_cast<TabRestoreService::Window*>(service->entries().front()); 157 EXPECT_EQ(2U, window->tabs.size()); 158} 159 160IN_PROC_BROWSER_TEST_F(SessionRestoreTest, WindowWithOneTab) { 161 GURL url(ui_test_utils::GetTestUrl( 162 FilePath(FilePath::kCurrentDirectory), 163 FilePath(FILE_PATH_LITERAL("title1.html")))); 164 165 // Add a single tab. 166 ui_test_utils::NavigateToURL(browser(), url); 167 168 TabRestoreService* service = browser()->profile()->GetTabRestoreService(); 169 service->ClearEntries(); 170 EXPECT_EQ(0U, service->entries().size()); 171 172 // Close the window. 173 browser()->window()->Close(); 174 175 // Expect the window to be converted to a tab by the TRS. 176 EXPECT_EQ(1U, service->entries().size()); 177 ASSERT_EQ(TabRestoreService::TAB, service->entries().front()->type); 178 const TabRestoreService::Tab* tab = 179 static_cast<TabRestoreService::Tab*>(service->entries().front()); 180 181 // Restore the tab. 182 service->RestoreEntryById(NULL, tab->id, false); 183 184 // Make sure the restore was successful. 185 EXPECT_EQ(0U, service->entries().size()); 186} 187 188// Verifies we remember the last browser window when closing the last 189// non-incognito window while an incognito window is open. 190IN_PROC_BROWSER_TEST_F(SessionRestoreTest, IncognitotoNonIncognito) { 191 // Turn on session restore. 192 SessionStartupPref pref(SessionStartupPref::LAST); 193 SessionStartupPref::SetStartupPref(browser()->profile(), pref); 194 195 GURL url(ui_test_utils::GetTestUrl( 196 FilePath(FilePath::kCurrentDirectory), 197 FilePath(FILE_PATH_LITERAL("title1.html")))); 198 199 // Add a single tab. 200 ui_test_utils::NavigateToURL(browser(), url); 201 202 // Create a new incognito window. 203 Browser* incognito_browser = CreateIncognitoBrowser(); 204 incognito_browser->AddBlankTab(true); 205 incognito_browser->window()->Show(); 206 207 // Close the normal browser. After this we only have the incognito window 208 // open. We wait until the window closes as window closing is async. 209 { 210 BrowserListObserverImpl observer; 211 browser()->window()->Close(); 212 observer.Run(); 213 } 214 215 // Create a new window, which should trigger session restore. 216 incognito_browser->NewWindow(); 217 218 // The first tab should have 'url' as its url. 219 Browser* new_browser = ui_test_utils::WaitForNewBrowser(); 220 ASSERT_TRUE(new_browser); 221 EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL()); 222} 223