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