blob: 4c590066198c0414a5d90eb1e1ff214cb45727c3 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sessions/session_restore_observer.h"
#include <memory>
#include <unordered_map>
#include "base/run_loop.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker_test_support.h"
#include "chrome/browser/resource_coordinator/tab_manager.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/sessions/session_restore_test_helper.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sessions/session_service_test_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/keep_alive_registry/keep_alive_types.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::WebContents;
using content::NavigationHandle;
class MockSessionRestoreObserver : public SessionRestoreObserver {
public:
MockSessionRestoreObserver() { SessionRestore::AddObserver(this); }
MockSessionRestoreObserver(const MockSessionRestoreObserver&) = delete;
MockSessionRestoreObserver& operator=(const MockSessionRestoreObserver&) =
delete;
~MockSessionRestoreObserver() { SessionRestore::RemoveObserver(this); }
enum class SessionRestoreEvent { kStartedLoadingTabs, kFinishedLoadingTabs };
const std::vector<SessionRestoreEvent>& session_restore_events() const {
return session_restore_events_;
}
// SessionRestoreObserver implementation:
void OnSessionRestoreStartedLoadingTabs() override {
session_restore_events_.emplace_back(
SessionRestoreEvent::kStartedLoadingTabs);
}
void OnSessionRestoreFinishedLoadingTabs() override {
session_restore_events_.emplace_back(
SessionRestoreEvent::kFinishedLoadingTabs);
}
private:
std::vector<SessionRestoreEvent> session_restore_events_;
};
class SessionRestoreObserverTest : public InProcessBrowserTest {
protected:
SessionRestoreObserverTest() = default;
SessionRestoreObserverTest(const SessionRestoreObserverTest&) = delete;
SessionRestoreObserverTest& operator=(const SessionRestoreObserverTest&) =
delete;
void SetUpOnMainThread() override {
SessionStartupPref pref(SessionStartupPref::LAST);
SessionStartupPref::SetStartupPref(browser()->profile(), pref);
#if BUILDFLAG(IS_CHROMEOS)
SessionServiceTestHelper helper(
SessionServiceFactory::GetForProfile(browser()->profile()));
helper.SetForceBrowserNotAliveWithNoWindows(true);
#endif
ASSERT_TRUE(embedded_test_server()->Start());
}
BrowserWindowInterface* QuitBrowserAndRestore(
BrowserWindowInterface* browser) {
Profile* const profile = browser->GetProfile();
auto keep_alive = std::make_unique<ScopedKeepAlive>(
KeepAliveOrigin::SESSION_RESTORE, KeepAliveRestartOption::DISABLED);
auto profile_keep_alive = std::make_unique<ScopedProfileKeepAlive>(
profile, ProfileKeepAliveOrigin::kBrowserWindow);
CloseBrowserSynchronously(browser);
// Create a new window, which should trigger session restore.
chrome::NewEmptyWindow(profile);
SessionRestoreTestHelper().Wait();
return GetLastActiveBrowserWindowInterfaceWithAnyProfile();
}
void WaitForTabsToLoad(TabStripModel* tab_strip_model) {
for (int i = 0; i < tab_strip_model->count(); ++i) {
WebContents* contents = tab_strip_model->GetWebContentsAt(i);
contents->GetController().LoadIfNecessary();
resource_coordinator::WaitForTransitionToLoaded(contents);
}
}
GURL GetTestURL() const {
return embedded_test_server()->GetURL("/title1.html");
}
const std::vector<MockSessionRestoreObserver::SessionRestoreEvent>&
session_restore_events() const {
return mock_observer_.session_restore_events();
}
size_t number_of_session_restore_events() const {
return session_restore_events().size();
}
MockSessionRestoreObserver& session_restore_observer() {
return mock_observer_;
}
private:
MockSessionRestoreObserver mock_observer_;
};
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#define MAYBE_SingleTabSessionRestore DISABLED_SingleTabSessionRestore
#else
#define MAYBE_SingleTabSessionRestore SingleTabSessionRestore
#endif
IN_PROC_BROWSER_TEST_F(SessionRestoreObserverTest,
MAYBE_SingleTabSessionRestore) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL()));
// The restored browser should have 1 tab.
TabStripModel* tab_strip =
QuitBrowserAndRestore(browser())->GetTabStripModel();
ASSERT_TRUE(tab_strip);
ASSERT_EQ(1, tab_strip->count());
ASSERT_EQ(1u, number_of_session_restore_events());
EXPECT_EQ(
MockSessionRestoreObserver::SessionRestoreEvent::kStartedLoadingTabs,
session_restore_events()[0]);
ASSERT_NO_FATAL_FAILURE(WaitForTabsToLoad(tab_strip));
ASSERT_EQ(2u, number_of_session_restore_events());
EXPECT_EQ(
MockSessionRestoreObserver::SessionRestoreEvent::kFinishedLoadingTabs,
session_restore_events()[1]);
}
IN_PROC_BROWSER_TEST_F(SessionRestoreObserverTest, MultipleTabSessionRestore) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL()));
ui_test_utils::NavigateToURLWithDisposition(
browser(), GetTestURL(), WindowOpenDisposition::NEW_BACKGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
// The restored browser should have 2 tabs.
TabStripModel* tab_strip =
QuitBrowserAndRestore(browser())->GetTabStripModel();
ASSERT_TRUE(tab_strip);
ASSERT_EQ(2, tab_strip->count());
ASSERT_EQ(1u, number_of_session_restore_events());
EXPECT_EQ(
MockSessionRestoreObserver::SessionRestoreEvent::kStartedLoadingTabs,
session_restore_events()[0]);
ASSERT_NO_FATAL_FAILURE(WaitForTabsToLoad(tab_strip));
ASSERT_EQ(2u, number_of_session_restore_events());
EXPECT_EQ(
MockSessionRestoreObserver::SessionRestoreEvent::kFinishedLoadingTabs,
session_restore_events()[1]);
}