weblayer: renames SessionService to BrowserPersister

This better conveys what the object does.

BUG=none
TEST=none

Change-Id: I21df5bcf0eca88184ace9a479e35b0e76a4be595
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2051018
Commit-Queue: Scott Violet <[email protected]>
Reviewed-by: Evan Stade <[email protected]>
Cr-Commit-Position: refs/heads/master@{#740452}
diff --git a/weblayer/browser/persistence/browser_persister_browsertest.cc b/weblayer/browser/persistence/browser_persister_browsertest.cc
new file mode 100644
index 0000000..a3ed821a
--- /dev/null
+++ b/weblayer/browser/persistence/browser_persister_browsertest.cc
@@ -0,0 +1,308 @@
+// 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/files/file_path.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "build/build_config.h"
+#include "components/sessions/core/command_storage_manager_test_helper.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 "weblayer/browser/browser_impl.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/common/weblayer_paths.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 {
+
+class OneShotNavigationObserver : public NavigationObserver {
+ public:
+  explicit OneShotNavigationObserver(Shell* shell) : tab_(shell->tab()) {
+    tab_->GetNavigationController()->AddObserver(this);
+  }
+
+  ~OneShotNavigationObserver() override {
+    tab_->GetNavigationController()->RemoveObserver(this);
+  }
+
+  void WaitForNavigation() { run_loop_.Run(); }
+
+  bool completed() { return completed_; }
+  bool is_error_page() { return is_error_page_; }
+  Navigation::LoadError load_error() { return load_error_; }
+  int http_status_code() { return http_status_code_; }
+  NavigationState navigation_state() { return navigation_state_; }
+
+ private:
+  // NavigationObserver implementation:
+  void NavigationCompleted(Navigation* navigation) override {
+    completed_ = true;
+    Finish(navigation);
+  }
+
+  void NavigationFailed(Navigation* navigation) override { Finish(navigation); }
+
+  void Finish(Navigation* navigation) {
+    is_error_page_ = navigation->IsErrorPage();
+    load_error_ = navigation->GetLoadError();
+    http_status_code_ = navigation->GetHttpStatusCode();
+    navigation_state_ = navigation->GetState();
+    run_loop_.Quit();
+  }
+
+  base::RunLoop run_loop_;
+  Tab* tab_;
+  bool completed_ = false;
+  bool is_error_page_ = false;
+  Navigation::LoadError load_error_ = Navigation::kNoError;
+  int http_status_code_ = 0;
+  NavigationState navigation_state_ = NavigationState::kWaitingResponse;
+};
+
+class BrowserObserverImpl : public BrowserObserver {
+ public:
+  static void WaitForNewTab(Browser* browser) {
+    BrowserObserverImpl observer(browser);
+    observer.Wait();
+  }
+
+ private:
+  explicit BrowserObserverImpl(Browser* browser) : browser_(browser) {
+    browser_->AddObserver(this);
+  }
+  ~BrowserObserverImpl() override { browser_->RemoveObserver(this); }
+
+  void Wait() { run_loop_.Run(); }
+
+  // BrowserObserver:
+  void OnTabAdded(Tab* tab) override { run_loop_.Quit(); }
+
+  Browser* browser_;
+  base::RunLoop run_loop_;
+};
+
+class BrowserNavigationObserverImpl : public BrowserObserver,
+                                      public NavigationObserver {
+ public:
+  static void WaitForNewTabToCompleteNavigation(Browser* browser,
+                                                const GURL& url,
+                                                int tab_to_wait_for = 1) {
+    BrowserNavigationObserverImpl observer(browser, url, tab_to_wait_for);
+    observer.Wait();
+  }
+
+ private:
+  BrowserNavigationObserverImpl(Browser* browser,
+                                const GURL& url,
+                                int tab_to_wait_for)
+      : browser_(browser), url_(url), tab_to_wait_for_(tab_to_wait_for) {
+    browser_->AddObserver(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();
+  }
+
+  // BrowserObserver:
+  void OnTabAdded(Tab* tab) override {
+    if (--tab_to_wait_for_ != 0)
+      return;
+
+    browser_->RemoveObserver(this);
+    tab_ = tab;
+    tab_->GetNavigationController()->AddObserver(this);
+  }
+
+  Browser* browser_;
+  const GURL& url_;
+  Tab* tab_ = nullptr;
+  int 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->AddTab(Tab::Create(GetProfile()));
+  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(1, browser->GetTabs()[0]
+                   ->GetNavigationController()
+                   ->GetNavigationListSize());
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
+  Tab* tab1 = browser->AddTab(Tab::Create(GetProfile()));
+  const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
+  NavigateAndWaitForCompletion(url1, tab1);
+
+  Tab* tab2 = browser->AddTab(Tab::Create(GetProfile()));
+  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, 2);
+
+    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->AddTab(Tab::Create(GetProfile()));
+  const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
+  NavigateAndWaitForCompletion(url1, tab1);
+
+  Tab* tab2 = browser1->AddTab(Tab::Create(GetProfile()));
+  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->AddTab(Tab::Create(GetProfile()));
+  const GURL url3 = embedded_test_server()->GetURL("/simple_page3.html");
+  NavigateAndWaitForCompletion(url3, tab3);
+
+  // Move |tab2| to |browser2|.
+  browser2->AddTab(browser1->RemoveTab(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, 1);
+  ASSERT_EQ(1u, browser1->GetTabs().size());
+  EXPECT_EQ(1, browser1->GetTabs()[0]
+                   ->GetNavigationController()
+                   ->GetNavigationListSize());
+
+  browser2 = CreateBrowser(GetProfile(), "y");
+  BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
+      browser2.get(), url2, 2);
+  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();
+  content::WaitForLoadStop(restored_tab_3->web_contents());
+}
+
+}  // namespace weblayer