// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/command_line.h" #include "base/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/string_number_conversions.h" #include "base/test/test_timeouts.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/defaults.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/window_proxy.h" #include "chrome/test/ui/ui_test.h" #include "googleurl/src/gurl.h" #include "net/base/net_util.h" #include "net/test/test_server.h" namespace { class SessionRestoreUITest : public UITest { protected: SessionRestoreUITest() : UITest() { FilePath path_prefix = test_data_directory_.AppendASCII("session_history"); url1_ = net::FilePathToFileURL(path_prefix.AppendASCII("bot1.html")); url2_ = net::FilePathToFileURL(path_prefix.AppendASCII("bot2.html")); url3_ = net::FilePathToFileURL(path_prefix.AppendASCII("bot3.html")); } virtual void QuitBrowserAndRestore(int expected_tab_count) { #if defined(OS_MACOSX) set_shutdown_type(ProxyLauncher::USER_QUIT); #endif UITest::TearDown(); clear_profile_ = false; launch_arguments_.AppendSwitchASCII(switches::kRestoreLastSession, base::IntToString(expected_tab_count)); UITest::SetUp(); } void CloseWindow(int window_index, int initial_count) { scoped_refptr<BrowserProxy> browser_proxy( automation()->GetBrowserWindow(window_index)); ASSERT_TRUE(browser_proxy.get()); ASSERT_TRUE(browser_proxy->RunCommand(IDC_CLOSE_WINDOW)); int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(initial_count - 1, window_count); } void AssertOneWindowWithOneTab() { int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); GURL url; AssertWindowHasOneTab(0, &url); } void AssertWindowHasOneTab(int window_index, GURL* url) { scoped_refptr<BrowserProxy> browser_proxy( automation()->GetBrowserWindow(window_index)); ASSERT_TRUE(browser_proxy.get()); int tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); ASSERT_EQ(1, tab_count); int active_tab_index; ASSERT_TRUE(browser_proxy->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(0, active_tab_index); scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetActiveTab()); ASSERT_TRUE(tab_proxy.get()); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); ASSERT_TRUE(tab_proxy->GetCurrentURL(url)); } GURL url1_; GURL url2_; GURL url3_; private: DISALLOW_COPY_AND_ASSIGN(SessionRestoreUITest); }; TEST_F(SessionRestoreUITest, Basic) { NavigateToURL(url1_); NavigateToURL(url2_); QuitBrowserAndRestore(1); // NOTE: Don't use GetActiveWindow here, when run with the screen locked // active windows returns NULL. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy.get()); scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetTab(0)); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); ASSERT_EQ(url2_, GetActiveTabURL()); ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_proxy->GoBack()); ASSERT_EQ(url1_, GetActiveTabURL()); } TEST_F(SessionRestoreUITest, RestoresForwardAndBackwardNavs) { NavigateToURL(url1_); NavigateToURL(url2_); NavigateToURL(url3_); scoped_refptr<TabProxy> active_tab(GetActiveTab()); ASSERT_TRUE(active_tab.get()); ASSERT_TRUE(active_tab->GoBack()); QuitBrowserAndRestore(1); // NOTE: Don't use GetActiveWindow here, when run with the screen locked // active windows returns NULL. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy.get()); scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetTab(0)); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); ASSERT_TRUE(GetActiveTabURL() == url2_); ASSERT_TRUE(tab_proxy->GoForward()); ASSERT_TRUE(GetActiveTabURL() == url3_); ASSERT_TRUE(tab_proxy->GoBack()); ASSERT_TRUE(GetActiveTabURL() == url2_); ASSERT_TRUE(tab_proxy->GoBack()); ASSERT_TRUE(GetActiveTabURL() == url1_); } // Tests that the SiteInstances used for entries in a restored tab's history // are given appropriate max page IDs, so that going back to a restored // cross-site page and then forward again works. (Bug 1204135) TEST_F(SessionRestoreUITest, RestoresCrossSiteForwardAndBackwardNavs) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(FILE_PATH_LITERAL("chrome/test/data"))); ASSERT_TRUE(test_server.Start()); GURL cross_site_url(test_server.GetURL("files/title2.html")); // Visit URLs on different sites. NavigateToURL(url1_); NavigateToURL(cross_site_url); NavigateToURL(url2_); scoped_refptr<TabProxy> active_tab(GetActiveTab()); ASSERT_TRUE(active_tab.get()); ASSERT_TRUE(active_tab->GoBack()); QuitBrowserAndRestore(1); // NOTE: Don't use GetActiveWindow here, when run with the screen locked // active windows returns NULL. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy.get()); int tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); ASSERT_EQ(1, tab_count); scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetTab(0)); ASSERT_TRUE(tab_proxy.get()); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); // Check that back and forward work as expected. GURL url; ASSERT_TRUE(tab_proxy->GetCurrentURL(&url)); ASSERT_EQ(cross_site_url, url); ASSERT_TRUE(tab_proxy->GoBack()); ASSERT_TRUE(tab_proxy->GetCurrentURL(&url)); ASSERT_EQ(url1_, url); ASSERT_TRUE(tab_proxy->GoForward()); ASSERT_TRUE(tab_proxy->GetCurrentURL(&url)); ASSERT_EQ(cross_site_url, url); ASSERT_TRUE(tab_proxy->GoForward()); ASSERT_TRUE(tab_proxy->GetCurrentURL(&url)); ASSERT_EQ(url2_, url); } TEST_F(SessionRestoreUITest, TwoTabsSecondSelected) { NavigateToURL(url1_); // NOTE: Don't use GetActiveWindow here, when run with the screen locked // active windows returns NULL. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy.get()); ASSERT_TRUE(browser_proxy->AppendTab(url2_)); QuitBrowserAndRestore(2); browser_proxy = NULL; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); browser_proxy = automation()->GetBrowserWindow(0); int tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); ASSERT_EQ(2, tab_count); int active_tab_index; ASSERT_TRUE(browser_proxy->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(1, active_tab_index); scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetActiveTab()); ASSERT_TRUE(tab_proxy.get()); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); ASSERT_EQ(url2_, GetActiveTabURL()); ASSERT_TRUE(browser_proxy->ActivateTab(0)); tab_proxy = browser_proxy->GetActiveTab(); ASSERT_TRUE(tab_proxy.get()); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); ASSERT_EQ(url1_, GetActiveTabURL()); } // Creates two tabs, closes one, quits and makes sure only one tab is restored. TEST_F(SessionRestoreUITest, ClosedTabStaysClosed) { NavigateToURL(url1_); // NOTE: Don't use GetActiveWindow here, when run with the screen locked // active windows returns NULL. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy.get()); scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetTab(0)); ASSERT_TRUE(tab_proxy.get()); ASSERT_TRUE(browser_proxy->AppendTab(url2_)); scoped_refptr<TabProxy> active_tab(browser_proxy->GetActiveTab()); ASSERT_TRUE(active_tab.get()); ASSERT_TRUE(active_tab->Close(true)); QuitBrowserAndRestore(1); browser_proxy = NULL; tab_proxy = NULL; AssertOneWindowWithOneTab(); ASSERT_EQ(url1_, GetActiveTabURL()); } // Creates a tabbed browser and popup and makes sure we restore both. TEST_F(SessionRestoreUITest, NormalAndPopup) { if (!browser_defaults::kRestorePopups) return; // Test only applicable if restoring popups. NavigateToURL(url1_); // Make sure we have one window. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); // Open a popup. ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_POPUP, true)); ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(2, window_count); scoped_refptr<BrowserProxy> popup(automation()->GetBrowserWindow(1)); ASSERT_TRUE(popup.get()); scoped_refptr<TabProxy> tab(popup->GetTab(0)); ASSERT_TRUE(tab.get()); ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(url1_)); // Simulate an exit by shuting down the session service. If we don't do this // the first window close is treated as though the user closed the window // and won't be restored. ASSERT_TRUE(popup->ShutdownSessionService()); tab = NULL; popup = NULL; // Restart and make sure we have only one window with one tab and the url // is url1_. QuitBrowserAndRestore(1); ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(2, window_count); scoped_refptr<BrowserProxy> browser_proxy1( automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy1.get()); scoped_refptr<BrowserProxy> browser_proxy2( automation()->GetBrowserWindow(1)); ASSERT_TRUE(browser_proxy2.get()); Browser::Type type1, type2; ASSERT_TRUE(browser_proxy1->GetType(&type1)); ASSERT_TRUE(browser_proxy2->GetType(&type2)); // The order of whether the normal window or popup is first depends upon // activation order, which is not necessarily consistant across runs. if (type1 == Browser::TYPE_NORMAL) { EXPECT_EQ(type2, Browser::TYPE_POPUP); } else { EXPECT_EQ(type1, Browser::TYPE_POPUP); EXPECT_EQ(type2, Browser::TYPE_NORMAL); } } #if !defined(OS_MACOSX) // This test doesn't apply to the Mac version; see // LaunchAnotherBrowserBlockUntilClosed for details. // Launches an app window, closes tabbed browser, launches and makes sure // we restore the tabbed browser url. // Flaky: http://crbug.com/29110 TEST_F(SessionRestoreUITest, FLAKY_RestoreAfterClosingTabbedBrowserWithAppAndLaunching) { NavigateToURL(url1_); // Launch an app. bool include_testing_id_orig = include_testing_id_; include_testing_id_ = false; clear_profile_ = false; CommandLine app_launch_arguments = launch_arguments_; app_launch_arguments.AppendSwitchASCII(switches::kApp, url2_.spec()); LaunchAnotherBrowserBlockUntilClosed(app_launch_arguments); ASSERT_TRUE(automation()->WaitForWindowCountToBecome(2)); // Close the first window. The only window left is the App window. CloseWindow(0, 2); // Restore the session, which should bring back the first window with url1_. // First restore the settings so we can connect to the browser. include_testing_id_ = include_testing_id_orig; // Restore the session with 1 tab. QuitBrowserAndRestore(1); AssertOneWindowWithOneTab(); ASSERT_EQ(url1_, GetActiveTabURL()); } #endif // !OS_MACOSX // Creates two windows, closes one, restores, make sure only one window open. TEST_F(SessionRestoreUITest, TwoWindowsCloseOneRestoreOnlyOne) { NavigateToURL(url1_); // Make sure we have one window. int window_count; ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(1, window_count); // Open a second window. ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_NORMAL, true)); ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); ASSERT_EQ(2, window_count); // Close it. CloseWindow(1, 2); // Restart and make sure we have only one window with one tab and the url // is url1_. QuitBrowserAndRestore(1); AssertOneWindowWithOneTab(); ASSERT_EQ(url1_, GetActiveTabURL()); } // Make sure after a restore the number of processes matches that of the number // of processes running before the restore. This creates a new tab so that // we should have two new tabs running. (This test will pass in both // process-per-site and process-per-site-instance, because we treat the new tab // as a special case in process-per-site-instance so that it only ever uses one // process.) // // Flaky: http://code.google.com/p/chromium/issues/detail?id=52022 // Unfortunately, the fix at http://codereview.chromium.org/6546078 // breaks NTP background image refreshing, so ThemeSource had to revert to // replacing the existing data source. TEST_F(SessionRestoreUITest, FLAKY_ShareProcessesOnRestore) { if (ProxyLauncher::in_process_renderer()) { // No point in running this test in single process mode. return; } scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser_proxy.get() != NULL); int tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); // Create two new tabs. ASSERT_TRUE(browser_proxy->RunCommand(IDC_NEW_TAB)); ASSERT_TRUE(browser_proxy->RunCommand(IDC_NEW_TAB)); int new_tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&new_tab_count)); ASSERT_EQ(tab_count + 2, new_tab_count); int expected_process_count = 0; ASSERT_TRUE(GetBrowserProcessCount(&expected_process_count)); int expected_tab_count = new_tab_count; // Restart. browser_proxy = NULL; QuitBrowserAndRestore(3); // Wait for each tab to finish being restored, then make sure the process // count matches. browser_proxy = automation()->GetBrowserWindow(0); ASSERT_TRUE(browser_proxy.get() != NULL); ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); ASSERT_EQ(expected_tab_count, tab_count); for (int i = 0; i < expected_tab_count; ++i) { scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetTab(i)); ASSERT_TRUE(tab_proxy.get() != NULL); ASSERT_TRUE(tab_proxy->WaitForTabToBeRestored( TestTimeouts::action_max_timeout_ms())); } int process_count = 0; ASSERT_TRUE(GetBrowserProcessCount(&process_count)); ASSERT_EQ(expected_process_count, process_count); } } // namespace