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 "components/offline_pages/core/snapshot_controller.h"
6 
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "base/test/test_mock_time_task_runner.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "components/offline_pages/core/offline_page_feature.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace offline_pages {
18 
19 class SnapshotControllerTest : public testing::Test,
20                                public SnapshotController::Client {
21  public:
22   SnapshotControllerTest();
23   ~SnapshotControllerTest() override;
24 
controller()25   SnapshotController* controller() { return controller_.get(); }
snapshot_count()26   int snapshot_count() { return snapshot_count_; }
27 
28   // testing::Test
29   void SetUp() override;
30   void TearDown() override;
31 
32   // SnapshotController::Client
33   void StartSnapshot() override;
34 
35   // Utility methods.
36   // Runs until all of the tasks that are not delayed are gone from the task
37   // queue.
38   void PumpLoop();
39   // Fast-forwards virtual time by |delta|, causing tasks with a remaining
40   // delay less than or equal to |delta| to be executed.
41   void FastForwardBy(base::TimeDelta delta);
42 
43  private:
44   std::unique_ptr<SnapshotController> controller_;
45   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
46   bool snapshot_started_;
47   int snapshot_count_;
48 };
49 
SnapshotControllerTest()50 SnapshotControllerTest::SnapshotControllerTest()
51     : task_runner_(new base::TestMockTimeTaskRunner),
52       snapshot_started_(true),
53       snapshot_count_(0) {}
54 
~SnapshotControllerTest()55 SnapshotControllerTest::~SnapshotControllerTest() {}
56 
SetUp()57 void SnapshotControllerTest::SetUp() {
58   controller_ = std::make_unique<SnapshotController>(task_runner_, this);
59   snapshot_started_ = true;
60 }
61 
TearDown()62 void SnapshotControllerTest::TearDown() {
63   controller_.reset();
64 }
65 
StartSnapshot()66 void SnapshotControllerTest::StartSnapshot() {
67   snapshot_count_++;
68 }
69 
PumpLoop()70 void SnapshotControllerTest::PumpLoop() {
71   task_runner_->RunUntilIdle();
72 }
73 
FastForwardBy(base::TimeDelta delta)74 void SnapshotControllerTest::FastForwardBy(base::TimeDelta delta) {
75   task_runner_->FastForwardBy(delta);
76 }
77 
TEST_F(SnapshotControllerTest,OnLoad)78 TEST_F(SnapshotControllerTest, OnLoad) {
79   // Onload should make snapshot after its delay.
80   controller()->DocumentOnLoadCompletedInMainFrame();
81   PumpLoop();
82   EXPECT_EQ(0, snapshot_count());
83   FastForwardBy(base::TimeDelta::FromMilliseconds(
84       controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
85   EXPECT_EQ(1, snapshot_count());
86 }
87 
TEST_F(SnapshotControllerTest,OnDocumentAvailable)88 TEST_F(SnapshotControllerTest, OnDocumentAvailable) {
89   EXPECT_GT(controller()->GetDelayAfterDocumentAvailableForTest(), 0LL);
90   // OnDOM should make snapshot after a delay.
91   controller()->DocumentAvailableInMainFrame();
92   PumpLoop();
93   EXPECT_EQ(0, snapshot_count());
94   FastForwardBy(base::TimeDelta::FromMilliseconds(
95       controller()->GetDelayAfterDocumentAvailableForTest()));
96   EXPECT_EQ(1, snapshot_count());
97 }
98 
TEST_F(SnapshotControllerTest,OnLoadSnapshotIsTheLastOne)99 TEST_F(SnapshotControllerTest, OnLoadSnapshotIsTheLastOne) {
100   // This test assumes DocumentAvailable delay is longer than OnLoadCompleted.
101   EXPECT_GT(controller()->GetDelayAfterDocumentAvailableForTest(),
102             controller()->GetDelayAfterDocumentOnLoadCompletedForTest());
103   // OnDOM should make snapshot after a delay.
104   controller()->DocumentAvailableInMainFrame();
105   PumpLoop();
106   EXPECT_EQ(0, snapshot_count());
107   controller()->DocumentOnLoadCompletedInMainFrame();
108   // Advance time to OnLoadCompleted delay to trigger snapshot.
109   FastForwardBy(base::TimeDelta::FromMilliseconds(
110       controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
111   EXPECT_EQ(1, snapshot_count());
112   // Report that snapshot is completed.
113   controller()->PendingSnapshotCompleted();
114   // Even though previous snapshot is completed, new one should not start
115   // when this DocumentAvailable delay expires.
116   FastForwardBy(base::TimeDelta::FromMilliseconds(
117       controller()->GetDelayAfterDocumentAvailableForTest()));
118   EXPECT_EQ(1, snapshot_count());
119 }
120 
TEST_F(SnapshotControllerTest,OnLoadSnapshotAfterLongDelay)121 TEST_F(SnapshotControllerTest, OnLoadSnapshotAfterLongDelay) {
122   // OnDOM should make snapshot after a delay.
123   controller()->DocumentAvailableInMainFrame();
124   PumpLoop();
125   EXPECT_EQ(0, snapshot_count());
126   FastForwardBy(base::TimeDelta::FromMilliseconds(
127       controller()->GetDelayAfterDocumentAvailableForTest()));
128   EXPECT_EQ(1, snapshot_count());
129   // Report that snapshot is completed.
130   controller()->PendingSnapshotCompleted();
131   // OnLoad should make 2nd snapshot after its delay.
132   controller()->DocumentOnLoadCompletedInMainFrame();
133   FastForwardBy(base::TimeDelta::FromMilliseconds(
134       controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
135   EXPECT_EQ(2, snapshot_count());
136 }
137 
TEST_F(SnapshotControllerTest,Stop)138 TEST_F(SnapshotControllerTest, Stop) {
139   // OnDOM should make snapshot after a delay.
140   controller()->DocumentAvailableInMainFrame();
141   PumpLoop();
142   EXPECT_EQ(0, snapshot_count());
143   controller()->Stop();
144   FastForwardBy(base::TimeDelta::FromMilliseconds(
145       controller()->GetDelayAfterDocumentAvailableForTest()));
146   // Should not start snapshots
147   EXPECT_EQ(0, snapshot_count());
148   // Also should not start snapshot.
149   controller()->DocumentOnLoadCompletedInMainFrame();
150   EXPECT_EQ(0, snapshot_count());
151 }
152 
TEST_F(SnapshotControllerTest,ClientReset)153 TEST_F(SnapshotControllerTest, ClientReset) {
154   controller()->DocumentAvailableInMainFrame();
155 
156   controller()->Reset();
157   FastForwardBy(base::TimeDelta::FromMilliseconds(
158       controller()->GetDelayAfterDocumentAvailableForTest()));
159   // No snapshot since session was reset.
160   EXPECT_EQ(0, snapshot_count());
161   controller()->DocumentOnLoadCompletedInMainFrame();
162   FastForwardBy(base::TimeDelta::FromMilliseconds(
163       controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
164   EXPECT_EQ(1, snapshot_count());
165 
166   controller()->Reset();
167   controller()->DocumentAvailableInMainFrame();
168   FastForwardBy(base::TimeDelta::FromMilliseconds(
169       controller()->GetDelayAfterDocumentAvailableForTest()));
170   // No snapshot since session was reset.
171   EXPECT_EQ(2, snapshot_count());
172 }
173 
174 // This simulated a Reset while there is ongoing snapshot, which is reported
175 // as done later. That reporting should have no effect nor crash.
TEST_F(SnapshotControllerTest,ClientResetWhileSnapshotting)176 TEST_F(SnapshotControllerTest, ClientResetWhileSnapshotting) {
177   controller()->DocumentOnLoadCompletedInMainFrame();
178   FastForwardBy(base::TimeDelta::FromMilliseconds(
179       controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
180   EXPECT_EQ(1, snapshot_count());
181   // This normally happens when navigation starts.
182   controller()->Reset();
183   controller()->PendingSnapshotCompleted();
184   // Next snapshot should be initiated when new document is loaded.
185   controller()->DocumentAvailableInMainFrame();
186   FastForwardBy(base::TimeDelta::FromMilliseconds(
187       controller()->GetDelayAfterDocumentAvailableForTest()));
188   // No snapshot since session was reset.
189   EXPECT_EQ(2, snapshot_count());
190 }
191 
192 }  // namespace offline_pages
193