1 // Copyright 2016 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 
5 #include "chrome/browser/offline_pages/background_loader_offliner.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/run_loop.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "chrome/browser/net/prediction_options.h"
18 #include "chrome/browser/offline_pages/offliner_helper.h"
19 #include "chrome/browser/previews/previews_ui_tab_helper.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "components/content_settings/core/browser/cookie_settings.h"
23 #include "components/content_settings/core/common/pref_names.h"
24 #include "components/offline_pages/content/background_loader/background_loader_contents_stub.h"
25 #include "components/offline_pages/core/background/load_termination_listener.h"
26 #include "components/offline_pages/core/background/offliner.h"
27 #include "components/offline_pages/core/background/offliner_policy.h"
28 #include "components/offline_pages/core/background/save_page_request.h"
29 #include "components/offline_pages/core/offline_page_feature.h"
30 #include "components/offline_pages/core/stub_offline_page_model.h"
31 #include "components/prefs/pref_service.h"
32 #include "components/previews/content/previews_user_data.h"
33 #include "components/security_state/core/security_state.h"
34 #include "content/public/browser/mhtml_extra_parts.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/test/browser_task_environment.h"
37 #include "content/public/test/mock_navigation_handle.h"
38 #include "content/public/test/test_renderer_host.h"
39 #include "content/public/test/web_contents_tester.h"
40 #include "net/base/net_errors.h"
41 #include "net/http/http_response_headers.h"
42 #include "net/test/cert_test_util.h"
43 #include "net/test/test_data_directory.h"
44 #include "testing/gtest/include/gtest/gtest.h"
45 
46 namespace {
47 char kShortSnapshotDelayForTest[] =
48     "short-offline-page-snapshot-delay-for-test";
49 }  // namespace
50 
51 namespace offline_pages {
52 
53 namespace {
54 
55 using security_state::VisibleSecurityState;
56 
57 const int64_t kRequestId = 7;
58 const ClientId kClientId("async_loading", "88");
59 const bool kUserRequested = true;
60 const char kRequestOrigin[] = "abc.xyz";
61 
62 // TODO(https://crbug.com/1042727): Fix test GURL scoping and remove this getter
63 // function.
HttpUrl()64 GURL HttpUrl() {
65   return GURL("http://www.tunafish.com");
66 }
HttpsUrl()67 GURL HttpsUrl() {
68   return GURL("https://www.yellowtail.com");
69 }
FileUrl()70 GURL FileUrl() {
71   return GURL("file://salmon.png");
72 }
73 
74 class TestLoadTerminationListener : public LoadTerminationListener {
75  public:
76   TestLoadTerminationListener() = default;
77   ~TestLoadTerminationListener() override = default;
78 
TerminateLoad()79   void TerminateLoad() { offliner()->TerminateLoadIfInProgress(); }
80 
offliner()81   Offliner* offliner() { return offliner_; }
82 
83  private:
84   DISALLOW_COPY_AND_ASSIGN(TestLoadTerminationListener);
85 };
86 
87 // Mock OfflinePageModel for testing the SavePage calls
88 class MockOfflinePageModel : public StubOfflinePageModel {
89  public:
MockOfflinePageModel()90   MockOfflinePageModel() : mock_saving_(false), mock_deleting_(false) {}
~MockOfflinePageModel()91   ~MockOfflinePageModel() override {}
92 
SavePage(const SavePageParams & save_page_params,std::unique_ptr<OfflinePageArchiver> archiver,content::WebContents * web_contents,SavePageCallback callback)93   void SavePage(const SavePageParams& save_page_params,
94                 std::unique_ptr<OfflinePageArchiver> archiver,
95                 content::WebContents* web_contents,
96                 SavePageCallback callback) override {
97     mock_saving_ = true;
98     save_page_callback_ = std::move(callback);
99     save_page_params_ = save_page_params;
100   }
101 
CompleteSavingAsArchiveCreationFailed()102   void CompleteSavingAsArchiveCreationFailed() {
103     DCHECK(mock_saving_);
104     mock_saving_ = false;
105     base::ThreadTaskRunnerHandle::Get()->PostTask(
106         FROM_HERE, base::BindOnce(std::move(save_page_callback_),
107                                   SavePageResult::ARCHIVE_CREATION_FAILED, 0));
108   }
109 
CompleteSavingAsSuccess()110   void CompleteSavingAsSuccess() {
111     DCHECK(mock_saving_);
112     mock_saving_ = false;
113     base::ThreadTaskRunnerHandle::Get()->PostTask(
114         FROM_HERE, base::BindOnce(std::move(save_page_callback_),
115                                   SavePageResult::SUCCESS, 123456));
116   }
117 
CompleteSavingAsAlreadyExists()118   void CompleteSavingAsAlreadyExists() {
119     DCHECK(mock_saving_);
120     mock_saving_ = false;
121     base::ThreadTaskRunnerHandle::Get()->PostTask(
122         FROM_HERE, base::BindOnce(std::move(save_page_callback_),
123                                   SavePageResult::ALREADY_EXISTS, 123456));
124   }
125 
DeletePagesWithCriteria(const PageCriteria & criteria,DeletePageCallback callback)126   void DeletePagesWithCriteria(const PageCriteria& criteria,
127                                DeletePageCallback callback) override {
128     mock_deleting_ = true;
129     std::move(callback).Run(DeletePageResult::SUCCESS);
130   }
131 
mock_saving() const132   bool mock_saving() const { return mock_saving_; }
mock_deleting() const133   bool mock_deleting() const { return mock_deleting_; }
save_page_params()134   SavePageParams& save_page_params() { return save_page_params_; }
135 
136  private:
137   bool mock_saving_;
138   bool mock_deleting_;
139   SavePageCallback save_page_callback_;
140   SavePageParams save_page_params_;
141 
142   DISALLOW_COPY_AND_ASSIGN(MockOfflinePageModel);
143 };
144 
145 }  // namespace
146 
147 // A BackgroundLoader that we can run tests on.
148 // Overrides the ResetState so we don't actually try to create any web contents.
149 // This is a temporary solution to test core BackgroundLoaderOffliner
150 // functionality until we straighten out assumptions made by RequestCoordinator
151 // so that the ResetState method is no longer needed.
152 class TestBackgroundLoaderOffliner : public BackgroundLoaderOffliner {
153  public:
154   explicit TestBackgroundLoaderOffliner(
155       content::BrowserContext* browser_context,
156       const OfflinerPolicy* policy,
157       OfflinePageModel* offline_page_model,
158       std::unique_ptr<LoadTerminationListener> load_termination_listener);
159   ~TestBackgroundLoaderOffliner() override;
web_contents_tester()160   content::WebContentsTester* web_contents_tester() {
161     return content::WebContentsTester::For(stub_->web_contents());
162   }
163 
web_contents()164   content::WebContents* web_contents() { return stub_->web_contents(); }
stub()165   background_loader::BackgroundLoaderContents* stub() { return stub_; }
166 
is_loading()167   bool is_loading() { return loader_ && stub_->is_loading(); }
168 
set_custom_visible_security_state(std::unique_ptr<VisibleSecurityState> visible_security_state)169   void set_custom_visible_security_state(
170       std::unique_ptr<VisibleSecurityState> visible_security_state) {
171     custom_visible_security_state_ = std::move(visible_security_state);
172   }
set_page_type(content::PageType page_type)173   void set_page_type(content::PageType page_type) { page_type_ = page_type; }
174 
175  private:
176   // BackgroundLoaderOffliner overrides.
177   void ResetLoader() override;
178   std::unique_ptr<VisibleSecurityState> GetVisibleSecurityState(
179       content::WebContents* web_contents) override;
180   content::PageType GetPageType(content::WebContents* web_contents) override;
181 
182   background_loader::BackgroundLoaderContentsStub* stub_;
183   std::unique_ptr<VisibleSecurityState> custom_visible_security_state_;
184   content::PageType page_type_ = content::PageType::PAGE_TYPE_NORMAL;
185 };
186 
TestBackgroundLoaderOffliner(content::BrowserContext * browser_context,const OfflinerPolicy * policy,OfflinePageModel * offline_page_model,std::unique_ptr<LoadTerminationListener> load_termination_listener)187 TestBackgroundLoaderOffliner::TestBackgroundLoaderOffliner(
188     content::BrowserContext* browser_context,
189     const OfflinerPolicy* policy,
190     OfflinePageModel* offline_page_model,
191     std::unique_ptr<LoadTerminationListener> load_termination_listener)
192     : BackgroundLoaderOffliner(browser_context,
193                                policy,
194                                offline_page_model,
195                                std::move(load_termination_listener)) {}
196 
~TestBackgroundLoaderOffliner()197 TestBackgroundLoaderOffliner::~TestBackgroundLoaderOffliner() {}
198 
ResetLoader()199 void TestBackgroundLoaderOffliner::ResetLoader() {
200   stub_ = new background_loader::BackgroundLoaderContentsStub(browser_context_);
201   loader_.reset(stub_);
202   loader_->SetDelegate(this);
203 }
204 
205 std::unique_ptr<VisibleSecurityState>
GetVisibleSecurityState(content::WebContents * web_contents)206 TestBackgroundLoaderOffliner::GetVisibleSecurityState(
207     content::WebContents* web_contents) {
208   if (custom_visible_security_state_)
209     return std::move(custom_visible_security_state_);
210   return BackgroundLoaderOffliner::GetVisibleSecurityState(web_contents);
211 }
212 
GetPageType(content::WebContents * web_contents)213 content::PageType TestBackgroundLoaderOffliner::GetPageType(
214     content::WebContents* web_contents) {
215   return page_type_;
216 }
217 
218 class BackgroundLoaderOfflinerTest : public testing::Test {
219  public:
220   BackgroundLoaderOfflinerTest();
221   ~BackgroundLoaderOfflinerTest() override;
222 
223   void SetUp() override;
224 
offliner() const225   TestBackgroundLoaderOffliner* offliner() const { return offliner_.get(); }
completion_callback()226   Offliner::CompletionCallback completion_callback() {
227     return base::BindOnce(&BackgroundLoaderOfflinerTest::OnCompletion,
228                           base::Unretained(this));
229   }
progress_callback()230   Offliner::ProgressCallback const progress_callback() {
231     return base::BindRepeating(&BackgroundLoaderOfflinerTest::OnProgress,
232                                base::Unretained(this));
233   }
cancel_callback()234   Offliner::CancelCallback cancel_callback() {
235     return base::BindOnce(&BackgroundLoaderOfflinerTest::OnCancel,
236                           base::Unretained(this));
237   }
can_download_callback()238   base::OnceCallback<void(bool)> can_download_callback() {
239     return base::BindOnce(&BackgroundLoaderOfflinerTest::OnCanDownload,
240                           base::Unretained(this));
241   }
profile()242   Profile* profile() { return &profile_; }
completion_callback_called()243   bool completion_callback_called() { return completion_callback_called_; }
request_status()244   Offliner::RequestStatus request_status() { return request_status_; }
cancel_callback_called()245   bool cancel_callback_called() { return cancel_callback_called_; }
can_download_callback_called()246   bool can_download_callback_called() { return can_download_callback_called_; }
can_download()247   bool can_download() { return can_download_; }
SaveInProgress() const248   bool SaveInProgress() const { return model_->mock_saving(); }
DeleteCalled() const249   bool DeleteCalled() const { return model_->mock_deleting(); }
model() const250   MockOfflinePageModel* model() const { return model_; }
histograms() const251   const base::HistogramTester& histograms() const { return histogram_tester_; }
progress()252   int64_t progress() { return progress_; }
policy() const253   OfflinerPolicy* policy() const { return policy_.get(); }
load_termination_listener()254   TestLoadTerminationListener* load_termination_listener() {
255     return load_termination_listener_;
256   }
257 
PumpLoop()258   void PumpLoop() { base::RunLoop().RunUntilIdle(); }
259 
CompleteLoading()260   void CompleteLoading() {
261     // Reset snapshot controller.
262     std::unique_ptr<BackgroundSnapshotController> snapshot_controller(
263         new BackgroundSnapshotController(base::ThreadTaskRunnerHandle::Get(),
264                                          offliner_.get(),
265                                          false /* RenovationsEnabled */));
266     offliner_->SetBackgroundSnapshotControllerForTest(
267         std::move(snapshot_controller));
268     // Call complete loading.
269     offliner()->DocumentAvailableInMainFrame();
270     offliner()->DocumentOnLoadCompletedInMainFrame();
271     PumpLoop();
272   }
273 
GetRequestStats()274   offline_pages::RequestStats* GetRequestStats() {
275     return offliner_->GetRequestStatsForTest();
276   }
277 
BaseVisibleSecurityState()278   std::unique_ptr<VisibleSecurityState> BaseVisibleSecurityState() {
279     auto visible_security_state = std::make_unique<VisibleSecurityState>();
280     visible_security_state->connection_info_initialized = true;
281     visible_security_state->url = HttpsUrl();
282     visible_security_state->certificate =
283         net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_2016.pem");
284     visible_security_state->cert_status =
285         net::CERT_STATUS_SHA1_SIGNATURE_PRESENT;
286     return visible_security_state;
287   }
288 
289  private:
290   void OnCompletion(const SavePageRequest& request,
291                     Offliner::RequestStatus status);
292   void OnProgress(const SavePageRequest& request, int64_t bytes);
293   void OnCancel(const SavePageRequest& request);
294   void OnCanDownload(bool allowed);
295   content::BrowserTaskEnvironment task_environment_;
296   content::RenderViewHostTestEnabler rvhte_;
297   TestingProfile profile_;
298   std::unique_ptr<OfflinerPolicy> policy_;
299   TestLoadTerminationListener* load_termination_listener_;
300   std::unique_ptr<TestBackgroundLoaderOffliner> offliner_;
301   MockOfflinePageModel* model_;
302   bool completion_callback_called_;
303   bool cancel_callback_called_;
304   bool can_download_callback_called_;
305   bool can_download_;
306   int64_t progress_;
307   Offliner::RequestStatus request_status_;
308   base::HistogramTester histogram_tester_;
309 
310   DISALLOW_COPY_AND_ASSIGN(BackgroundLoaderOfflinerTest);
311 };
312 
BackgroundLoaderOfflinerTest()313 BackgroundLoaderOfflinerTest::BackgroundLoaderOfflinerTest()
314     : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
315       load_termination_listener_(nullptr),
316       model_(nullptr),
317       completion_callback_called_(false),
318       cancel_callback_called_(false),
319       can_download_callback_called_(false),
320       can_download_(false),
321       progress_(0LL),
322       request_status_(Offliner::RequestStatus::UNKNOWN) {}
323 
~BackgroundLoaderOfflinerTest()324 BackgroundLoaderOfflinerTest::~BackgroundLoaderOfflinerTest() {}
325 
SetUp()326 void BackgroundLoaderOfflinerTest::SetUp() {
327   // Set the snapshot controller delay command line switch to short delays.
328   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
329   cl->AppendSwitch(kShortSnapshotDelayForTest);
330 
331   std::unique_ptr<TestLoadTerminationListener> listener =
332       std::make_unique<TestLoadTerminationListener>();
333   load_termination_listener_ = listener.get();
334   model_ = new MockOfflinePageModel();
335   policy_.reset(new OfflinerPolicy());
336   offliner_.reset(new TestBackgroundLoaderOffliner(
337       profile(), policy_.get(), model_, std::move(listener)));
338 }
339 
OnCompletion(const SavePageRequest & request,Offliner::RequestStatus status)340 void BackgroundLoaderOfflinerTest::OnCompletion(
341     const SavePageRequest& request,
342     Offliner::RequestStatus status) {
343   DCHECK(!completion_callback_called_);  // Expect 1 callback per request.
344   completion_callback_called_ = true;
345   request_status_ = status;
346 }
347 
OnProgress(const SavePageRequest & request,int64_t bytes)348 void BackgroundLoaderOfflinerTest::OnProgress(const SavePageRequest& request,
349                                               int64_t bytes) {
350   progress_ = bytes;
351 }
352 
OnCancel(const SavePageRequest & request)353 void BackgroundLoaderOfflinerTest::OnCancel(const SavePageRequest& request) {
354   DCHECK(!cancel_callback_called_);
355   cancel_callback_called_ = true;
356 }
357 
OnCanDownload(bool allowed)358 void BackgroundLoaderOfflinerTest::OnCanDownload(bool allowed) {
359   can_download_callback_called_ = true;
360   can_download_ = allowed;
361 }
362 
TEST_F(BackgroundLoaderOfflinerTest,LoadTerminationListenerSetup)363 TEST_F(BackgroundLoaderOfflinerTest, LoadTerminationListenerSetup) {
364   // Verify that back pointer to offliner is set up in the listener.
365   Offliner* base_offliner = offliner();
366   EXPECT_NE(base_offliner, nullptr);
367   EXPECT_EQ(base_offliner, load_termination_listener()->offliner());
368 }
369 
TEST_F(BackgroundLoaderOfflinerTest,LoadAndSaveBlockThirdPartyCookiesForCustomTabs)370 TEST_F(BackgroundLoaderOfflinerTest,
371        LoadAndSaveBlockThirdPartyCookiesForCustomTabs) {
372   base::Time creation_time = base::Time::Now();
373   ClientId custom_tabs_client_id("custom_tabs", "88");
374   SavePageRequest request(kRequestId, HttpUrl(), custom_tabs_client_id,
375                           creation_time, kUserRequested);
376 
377   profile()->GetPrefs()->SetInteger(
378       prefs::kCookieControlsMode,
379       static_cast<int>(content_settings::CookieControlsMode::kBlockThirdParty));
380   EXPECT_FALSE(offliner()->LoadAndSave(request, completion_callback(),
381                                        progress_callback()));
382 }
383 
TEST_F(BackgroundLoaderOfflinerTest,LoadAndSaveNetworkPredictionDisabledForCustomTabs)384 TEST_F(BackgroundLoaderOfflinerTest,
385        LoadAndSaveNetworkPredictionDisabledForCustomTabs) {
386   base::Time creation_time = base::Time::Now();
387   ClientId custom_tabs_client_id("custom_tabs", "88");
388   SavePageRequest request(kRequestId, HttpUrl(), custom_tabs_client_id,
389                           creation_time, kUserRequested);
390 
391   profile()->GetPrefs()->SetInteger(
392       prefs::kNetworkPredictionOptions,
393       chrome_browser_net::NETWORK_PREDICTION_NEVER);
394   EXPECT_FALSE(offliner()->LoadAndSave(request, completion_callback(),
395                                        progress_callback()));
396 }
397 
TEST_F(BackgroundLoaderOfflinerTest,LoadAndSaveStartsLoading)398 TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveStartsLoading) {
399   base::Time creation_time = base::Time::Now();
400   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
401                           kUserRequested);
402   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
403                                       progress_callback()));
404   EXPECT_TRUE(offliner()->is_loading());
405   EXPECT_FALSE(SaveInProgress());
406   EXPECT_FALSE(completion_callback_called());
407   EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
408 }
409 
TEST_F(BackgroundLoaderOfflinerTest,BytesReportedWillUpdateProgress)410 TEST_F(BackgroundLoaderOfflinerTest, BytesReportedWillUpdateProgress) {
411   base::Time creation_time = base::Time::Now();
412   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
413                           kUserRequested);
414   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
415                                       progress_callback()));
416   offliner()->OnNetworkBytesChanged(5LL);
417   EXPECT_EQ(progress(), 5LL);
418   offliner()->OnNetworkBytesChanged(10LL);
419   EXPECT_EQ(progress(), 15LL);
420 }
421 
TEST_F(BackgroundLoaderOfflinerTest,CompleteLoadingInitiatesSave)422 TEST_F(BackgroundLoaderOfflinerTest, CompleteLoadingInitiatesSave) {
423   base::Time creation_time = base::Time::Now();
424   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
425                           kUserRequested);
426   request.set_request_origin(kRequestOrigin);
427   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
428                                       progress_callback()));
429   CompleteLoading();
430   PumpLoop();
431   // Verify that request origin is propagated.
432   EXPECT_EQ(kRequestOrigin, model()->save_page_params().request_origin);
433   EXPECT_FALSE(completion_callback_called());
434   EXPECT_TRUE(SaveInProgress());
435   EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
436 }
437 
TEST_F(BackgroundLoaderOfflinerTest,CancelWhenLoading)438 TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoading) {
439   base::Time creation_time = base::Time::Now();
440   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
441                           kUserRequested);
442   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
443                                       progress_callback()));
444   offliner()->Cancel(cancel_callback());
445   PumpLoop();
446   offliner()->OnNetworkBytesChanged(15LL);
447   EXPECT_TRUE(cancel_callback_called());
448   EXPECT_FALSE(completion_callback_called());
449   EXPECT_FALSE(offliner()->is_loading());  // Offliner reset.
450   EXPECT_EQ(progress(), 0LL);  // network bytes not recorded when not busy.
451 }
452 
TEST_F(BackgroundLoaderOfflinerTest,CancelWhenLoadTerminated)453 TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoadTerminated) {
454   base::Time creation_time = base::Time::Now();
455   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
456                           kUserRequested);
457   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
458                                       progress_callback()));
459   load_termination_listener()->TerminateLoad();
460   PumpLoop();
461   EXPECT_TRUE(completion_callback_called());
462   EXPECT_FALSE(offliner()->is_loading());  // Offliner reset.
463   EXPECT_EQ(Offliner::RequestStatus::FOREGROUND_CANCELED, request_status());
464 }
465 
TEST_F(BackgroundLoaderOfflinerTest,CancelWhenLoaded)466 TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoaded) {
467   base::Time creation_time = base::Time::Now();
468   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
469                           kUserRequested);
470   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
471                                       progress_callback()));
472   CompleteLoading();
473   PumpLoop();
474   offliner()->Cancel(cancel_callback());
475   PumpLoop();
476 
477   // Subsequent save callback cause no crash.
478   model()->CompleteSavingAsArchiveCreationFailed();
479   PumpLoop();
480   EXPECT_TRUE(cancel_callback_called());
481   EXPECT_TRUE(DeleteCalled());
482   EXPECT_FALSE(completion_callback_called());
483   EXPECT_FALSE(SaveInProgress());
484   EXPECT_FALSE(offliner()->is_loading());  // Offliner reset.
485 }
486 
TEST_F(BackgroundLoaderOfflinerTest,LoadedButSaveFails)487 TEST_F(BackgroundLoaderOfflinerTest, LoadedButSaveFails) {
488   base::Time creation_time = base::Time::Now();
489   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
490                           kUserRequested);
491   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
492                                       progress_callback()));
493 
494   CompleteLoading();
495   PumpLoop();
496   model()->CompleteSavingAsArchiveCreationFailed();
497   PumpLoop();
498 
499   EXPECT_TRUE(completion_callback_called());
500   EXPECT_EQ(Offliner::RequestStatus::SAVE_FAILED, request_status());
501   EXPECT_FALSE(offliner()->is_loading());
502   EXPECT_FALSE(SaveInProgress());
503 }
504 
TEST_F(BackgroundLoaderOfflinerTest,ProgressDoesNotUpdateDuringSave)505 TEST_F(BackgroundLoaderOfflinerTest, ProgressDoesNotUpdateDuringSave) {
506   base::Time creation_time = base::Time::Now();
507   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
508                           kUserRequested);
509   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
510                                       progress_callback()));
511   offliner()->OnNetworkBytesChanged(10LL);
512   CompleteLoading();
513   PumpLoop();
514   offliner()->OnNetworkBytesChanged(15LL);
515   EXPECT_EQ(progress(), 10LL);
516 }
517 
TEST_F(BackgroundLoaderOfflinerTest,LoadAndSaveSuccess)518 TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveSuccess) {
519   base::Time creation_time = base::Time::Now();
520   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
521                           kUserRequested);
522   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
523                                       progress_callback()));
524 
525   CompleteLoading();
526   PumpLoop();
527   model()->CompleteSavingAsSuccess();
528   PumpLoop();
529 
530   EXPECT_TRUE(completion_callback_called());
531   EXPECT_EQ(Offliner::RequestStatus::SAVED, request_status());
532   EXPECT_FALSE(offliner()->is_loading());
533   EXPECT_FALSE(can_download_callback_called());
534   EXPECT_FALSE(SaveInProgress());
535 }
536 
TEST_F(BackgroundLoaderOfflinerTest,LoadAndSaveAlreadyExists)537 TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveAlreadyExists) {
538   base::Time creation_time = base::Time::Now();
539   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
540                           kUserRequested);
541   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
542                                       progress_callback()));
543 
544   CompleteLoading();
545   PumpLoop();
546   model()->CompleteSavingAsAlreadyExists();
547   PumpLoop();
548 
549   EXPECT_TRUE(completion_callback_called());
550   EXPECT_EQ(Offliner::RequestStatus::SAVED, request_status());
551   EXPECT_FALSE(offliner()->is_loading());
552   EXPECT_FALSE(SaveInProgress());
553 }
554 
TEST_F(BackgroundLoaderOfflinerTest,ResetsWhenDownloadStarts)555 TEST_F(BackgroundLoaderOfflinerTest, ResetsWhenDownloadStarts) {
556   base::Time creation_time = base::Time::Now();
557   ClientId browser_actions("browser_actions", "123");
558   SavePageRequest request(kRequestId, HttpUrl(), browser_actions, creation_time,
559                           kUserRequested);
560   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
561                                       progress_callback()));
562   offliner()->stub()->CanDownload(HttpUrl(), "foo", can_download_callback());
563   PumpLoop();
564   EXPECT_TRUE(can_download_callback_called());
565   EXPECT_TRUE(can_download());
566   EXPECT_TRUE(completion_callback_called());
567   EXPECT_EQ(Offliner::RequestStatus::DOWNLOAD_THROTTLED, request_status());
568 }
569 
TEST_F(BackgroundLoaderOfflinerTest,ResetsWhenDownloadEncountered)570 TEST_F(BackgroundLoaderOfflinerTest, ResetsWhenDownloadEncountered) {
571   base::Time creation_time = base::Time::Now();
572   ClientId prefetching("suggested_articles", "123");
573   SavePageRequest request(kRequestId, HttpUrl(), prefetching, creation_time,
574                           kUserRequested);
575   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
576                                       progress_callback()));
577   offliner()->stub()->CanDownload(HttpUrl(), "foo", can_download_callback());
578   PumpLoop();
579   EXPECT_TRUE(can_download_callback_called());
580   EXPECT_FALSE(can_download());
581   EXPECT_TRUE(completion_callback_called());
582   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED_DOWNLOAD, request_status());
583 }
584 
TEST_F(BackgroundLoaderOfflinerTest,CanDownloadReturnsIfNoPendingRequest)585 TEST_F(BackgroundLoaderOfflinerTest, CanDownloadReturnsIfNoPendingRequest) {
586   offliner()->CanDownload(can_download_callback());
587   PumpLoop();
588   EXPECT_TRUE(can_download_callback_called());
589   EXPECT_FALSE(can_download());
590 }
591 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnInvalidURL)592 TEST_F(BackgroundLoaderOfflinerTest, FailsOnInvalidURL) {
593   base::Time creation_time = base::Time::Now();
594   SavePageRequest request(kRequestId, FileUrl(), kClientId, creation_time,
595                           kUserRequested);
596   EXPECT_FALSE(offliner()->LoadAndSave(request, completion_callback(),
597                                        progress_callback()));
598 }
599 
TEST_F(BackgroundLoaderOfflinerTest,ReturnsOnRenderCrash)600 TEST_F(BackgroundLoaderOfflinerTest, ReturnsOnRenderCrash) {
601   base::Time creation_time = base::Time::Now();
602   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
603                           kUserRequested);
604   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
605                                       progress_callback()));
606   offliner()->RenderProcessGone(
607       base::TerminationStatus::TERMINATION_STATUS_PROCESS_CRASHED);
608 
609   EXPECT_TRUE(completion_callback_called());
610   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED_NO_NEXT, request_status());
611 }
612 
TEST_F(BackgroundLoaderOfflinerTest,ReturnsOnRenderKilled)613 TEST_F(BackgroundLoaderOfflinerTest, ReturnsOnRenderKilled) {
614   base::Time creation_time = base::Time::Now();
615   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
616                           kUserRequested);
617   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
618                                       progress_callback()));
619   offliner()->RenderProcessGone(
620       base::TerminationStatus::TERMINATION_STATUS_PROCESS_WAS_KILLED);
621 
622   EXPECT_TRUE(completion_callback_called());
623   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED, request_status());
624 }
625 
TEST_F(BackgroundLoaderOfflinerTest,ReturnsOnWebContentsDestroyed)626 TEST_F(BackgroundLoaderOfflinerTest, ReturnsOnWebContentsDestroyed) {
627   base::Time creation_time = base::Time::Now();
628   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
629                           kUserRequested);
630   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
631                                       progress_callback()));
632   offliner()->WebContentsDestroyed();
633 
634   EXPECT_TRUE(completion_callback_called());
635   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED, request_status());
636 }
637 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnErrorPage)638 TEST_F(BackgroundLoaderOfflinerTest, FailsOnErrorPage) {
639   base::Time creation_time = base::Time::Now();
640   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
641                           kUserRequested);
642   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
643                                       progress_callback()));
644   // Create handle with net error code.
645   // Called after calling LoadAndSave so we have web_contents to work with.
646   content::MockNavigationHandle handle(
647       HttpUrl(), offliner()->web_contents()->GetMainFrame());
648   handle.set_has_committed(true);
649   handle.set_is_error_page(true);
650   handle.set_net_error_code(net::Error::ERR_NAME_NOT_RESOLVED);
651   offliner()->DidFinishNavigation(&handle);
652 
653   histograms().ExpectBucketCount(
654       "OfflinePages.Background.LoadingErrorStatusCode.async_loading",
655       -105,  // ERR_NAME_NOT_RESOLVED
656       1);
657   CompleteLoading();
658   PumpLoop();
659 
660   EXPECT_TRUE(completion_callback_called());
661   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED_NET_ERROR,
662             request_status());
663 }
664 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnCertificateError)665 TEST_F(BackgroundLoaderOfflinerTest, FailsOnCertificateError) {
666   base::Time creation_time = base::Time::Now();
667   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
668                           kUserRequested);
669   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
670                                       progress_callback()));
671 
672   // Sets the certificate status as having been revoked.
673   std::unique_ptr<VisibleSecurityState> visible_security_state =
674       BaseVisibleSecurityState();
675   visible_security_state->cert_status |= net::CERT_STATUS_REVOKED;
676   offliner()->set_custom_visible_security_state(
677       std::move(visible_security_state));
678 
679   // Called after calling LoadAndSave so we have web_contents to work with.
680   content::MockNavigationHandle handle(
681       HttpUrl(), offliner()->web_contents()->GetMainFrame());
682   handle.set_has_committed(true);
683   offliner()->DidFinishNavigation(&handle);
684 
685   CompleteLoading();
686   PumpLoop();
687 
688   EXPECT_FALSE(SaveInProgress());
689   EXPECT_TRUE(completion_callback_called());
690   EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR,
691             request_status());
692 }
693 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnRevocationCheckingFailure)694 TEST_F(BackgroundLoaderOfflinerTest, FailsOnRevocationCheckingFailure) {
695   base::Time creation_time = base::Time::Now();
696   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
697                           kUserRequested);
698   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
699                                       progress_callback()));
700 
701   // Sets a revocation checking failure certificate error that should not be
702   // allowed.
703   std::unique_ptr<VisibleSecurityState> visible_security_state =
704       BaseVisibleSecurityState();
705   visible_security_state->cert_status |=
706       net::CERT_STATUS_NO_REVOCATION_MECHANISM;
707   offliner()->set_custom_visible_security_state(
708       std::move(visible_security_state));
709 
710   // Called after calling LoadAndSave so we have web_contents to work with.
711   content::MockNavigationHandle handle(
712       HttpUrl(), offliner()->web_contents()->GetMainFrame());
713   handle.set_has_committed(true);
714   offliner()->DidFinishNavigation(&handle);
715 
716   CompleteLoading();
717   PumpLoop();
718 
719   EXPECT_FALSE(SaveInProgress());
720   EXPECT_TRUE(completion_callback_called());
721   EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR,
722             request_status());
723 }
724 
TEST_F(BackgroundLoaderOfflinerTest,SucceedsOnHttp)725 TEST_F(BackgroundLoaderOfflinerTest, SucceedsOnHttp) {
726   base::Time creation_time = base::Time::Now();
727   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
728                           kUserRequested);
729   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
730                                       progress_callback()));
731 
732   // Sets the URL to HTTP while still setting a major certificate error (should
733   // be ignored).
734   std::unique_ptr<VisibleSecurityState> visible_security_state =
735       BaseVisibleSecurityState();
736   visible_security_state->url = HttpUrl();
737   visible_security_state->cert_status |= net::CERT_STATUS_REVOKED;
738   offliner()->set_custom_visible_security_state(
739       std::move(visible_security_state));
740 
741   // Called after calling LoadAndSave so we have web_contents to work with.
742   content::MockNavigationHandle handle(
743       HttpUrl(), offliner()->web_contents()->GetMainFrame());
744   handle.set_has_committed(true);
745   offliner()->DidFinishNavigation(&handle);
746 
747   CompleteLoading();
748   PumpLoop();
749 
750   EXPECT_TRUE(SaveInProgress());
751   EXPECT_FALSE(completion_callback_called());
752 }
753 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnUnwantedContent)754 TEST_F(BackgroundLoaderOfflinerTest, FailsOnUnwantedContent) {
755   base::Time creation_time = base::Time::Now();
756   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
757                           kUserRequested);
758   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
759                                       progress_callback()));
760 
761   // Sets the page as containing SafeBrowsing unwanted content.
762   std::unique_ptr<VisibleSecurityState> visible_security_state =
763       BaseVisibleSecurityState();
764   visible_security_state->malicious_content_status = security_state::
765       MaliciousContentStatus::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING;
766   offliner()->set_custom_visible_security_state(
767       std::move(visible_security_state));
768   // Called after calling LoadAndSave so we have web_contents to work with.
769   content::MockNavigationHandle handle(
770       HttpUrl(), offliner()->web_contents()->GetMainFrame());
771   handle.set_has_committed(true);
772   offliner()->DidFinishNavigation(&handle);
773 
774   CompleteLoading();
775   PumpLoop();
776 
777   EXPECT_FALSE(SaveInProgress());
778   EXPECT_TRUE(completion_callback_called());
779   EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_IS_BLOCKED, request_status());
780 }
781 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnInterstitialPage)782 TEST_F(BackgroundLoaderOfflinerTest, FailsOnInterstitialPage) {
783   base::Time creation_time = base::Time::Now();
784   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
785                           kUserRequested);
786   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
787                                       progress_callback()));
788 
789   // Sets the page as being an interstitial.
790   offliner()->set_page_type(content::PageType::PAGE_TYPE_INTERSTITIAL);
791   // Called after calling LoadAndSave so we have web_contents to work with.
792   content::MockNavigationHandle handle(
793       HttpUrl(), offliner()->web_contents()->GetMainFrame());
794   handle.set_has_committed(true);
795   offliner()->DidFinishNavigation(&handle);
796 
797   CompleteLoading();
798   PumpLoop();
799 
800   EXPECT_FALSE(SaveInProgress());
801   EXPECT_TRUE(completion_callback_called());
802   EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_IS_CHROME_INTERNAL,
803             request_status());
804 }
805 
TEST_F(BackgroundLoaderOfflinerTest,FailsOnInternetDisconnected)806 TEST_F(BackgroundLoaderOfflinerTest, FailsOnInternetDisconnected) {
807   base::Time creation_time = base::Time::Now();
808   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
809                           kUserRequested);
810   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
811                                       progress_callback()));
812 
813   // Create handle with net error code.
814   // Called after calling LoadAndSave so we have web_contents to work with.
815   content::MockNavigationHandle handle(
816       HttpUrl(), offliner()->web_contents()->GetMainFrame());
817   handle.set_has_committed(true);
818   handle.set_is_error_page(true);
819   handle.set_net_error_code(net::Error::ERR_INTERNET_DISCONNECTED);
820   offliner()->DidFinishNavigation(&handle);
821 
822   CompleteLoading();
823   PumpLoop();
824 
825   EXPECT_TRUE(completion_callback_called());
826   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED_NET_ERROR,
827             request_status());
828 }
829 
TEST_F(BackgroundLoaderOfflinerTest,DoesNotCrashWithNullResponseHeaders)830 TEST_F(BackgroundLoaderOfflinerTest, DoesNotCrashWithNullResponseHeaders) {
831   base::Time creation_time = base::Time::Now();
832   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
833                           kUserRequested);
834   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
835                                       progress_callback()));
836 
837   // Called after calling LoadAndSave so we have web_contents to work with.
838   content::MockNavigationHandle handle(
839       HttpUrl(), offliner()->web_contents()->GetMainFrame());
840   handle.set_has_committed(true);
841   offliner()->DidFinishNavigation(&handle);
842 }
843 
TEST_F(BackgroundLoaderOfflinerTest,OffliningPreviewsStatusOffHistogram)844 TEST_F(BackgroundLoaderOfflinerTest, OffliningPreviewsStatusOffHistogram) {
845   base::Time creation_time = base::Time::Now();
846   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
847                           kUserRequested);
848   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
849                                       progress_callback()));
850 
851   // Called after calling LoadAndSave so we have web_contents to work with.
852   content::MockNavigationHandle handle(
853       HttpUrl(), offliner()->web_contents()->GetMainFrame());
854   handle.set_has_committed(true);
855   // Set up PreviewsUserData on the handle.
856   PreviewsUITabHelper::CreateForWebContents(offliner()->web_contents());
857   PreviewsUITabHelper::FromWebContents(offliner()->web_contents())
858       ->CreatePreviewsUserDataForNavigationHandle(&handle, 1u)
859       ->set_committed_previews_state(
860           blink::PreviewsTypes::PREVIEWS_NO_TRANSFORM);
861   scoped_refptr<net::HttpResponseHeaders> header(
862       new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
863   handle.set_response_headers(header.get());
864   // Call DidFinishNavigation with handle.
865   offliner()->DidFinishNavigation(&handle);
866 
867   histograms().ExpectBucketCount(
868       "OfflinePages.Background.OffliningPreviewStatus.async_loading",
869       0,  // Previews Disabled
870       1);
871 }
872 
TEST_F(BackgroundLoaderOfflinerTest,OffliningPreviewsStatusOnHistogram)873 TEST_F(BackgroundLoaderOfflinerTest, OffliningPreviewsStatusOnHistogram) {
874   base::Time creation_time = base::Time::Now();
875   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
876                           kUserRequested);
877   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
878                                       progress_callback()));
879 
880   // Called after calling LoadAndSave so we have web_contents to work with.
881   content::MockNavigationHandle handle(
882       HttpUrl(), offliner()->web_contents()->GetMainFrame());
883   handle.set_has_committed(true);
884   // Set up PreviewsUserData on the handle.
885   PreviewsUITabHelper::CreateForWebContents(offliner()->web_contents());
886   PreviewsUITabHelper::FromWebContents(offliner()->web_contents())
887       ->CreatePreviewsUserDataForNavigationHandle(&handle, 1u)
888       ->set_committed_previews_state(blink::PreviewsTypes::NOSCRIPT_ON);
889   scoped_refptr<net::HttpResponseHeaders> header(
890       new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
891   handle.set_response_headers(header.get());
892 
893   // Call DidFinishNavigation with handle.
894   offliner()->DidFinishNavigation(&handle);
895 
896   histograms().ExpectBucketCount(
897       "OfflinePages.Background.OffliningPreviewStatus.async_loading",
898       1,  // Previews Enabled
899       1);
900 }
901 
TEST_F(BackgroundLoaderOfflinerTest,OnlySavesOnceOnMultipleLoads)902 TEST_F(BackgroundLoaderOfflinerTest, OnlySavesOnceOnMultipleLoads) {
903   base::Time creation_time = base::Time::Now();
904   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
905                           kUserRequested);
906   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
907                                       progress_callback()));
908   // First load
909   CompleteLoading();
910   // Second load
911   CompleteLoading();
912   PumpLoop();
913   model()->CompleteSavingAsSuccess();
914   PumpLoop();
915 
916   EXPECT_TRUE(completion_callback_called());
917   EXPECT_EQ(Offliner::RequestStatus::SAVED, request_status());
918   EXPECT_FALSE(offliner()->is_loading());
919   EXPECT_FALSE(SaveInProgress());
920 }
921 
TEST_F(BackgroundLoaderOfflinerTest,HandleTimeoutWithLowBarStartedTriesMet)922 TEST_F(BackgroundLoaderOfflinerTest, HandleTimeoutWithLowBarStartedTriesMet) {
923   base::Time creation_time = base::Time::Now();
924   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
925                           kUserRequested);
926   request.set_started_attempt_count(policy()->GetMaxStartedTries() - 1);
927   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
928                                       progress_callback()));
929   // Guarantees low bar for saving is met.
930   offliner()->DocumentAvailableInMainFrame();
931   // Timeout
932   EXPECT_TRUE(offliner()->HandleTimeout(kRequestId));
933   EXPECT_TRUE(SaveInProgress());
934   model()->CompleteSavingAsSuccess();
935   PumpLoop();
936   EXPECT_EQ(Offliner::RequestStatus::SAVED_ON_LAST_RETRY, request_status());
937 }
938 
TEST_F(BackgroundLoaderOfflinerTest,HandleTimeoutWithLowBarCompletedTriesMet)939 TEST_F(BackgroundLoaderOfflinerTest, HandleTimeoutWithLowBarCompletedTriesMet) {
940   base::Time creation_time = base::Time::Now();
941   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
942                           kUserRequested);
943   request.set_completed_attempt_count(policy()->GetMaxCompletedTries() - 1);
944   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
945                                       progress_callback()));
946   // Guarantees low bar for saving is met.
947   offliner()->DocumentAvailableInMainFrame();
948   // Timeout
949   EXPECT_TRUE(offliner()->HandleTimeout(kRequestId));
950   EXPECT_TRUE(SaveInProgress());
951   model()->CompleteSavingAsSuccess();
952   PumpLoop();
953   EXPECT_EQ(Offliner::RequestStatus::SAVED_ON_LAST_RETRY, request_status());
954 }
955 
TEST_F(BackgroundLoaderOfflinerTest,HandleTimeoutWithNoLowBarStartedTriesMet)956 TEST_F(BackgroundLoaderOfflinerTest, HandleTimeoutWithNoLowBarStartedTriesMet) {
957   base::Time creation_time = base::Time::Now();
958   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
959                           kUserRequested);
960   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
961                                       progress_callback()));
962   request.set_started_attempt_count(policy()->GetMaxStartedTries() - 1);
963   // Timeout
964   EXPECT_FALSE(offliner()->HandleTimeout(kRequestId));
965   EXPECT_FALSE(SaveInProgress());
966 }
967 
TEST_F(BackgroundLoaderOfflinerTest,HandleTimeoutWithNoLowBarCompletedTriesMet)968 TEST_F(BackgroundLoaderOfflinerTest,
969        HandleTimeoutWithNoLowBarCompletedTriesMet) {
970   base::Time creation_time = base::Time::Now();
971   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
972                           kUserRequested);
973   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
974                                       progress_callback()));
975   request.set_completed_attempt_count(policy()->GetMaxCompletedTries() - 1);
976   // Timeout
977   EXPECT_FALSE(offliner()->HandleTimeout(kRequestId));
978   EXPECT_FALSE(SaveInProgress());
979 }
980 
TEST_F(BackgroundLoaderOfflinerTest,HandleTimeoutWithLowBarNoRetryLimit)981 TEST_F(BackgroundLoaderOfflinerTest, HandleTimeoutWithLowBarNoRetryLimit) {
982   base::Time creation_time = base::Time::Now();
983   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
984                           kUserRequested);
985   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
986                                       progress_callback()));
987   // Sets lowbar.
988   offliner()->DocumentAvailableInMainFrame();
989   // Timeout
990   EXPECT_FALSE(offliner()->HandleTimeout(kRequestId));
991   EXPECT_FALSE(SaveInProgress());
992 }
993 
TEST_F(BackgroundLoaderOfflinerTest,SignalCollectionDisabled)994 TEST_F(BackgroundLoaderOfflinerTest, SignalCollectionDisabled) {
995   // Ensure feature flag for Signal collection is off,
996   EXPECT_FALSE(offline_pages::IsOfflinePagesLoadSignalCollectingEnabled());
997 
998   base::Time creation_time = base::Time::Now();
999   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
1000                           kUserRequested);
1001   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
1002                                       progress_callback()));
1003 
1004   CompleteLoading();
1005   PumpLoop();
1006 
1007   // No extra parts should be added if the flag is off.
1008   content::MHTMLExtraParts* extra_parts =
1009       content::MHTMLExtraParts::FromWebContents(offliner()->web_contents());
1010   EXPECT_EQ(extra_parts->size(), 0);
1011 }
1012 
TEST_F(BackgroundLoaderOfflinerTest,SignalCollectionEnabled)1013 TEST_F(BackgroundLoaderOfflinerTest, SignalCollectionEnabled) {
1014   // Ensure feature flag for signal collection is on.
1015   base::test::ScopedFeatureList scoped_feature_list;
1016   scoped_feature_list.InitAndEnableFeature(
1017       kOfflinePagesLoadSignalCollectingFeature);
1018   EXPECT_TRUE(IsOfflinePagesLoadSignalCollectingEnabled());
1019 
1020   base::Time creation_time = base::Time::Now();
1021   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
1022                           kUserRequested);
1023   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
1024                                       progress_callback()));
1025 
1026   CompleteLoading();
1027   PumpLoop();
1028 
1029   // One extra part should be added if the flag is on.
1030   content::MHTMLExtraParts* extra_parts =
1031       content::MHTMLExtraParts::FromWebContents(offliner()->web_contents());
1032   EXPECT_EQ(extra_parts->size(), 1);
1033 }
1034 
TEST_F(BackgroundLoaderOfflinerTest,ResourceSignalCollection)1035 TEST_F(BackgroundLoaderOfflinerTest, ResourceSignalCollection) {
1036   // Ensure feature flag for signal collection is on.
1037   base::test::ScopedFeatureList scoped_feature_list;
1038   scoped_feature_list.InitAndEnableFeature(
1039       kOfflinePagesLoadSignalCollectingFeature);
1040   EXPECT_TRUE(IsOfflinePagesLoadSignalCollectingEnabled());
1041 
1042   base::Time creation_time = base::Time::Now();
1043   SavePageRequest request(kRequestId, HttpUrl(), kClientId, creation_time,
1044                           kUserRequested);
1045   EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(),
1046                                       progress_callback()));
1047 
1048   // Simulate resource requests starting and completing
1049   offliner()->ObserveResourceLoading(
1050       ResourceLoadingObserver::ResourceDataType::IMAGE, true);
1051   offliner()->ObserveResourceLoading(
1052       ResourceLoadingObserver::ResourceDataType::IMAGE, false);
1053   offliner()->ObserveResourceLoading(
1054       ResourceLoadingObserver::ResourceDataType::TEXT_CSS, true);
1055   offliner()->ObserveResourceLoading(
1056       ResourceLoadingObserver::ResourceDataType::TEXT_CSS, true);
1057   offliner()->ObserveResourceLoading(
1058       ResourceLoadingObserver::ResourceDataType::XHR, true);
1059 
1060   CompleteLoading();
1061   PumpLoop();
1062 
1063   // One extra part should be added if the flag is on.
1064   content::MHTMLExtraParts* extra_parts =
1065       content::MHTMLExtraParts::FromWebContents(offliner()->web_contents());
1066   EXPECT_EQ(extra_parts->size(), 1);
1067 
1068   offline_pages::RequestStats* stats = GetRequestStats();
1069   EXPECT_EQ(1,
1070             stats[ResourceLoadingObserver::ResourceDataType::IMAGE].requested);
1071   EXPECT_EQ(1,
1072             stats[ResourceLoadingObserver::ResourceDataType::IMAGE].completed);
1073   EXPECT_EQ(
1074       2, stats[ResourceLoadingObserver::ResourceDataType::TEXT_CSS].requested);
1075   EXPECT_EQ(1, stats[ResourceLoadingObserver::ResourceDataType::XHR].requested);
1076 }
1077 
1078 }  // namespace offline_pages
1079