blob: 692fff8d7a64dd11576a220958c9237b58183501 [file] [log] [blame]
Scott Violet87450ce2020-01-23 01:56:251// Copyright 2020 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
Scott Violet9843d0a2020-02-11 22:38:075#include "weblayer/browser/persistence/browser_persister.h"
Scott Violet87450ce2020-01-23 01:56:256
Gabriel Charette9f60dd12020-03-06 20:48:047#include "base/bind_helpers.h"
Scott Violet87450ce2020-01-23 01:56:258#include "base/files/file_path.h"
9#include "base/path_service.h"
10#include "base/run_loop.h"
Colin Blundellbe1dc132020-01-29 09:54:0611#include "build/build_config.h"
Scott Violet87450ce2020-01-23 01:56:2512#include "components/sessions/core/command_storage_manager_test_helper.h"
13#include "content/public/test/browser_test_utils.h"
14#include "content/public/test/url_loader_interceptor.h"
15#include "net/base/filename_util.h"
16#include "net/test/embedded_test_server/embedded_test_server.h"
17#include "weblayer/browser/browser_impl.h"
18#include "weblayer/browser/profile_impl.h"
19#include "weblayer/browser/tab_impl.h"
20#include "weblayer/common/weblayer_paths.h"
21#include "weblayer/public/navigation.h"
22#include "weblayer/public/navigation_controller.h"
23#include "weblayer/public/navigation_observer.h"
24#include "weblayer/public/tab.h"
25#include "weblayer/shell/browser/shell.h"
26#include "weblayer/test/interstitial_utils.h"
27#include "weblayer/test/test_navigation_observer.h"
28#include "weblayer/test/weblayer_browser_test.h"
29#include "weblayer/test/weblayer_browser_test_utils.h"
30
31namespace weblayer {
32
Scott Violet9843d0a2020-02-11 22:38:0733class BrowserPersisterTestHelper {
Scott Violet87450ce2020-01-23 01:56:2534 public:
35 static sessions::CommandStorageManager* GetCommandStorageManager(
Scott Violet9843d0a2020-02-11 22:38:0736 BrowserPersister* persister) {
37 return persister->command_storage_manager_.get();
Scott Violet87450ce2020-01-23 01:56:2538 }
39};
40
41namespace {
42
43class OneShotNavigationObserver : public NavigationObserver {
44 public:
45 explicit OneShotNavigationObserver(Shell* shell) : tab_(shell->tab()) {
46 tab_->GetNavigationController()->AddObserver(this);
47 }
48
49 ~OneShotNavigationObserver() override {
50 tab_->GetNavigationController()->RemoveObserver(this);
51 }
52
53 void WaitForNavigation() { run_loop_.Run(); }
54
55 bool completed() { return completed_; }
56 bool is_error_page() { return is_error_page_; }
57 Navigation::LoadError load_error() { return load_error_; }
58 int http_status_code() { return http_status_code_; }
59 NavigationState navigation_state() { return navigation_state_; }
60
61 private:
62 // NavigationObserver implementation:
63 void NavigationCompleted(Navigation* navigation) override {
64 completed_ = true;
65 Finish(navigation);
66 }
67
68 void NavigationFailed(Navigation* navigation) override { Finish(navigation); }
69
70 void Finish(Navigation* navigation) {
71 is_error_page_ = navigation->IsErrorPage();
72 load_error_ = navigation->GetLoadError();
73 http_status_code_ = navigation->GetHttpStatusCode();
74 navigation_state_ = navigation->GetState();
75 run_loop_.Quit();
76 }
77
78 base::RunLoop run_loop_;
79 Tab* tab_;
80 bool completed_ = false;
81 bool is_error_page_ = false;
82 Navigation::LoadError load_error_ = Navigation::kNoError;
83 int http_status_code_ = 0;
84 NavigationState navigation_state_ = NavigationState::kWaitingResponse;
85};
86
87class BrowserObserverImpl : public BrowserObserver {
88 public:
89 static void WaitForNewTab(Browser* browser) {
90 BrowserObserverImpl observer(browser);
91 observer.Wait();
92 }
93
94 private:
95 explicit BrowserObserverImpl(Browser* browser) : browser_(browser) {
96 browser_->AddObserver(this);
97 }
98 ~BrowserObserverImpl() override { browser_->RemoveObserver(this); }
99
100 void Wait() { run_loop_.Run(); }
101
102 // BrowserObserver:
103 void OnTabAdded(Tab* tab) override { run_loop_.Quit(); }
104
105 Browser* browser_;
106 base::RunLoop run_loop_;
107};
108
109class BrowserNavigationObserverImpl : public BrowserObserver,
110 public NavigationObserver {
111 public:
112 static void WaitForNewTabToCompleteNavigation(Browser* browser,
113 const GURL& url,
114 int tab_to_wait_for = 1) {
115 BrowserNavigationObserverImpl observer(browser, url, tab_to_wait_for);
116 observer.Wait();
117 }
118
119 private:
120 BrowserNavigationObserverImpl(Browser* browser,
121 const GURL& url,
122 int tab_to_wait_for)
123 : browser_(browser), url_(url), tab_to_wait_for_(tab_to_wait_for) {
124 browser_->AddObserver(this);
125 }
126 ~BrowserNavigationObserverImpl() override {
127 tab_->GetNavigationController()->RemoveObserver(this);
128 }
129
130 void Wait() { run_loop_.Run(); }
131
132 // NavigationObserver;
133 void NavigationCompleted(Navigation* navigation) override {
134 if (navigation->GetURL() == url_)
135 run_loop_.Quit();
136 }
137
138 // BrowserObserver:
139 void OnTabAdded(Tab* tab) override {
140 if (--tab_to_wait_for_ != 0)
141 return;
142
143 browser_->RemoveObserver(this);
144 tab_ = tab;
145 tab_->GetNavigationController()->AddObserver(this);
146 }
147
148 Browser* browser_;
149 const GURL& url_;
150 Tab* tab_ = nullptr;
151 int tab_to_wait_for_;
152 std::unique_ptr<TestNavigationObserver> navigation_observer_;
153 base::RunLoop run_loop_;
154};
155
Scott Violet9843d0a2020-02-11 22:38:07156void ShutdownBrowserPersisterAndWait(BrowserImpl* browser) {
Scott Violet87450ce2020-01-23 01:56:25157 auto task_runner = sessions::CommandStorageManagerTestHelper(
Scott Violet9843d0a2020-02-11 22:38:07158 BrowserPersisterTestHelper::GetCommandStorageManager(
159 browser->browser_persister()))
Scott Violet87450ce2020-01-23 01:56:25160 .GetBackendTaskRunner();
161 browser->PrepareForShutdown();
162 base::RunLoop run_loop;
163 task_runner->PostTaskAndReply(FROM_HERE, base::DoNothing(),
164 run_loop.QuitClosure());
165 run_loop.Run();
166}
167
Scott Violetbf8b8aa72020-01-28 19:37:32168std::unique_ptr<BrowserImpl> CreateBrowser(ProfileImpl* profile,
169 const std::string& persistence_id) {
170 Browser::PersistenceInfo info;
171 info.id = persistence_id;
Scott Violetb7df9d62020-01-31 16:18:49172 auto browser = Browser::Create(profile, &info);
173 return std::unique_ptr<BrowserImpl>(
174 static_cast<BrowserImpl*>(browser.release()));
Scott Violetbf8b8aa72020-01-28 19:37:32175}
176
Scott Violet87450ce2020-01-23 01:56:25177} // namespace
178
Scott Violet9843d0a2020-02-11 22:38:07179using BrowserPersisterTest = WebLayerBrowserTest;
Scott Violet87450ce2020-01-23 01:56:25180
Scott Violet9843d0a2020-02-11 22:38:07181IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) {
Scott Violet87450ce2020-01-23 01:56:25182 ASSERT_TRUE(embedded_test_server()->Start());
183
Scott Violetbf8b8aa72020-01-28 19:37:32184 std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
Scott Violetbb6c84552020-01-29 23:35:24185 Tab* tab = browser->AddTab(Tab::Create(GetProfile()));
Scott Violet87450ce2020-01-23 01:56:25186 const GURL url = embedded_test_server()->GetURL("/simple_page.html");
Scott Violetbb6c84552020-01-29 23:35:24187 NavigateAndWaitForCompletion(url, tab);
Scott Violet9843d0a2020-02-11 22:38:07188 ShutdownBrowserPersisterAndWait(browser.get());
Scott Violetbb6c84552020-01-29 23:35:24189 tab = nullptr;
Scott Violet87450ce2020-01-23 01:56:25190 browser.reset();
191
Scott Violetbf8b8aa72020-01-28 19:37:32192 browser = CreateBrowser(GetProfile(), "x");
Scott Violet87450ce2020-01-23 01:56:25193 // Should be no tabs while waiting for restore.
194 EXPECT_TRUE(browser->GetTabs().empty());
195 // Wait for the restore and navigation to complete.
196 BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
197 browser.get(), url);
198
199 ASSERT_EQ(1u, browser->GetTabs().size());
200 EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
201 EXPECT_EQ(1, browser->GetTabs()[0]
202 ->GetNavigationController()
203 ->GetNavigationListSize());
204}
205
Scott Violet9843d0a2020-02-11 22:38:07206IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) {
Scott Violet87450ce2020-01-23 01:56:25207 ASSERT_TRUE(embedded_test_server()->Start());
208
Scott Violetbf8b8aa72020-01-28 19:37:32209 std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
Scott Violetbb6c84552020-01-29 23:35:24210 Tab* tab1 = browser->AddTab(Tab::Create(GetProfile()));
Scott Violet87450ce2020-01-23 01:56:25211 const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
Scott Violetbb6c84552020-01-29 23:35:24212 NavigateAndWaitForCompletion(url1, tab1);
Scott Violet87450ce2020-01-23 01:56:25213
Scott Violetbb6c84552020-01-29 23:35:24214 Tab* tab2 = browser->AddTab(Tab::Create(GetProfile()));
Scott Violet87450ce2020-01-23 01:56:25215 const GURL url2 = embedded_test_server()->GetURL("/simple_page2.html");
Scott Violetbb6c84552020-01-29 23:35:24216 NavigateAndWaitForCompletion(url2, tab2);
217 browser->SetActiveTab(tab2);
Scott Violet87450ce2020-01-23 01:56:25218
Colin Blundellbe1dc132020-01-29 09:54:06219 // Shut down the service.
Scott Violet9843d0a2020-02-11 22:38:07220 ShutdownBrowserPersisterAndWait(browser.get());
Scott Violetbb6c84552020-01-29 23:35:24221 tab1 = tab2 = nullptr;
Colin Blundellbe1dc132020-01-29 09:54:06222 browser.reset();
223
224 // Recreate the browser and run the assertions twice to ensure we handle
Scott Violet87450ce2020-01-23 01:56:25225 // correctly storing state of tabs that need to be reloaded.
226 for (int i = 0; i < 2; ++i) {
Scott Violetbf8b8aa72020-01-28 19:37:32227 browser = CreateBrowser(GetProfile(), "x");
Scott Violet87450ce2020-01-23 01:56:25228 // Should be no tabs while waiting for restore.
229 EXPECT_TRUE(browser->GetTabs().empty()) << "iteration " << i;
230 // Wait for the restore and navigation to complete. This waits for the
231 // second tab as that was the active one.
232 BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
233 browser.get(), url2, 2);
234
235 ASSERT_EQ(2u, browser->GetTabs().size()) << "iteration " << i;
236 // The first tab shouldn't have loaded yet, as it's not active.
237 EXPECT_TRUE(static_cast<TabImpl*>(browser->GetTabs()[0])
238 ->web_contents()
239 ->GetController()
240 .NeedsReload())
241 << "iteration " << i;
242 EXPECT_EQ(browser->GetTabs()[1], browser->GetActiveTab())
243 << "iteration " << i;
244 EXPECT_EQ(1, browser->GetTabs()[1]
245 ->GetNavigationController()
246 ->GetNavigationListSize())
247 << "iteration " << i;
Colin Blundellbe1dc132020-01-29 09:54:06248
Scott Violet9843d0a2020-02-11 22:38:07249 ShutdownBrowserPersisterAndWait(browser.get());
Scott Violet87450ce2020-01-23 01:56:25250 }
251}
252
Scott Violet9843d0a2020-02-11 22:38:07253IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) {
Scott Violet87450ce2020-01-23 01:56:25254 ASSERT_TRUE(embedded_test_server()->Start());
255
256 // Create a browser with two tabs.
Scott Violetbf8b8aa72020-01-28 19:37:32257 std::unique_ptr<BrowserImpl> browser1 = CreateBrowser(GetProfile(), "x");
Scott Violetbb6c84552020-01-29 23:35:24258 Tab* tab1 = browser1->AddTab(Tab::Create(GetProfile()));
Scott Violet87450ce2020-01-23 01:56:25259 const GURL url1 = embedded_test_server()->GetURL("/simple_page.html");
Scott Violetbb6c84552020-01-29 23:35:24260 NavigateAndWaitForCompletion(url1, tab1);
Scott Violet87450ce2020-01-23 01:56:25261
Scott Violetbb6c84552020-01-29 23:35:24262 Tab* tab2 = browser1->AddTab(Tab::Create(GetProfile()));
Scott Violet87450ce2020-01-23 01:56:25263 const GURL url2 = embedded_test_server()->GetURL("/simple_page2.html");
Scott Violetbb6c84552020-01-29 23:35:24264 NavigateAndWaitForCompletion(url2, tab2);
265 browser1->SetActiveTab(tab2);
Scott Violet87450ce2020-01-23 01:56:25266
267 // Create another browser with a single tab.
Scott Violetbf8b8aa72020-01-28 19:37:32268 std::unique_ptr<BrowserImpl> browser2 = CreateBrowser(GetProfile(), "y");
Scott Violetbb6c84552020-01-29 23:35:24269 Tab* tab3 = browser2->AddTab(Tab::Create(GetProfile()));
Scott Violet87450ce2020-01-23 01:56:25270 const GURL url3 = embedded_test_server()->GetURL("/simple_page3.html");
Scott Violetbb6c84552020-01-29 23:35:24271 NavigateAndWaitForCompletion(url3, tab3);
Scott Violet87450ce2020-01-23 01:56:25272
273 // Move |tab2| to |browser2|.
Scott Violetbb6c84552020-01-29 23:35:24274 browser2->AddTab(browser1->RemoveTab(tab2));
275 browser2->SetActiveTab(tab2);
Scott Violet87450ce2020-01-23 01:56:25276
Scott Violet9843d0a2020-02-11 22:38:07277 ShutdownBrowserPersisterAndWait(browser1.get());
278 ShutdownBrowserPersisterAndWait(browser2.get());
Scott Violetbb6c84552020-01-29 23:35:24279 tab1 = nullptr;
Scott Violet87450ce2020-01-23 01:56:25280 browser1.reset();
281
Scott Violetbb6c84552020-01-29 23:35:24282 tab2 = tab3 = nullptr;
Scott Violet87450ce2020-01-23 01:56:25283 browser2.reset();
284
285 // Restore the browsers.
Scott Violetbf8b8aa72020-01-28 19:37:32286 browser1 = CreateBrowser(GetProfile(), "x");
Scott Violet87450ce2020-01-23 01:56:25287 BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
288 browser1.get(), url1, 1);
289 ASSERT_EQ(1u, browser1->GetTabs().size());
290 EXPECT_EQ(1, browser1->GetTabs()[0]
291 ->GetNavigationController()
292 ->GetNavigationListSize());
293
Scott Violetbf8b8aa72020-01-28 19:37:32294 browser2 = CreateBrowser(GetProfile(), "y");
Scott Violet87450ce2020-01-23 01:56:25295 BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
296 browser2.get(), url2, 2);
297 ASSERT_EQ(2u, browser2->GetTabs().size());
298 EXPECT_EQ(1, browser2->GetTabs()[1]
299 ->GetNavigationController()
300 ->GetNavigationListSize());
301
302 // As |tab3| isn't active it needs to be loaded. Force that now.
303 TabImpl* restored_tab_3 = static_cast<TabImpl*>(browser2->GetTabs()[0]);
304 EXPECT_TRUE(restored_tab_3->web_contents()->GetController().NeedsReload());
305 restored_tab_3->web_contents()->GetController().LoadIfNecessary();
306 content::WaitForLoadStop(restored_tab_3->web_contents());
Scott Violet87450ce2020-01-23 01:56:25307}
308
309} // namespace weblayer