123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- // Copyright 2020 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 "weblayer/browser/persistence/browser_persister.h"
- #include "base/callback_helpers.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/guid.h"
- #include "base/memory/raw_ptr.h"
- #include "base/path_service.h"
- #include "base/run_loop.h"
- #include "base/test/bind.h"
- #include "base/threading/thread_restrictions.h"
- #include "build/build_config.h"
- #include "components/sessions/core/command_storage_backend.h"
- #include "components/sessions/core/command_storage_manager_test_helper.h"
- #include "components/sessions/core/session_constants.h"
- #include "content/public/test/browser_test_utils.h"
- #include "content/public/test/url_loader_interceptor.h"
- #include "net/base/filename_util.h"
- #include "net/test/embedded_test_server/embedded_test_server.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "weblayer/browser/browser_impl.h"
- #include "weblayer/browser/persistence/browser_persister_file_utils.h"
- #include "weblayer/browser/profile_impl.h"
- #include "weblayer/browser/tab_impl.h"
- #include "weblayer/common/weblayer_paths.h"
- #include "weblayer/public/browser_restore_observer.h"
- #include "weblayer/public/navigation.h"
- #include "weblayer/public/navigation_controller.h"
- #include "weblayer/public/navigation_observer.h"
- #include "weblayer/public/tab.h"
- #include "weblayer/shell/browser/shell.h"
- #include "weblayer/test/interstitial_utils.h"
- #include "weblayer/test/test_navigation_observer.h"
- #include "weblayer/test/weblayer_browser_test.h"
- #include "weblayer/test/weblayer_browser_test_utils.h"
- namespace weblayer {
- class BrowserPersisterTestHelper {
- public:
- static sessions::CommandStorageManager* GetCommandStorageManager(
- BrowserPersister* persister) {
- return persister->command_storage_manager_.get();
- }
- };
- namespace {
- using testing::UnorderedElementsAre;
- class BrowserNavigationObserverImpl : public BrowserRestoreObserver,
- public NavigationObserver {
- public:
- static void WaitForNewTabToCompleteNavigation(Browser* browser,
- const GURL& url,
- size_t tab_to_wait_for = 0) {
- BrowserNavigationObserverImpl observer(browser, url, tab_to_wait_for);
- observer.Wait();
- }
- private:
- BrowserNavigationObserverImpl(Browser* browser,
- const GURL& url,
- size_t tab_to_wait_for)
- : browser_(browser), url_(url), tab_to_wait_for_(tab_to_wait_for) {
- browser_->AddBrowserRestoreObserver(this);
- }
- ~BrowserNavigationObserverImpl() override {
- tab_->GetNavigationController()->RemoveObserver(this);
- }
- void Wait() { run_loop_.Run(); }
- // NavigationObserver;
- void NavigationCompleted(Navigation* navigation) override {
- if (navigation->GetURL() == url_)
- run_loop_.Quit();
- }
- // BrowserRestoreObserver:
- void OnRestoreCompleted() override {
- browser_->RemoveBrowserRestoreObserver(this);
- ASSERT_LT(tab_to_wait_for_, browser_->GetTabs().size());
- ASSERT_EQ(nullptr, tab_.get());
- tab_ = browser_->GetTabs()[tab_to_wait_for_];
- tab_->GetNavigationController()->AddObserver(this);
- }
- raw_ptr<Browser> browser_;
- const GURL& url_;
- raw_ptr<Tab> tab_ = nullptr;
- const size_t tab_to_wait_for_;
- std::unique_ptr<TestNavigationObserver> navigation_observer_;
- base::RunLoop run_loop_;
- };
- void ShutdownBrowserPersisterAndWait(BrowserImpl* browser) {
- auto task_runner = sessions::CommandStorageManagerTestHelper(
- BrowserPersisterTestHelper::GetCommandStorageManager(
- browser->browser_persister()))
- .GetBackendTaskRunner();
- browser->PrepareForShutdown();
- base::RunLoop run_loop;
- task_runner->PostTaskAndReply(FROM_HERE, base::DoNothing(),
- run_loop.QuitClosure());
- run_loop.Run();
- }
- std::unique_ptr<BrowserImpl> CreateBrowser(ProfileImpl* profile,
- const std::string& persistence_id) {
- Browser::PersistenceInfo info;
- info.id = persistence_id;
- auto browser = Browser::Create(profile, &info);
- return std::unique_ptr<BrowserImpl>(
- static_cast<BrowserImpl*>(browser.release()));
- }
- } // namespace
- using BrowserPersisterTest = WebLayerBrowserTest;
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) {
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
- Tab* tab = browser->CreateTab();
- EXPECT_TRUE(browser->IsRestoringPreviousState());
- const GURL url = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url, tab);
- ShutdownBrowserPersisterAndWait(browser.get());
- tab = nullptr;
- browser.reset();
- browser = CreateBrowser(GetProfile(), "x");
- // Should be no tabs while waiting for restore.
- EXPECT_TRUE(browser->GetTabs().empty());
- EXPECT_TRUE(browser->IsRestoringPreviousState());
- // Wait for the restore and navigation to complete.
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser.get(), url);
- ASSERT_EQ(1u, browser->GetTabs().size());
- EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
- EXPECT_EQ(1, browser->GetTabs()[0]
- ->GetNavigationController()
- ->GetNavigationListSize());
- EXPECT_FALSE(browser->IsRestoringPreviousState());
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, RestoresGuid) {
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
- Tab* tab = browser->CreateTab();
- const std::string original_guid = tab->GetGuid();
- EXPECT_FALSE(original_guid.empty());
- EXPECT_TRUE(base::IsValidGUID(original_guid));
- const GURL url = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url, tab);
- ShutdownBrowserPersisterAndWait(browser.get());
- tab = nullptr;
- browser.reset();
- browser = CreateBrowser(GetProfile(), "x");
- // Should be no tabs while waiting for restore.
- EXPECT_TRUE(browser->GetTabs().empty());
- // Wait for the restore and navigation to complete.
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser.get(), url);
- ASSERT_EQ(1u, browser->GetTabs().size());
- EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
- EXPECT_EQ(original_guid, browser->GetTabs()[0]->GetGuid());
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, RestoresData) {
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
- Tab* tab = browser->CreateTab();
- tab->SetData({{"abc", "efg"}});
- const GURL url = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url, tab);
- ShutdownBrowserPersisterAndWait(browser.get());
- tab = nullptr;
- browser.reset();
- browser = CreateBrowser(GetProfile(), "x");
- // Should be no tabs while waiting for restore.
- EXPECT_TRUE(browser->GetTabs().empty());
- // Wait for the restore and navigation to complete.
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser.get(), url);
- ASSERT_EQ(1u, browser->GetTabs().size());
- EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
- EXPECT_THAT(browser->GetTabs()[0]->GetData(),
- UnorderedElementsAre(std::make_pair("abc", "efg")));
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, RestoresMostRecentData) {
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
- Tab* tab = browser->CreateTab();
- tab->SetData({{"xxx", "xxx"}});
- const GURL url = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url, tab);
- // Make sure the data has been saved, then set different data on the tab.
- BrowserPersisterTestHelper::GetCommandStorageManager(
- browser->browser_persister())
- ->Save();
- tab->SetData({{"abc", "efg"}});
- ShutdownBrowserPersisterAndWait(browser.get());
- tab = nullptr;
- browser.reset();
- browser = CreateBrowser(GetProfile(), "x");
- // Should be no tabs while waiting for restore.
- EXPECT_TRUE(browser->GetTabs().empty());
- // Wait for the restore and navigation to complete.
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser.get(), url);
- ASSERT_EQ(1u, browser->GetTabs().size());
- EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
- EXPECT_THAT(browser->GetTabs()[0]->GetData(),
- UnorderedElementsAre(std::make_pair("abc", "efg")));
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) {
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
- Tab* tab1 = browser->CreateTab();
- const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url1, tab1);
- Tab* tab2 = browser->CreateTab();
- const GURL url2 = embedded_test_server()->GetURL("/simple_page2.html");
- NavigateAndWaitForCompletion(url2, tab2);
- browser->SetActiveTab(tab2);
- // Shut down the service.
- ShutdownBrowserPersisterAndWait(browser.get());
- tab1 = tab2 = nullptr;
- browser.reset();
- // Recreate the browser and run the assertions twice to ensure we handle
- // correctly storing state of tabs that need to be reloaded.
- for (int i = 0; i < 2; ++i) {
- browser = CreateBrowser(GetProfile(), "x");
- // Should be no tabs while waiting for restore.
- EXPECT_TRUE(browser->GetTabs().empty()) << "iteration " << i;
- // Wait for the restore and navigation to complete. This waits for the
- // second tab as that was the active one.
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser.get(), url2, 1);
- ASSERT_EQ(2u, browser->GetTabs().size()) << "iteration " << i;
- // The first tab shouldn't have loaded yet, as it's not active.
- EXPECT_TRUE(static_cast<TabImpl*>(browser->GetTabs()[0])
- ->web_contents()
- ->GetController()
- .NeedsReload())
- << "iteration " << i;
- EXPECT_EQ(browser->GetTabs()[1], browser->GetActiveTab())
- << "iteration " << i;
- EXPECT_EQ(1, browser->GetTabs()[1]
- ->GetNavigationController()
- ->GetNavigationListSize())
- << "iteration " << i;
- ShutdownBrowserPersisterAndWait(browser.get());
- }
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) {
- ASSERT_TRUE(embedded_test_server()->Start());
- // Create a browser with two tabs.
- std::unique_ptr<BrowserImpl> browser1 = CreateBrowser(GetProfile(), "x");
- Tab* tab1 = browser1->CreateTab();
- const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url1, tab1);
- Tab* tab2 = browser1->CreateTab();
- const GURL url2 = embedded_test_server()->GetURL("/simple_page2.html");
- NavigateAndWaitForCompletion(url2, tab2);
- browser1->SetActiveTab(tab2);
- // Create another browser with a single tab.
- std::unique_ptr<BrowserImpl> browser2 = CreateBrowser(GetProfile(), "y");
- Tab* tab3 = browser2->CreateTab();
- const GURL url3 = embedded_test_server()->GetURL("/simple_page3.html");
- NavigateAndWaitForCompletion(url3, tab3);
- // Move |tab2| to |browser2|.
- browser2->AddTab(tab2);
- browser2->SetActiveTab(tab2);
- ShutdownBrowserPersisterAndWait(browser1.get());
- ShutdownBrowserPersisterAndWait(browser2.get());
- tab1 = nullptr;
- browser1.reset();
- tab2 = tab3 = nullptr;
- browser2.reset();
- // Restore the browsers.
- browser1 = CreateBrowser(GetProfile(), "x");
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser1.get(), url1);
- ASSERT_EQ(1u, browser1->GetTabs().size());
- EXPECT_EQ(1, browser1->GetTabs()[0]
- ->GetNavigationController()
- ->GetNavigationListSize());
- browser2 = CreateBrowser(GetProfile(), "y");
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser2.get(), url2, 1);
- ASSERT_EQ(2u, browser2->GetTabs().size());
- EXPECT_EQ(1, browser2->GetTabs()[1]
- ->GetNavigationController()
- ->GetNavigationListSize());
- // As |tab3| isn't active it needs to be loaded. Force that now.
- TabImpl* restored_tab_3 = static_cast<TabImpl*>(browser2->GetTabs()[0]);
- EXPECT_TRUE(restored_tab_3->web_contents()->GetController().NeedsReload());
- restored_tab_3->web_contents()->GetController().LoadIfNecessary();
- EXPECT_TRUE(content::WaitForLoadStop(restored_tab_3->web_contents()));
- }
- class BrowserPersisterTestWithTwoPersistedIds : public WebLayerBrowserTest {
- public:
- // WebLayerBrowserTest:
- void SetUpOnMainThread() override {
- WebLayerBrowserTest::SetUpOnMainThread();
- // Configure two browsers with ids 'x' and 'y'.
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser1 = CreateBrowser(GetProfile(), "x");
- const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url1, browser1->CreateTab());
- std::unique_ptr<BrowserImpl> browser2 = CreateBrowser(GetProfile(), "y");
- const GURL url2 = embedded_test_server()->GetURL("/simple_page3.html");
- NavigateAndWaitForCompletion(url2, browser2->CreateTab());
- // Shut down the browsers.
- ShutdownBrowserPersisterAndWait(browser1.get());
- browser1.reset();
- ShutdownBrowserPersisterAndWait(browser2.get());
- browser2.reset();
- }
- };
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTestWithTwoPersistedIds,
- GetBrowserPersistenceIds) {
- {
- // Create a file that has the name of a valid persistence file, but has
- // invalid contents.
- base::ScopedAllowBlockingForTesting allow_blocking;
- base::WriteFile(BuildBasePathForBrowserPersister(
- GetProfile()->GetBrowserPersisterDataBaseDir(), "z"),
- "a bogus persistence file");
- }
- base::RunLoop run_loop;
- base::flat_set<std::string> persistence_ids;
- GetProfile()->GetBrowserPersistenceIds(
- base::BindLambdaForTesting([&](base::flat_set<std::string> ids) {
- persistence_ids = std::move(ids);
- run_loop.Quit();
- }));
- run_loop.Run();
- ASSERT_EQ(2u, persistence_ids.size());
- EXPECT_TRUE(persistence_ids.contains("x"));
- EXPECT_TRUE(persistence_ids.contains("y"));
- }
- bool HasSessionFileStartingWith(const base::FilePath& path) {
- auto paths = sessions::CommandStorageBackend::GetSessionFilePaths(
- path, sessions::CommandStorageManager::kOther);
- return paths.size() == 1;
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTestWithTwoPersistedIds,
- RemoveBrowserPersistenceStorage) {
- base::FilePath file_path1 = BuildBasePathForBrowserPersister(
- GetProfile()->GetBrowserPersisterDataBaseDir(), "x");
- base::FilePath file_path2 = BuildBasePathForBrowserPersister(
- GetProfile()->GetBrowserPersisterDataBaseDir(), "y");
- {
- base::ScopedAllowBlockingForTesting allow_blocking;
- ASSERT_TRUE(HasSessionFileStartingWith(file_path1));
- ASSERT_TRUE(HasSessionFileStartingWith(file_path2));
- }
- base::RunLoop run_loop;
- base::flat_set<std::string> persistence_ids;
- persistence_ids.insert("x");
- persistence_ids.insert("y");
- GetProfile()->RemoveBrowserPersistenceStorage(
- base::BindLambdaForTesting([&](bool result) {
- EXPECT_TRUE(result);
- run_loop.Quit();
- }),
- std::move(persistence_ids));
- run_loop.Run();
- {
- base::ScopedAllowBlockingForTesting allow_blocking;
- EXPECT_FALSE(base::PathExists(file_path1));
- EXPECT_FALSE(base::PathExists(file_path2));
- }
- }
- IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, OnErrorWritingSessionCommands) {
- ASSERT_TRUE(embedded_test_server()->Start());
- std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
- Tab* tab = browser->CreateTab();
- EXPECT_TRUE(browser->IsRestoringPreviousState());
- const GURL url = embedded_test_server()->GetURL("/simple_page.html");
- NavigateAndWaitForCompletion(url, tab);
- static_cast<sessions::CommandStorageManagerDelegate*>(
- browser->browser_persister())
- ->OnErrorWritingSessionCommands();
- ShutdownBrowserPersisterAndWait(browser.get());
- tab = nullptr;
- browser.reset();
- browser = CreateBrowser(GetProfile(), "x");
- // Should be no tabs while waiting for restore.
- EXPECT_TRUE(browser->GetTabs().empty());
- EXPECT_TRUE(browser->IsRestoringPreviousState());
- // Wait for the restore and navigation to complete.
- BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
- browser.get(), url);
- ASSERT_EQ(1u, browser->GetTabs().size());
- EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
- EXPECT_EQ(1, browser->GetTabs()[0]
- ->GetNavigationController()
- ->GetNavigationListSize());
- EXPECT_FALSE(browser->IsRestoringPreviousState());
- }
- } // namespace weblayer
|