1 // Copyright (c) 2015 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/browsing_data/core/counters/history_counter.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/run_loop.h"
10 #include "chrome/browser/history/history_service_factory.h"
11 #include "chrome/browser/history/web_history_service_factory.h"
12 #include "chrome/browser/sync/profile_sync_service_factory.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/test/base/in_process_browser_test.h"
15 #include "components/browsing_data/core/browsing_data_utils.h"
16 #include "components/browsing_data/core/pref_names.h"
17 #include "components/history/core/browser/history_service.h"
18 #include "components/history/core/browser/web_history_service.h"
19 #include "components/history/core/test/fake_web_history_service.h"
20 #include "components/prefs/pref_service.h"
21 #include "content/public/test/browser_test.h"
22 #include "net/http/http_status_code.h"
23 #include "url/gurl.h"
24
25 namespace {
26
27 using browsing_data::BrowsingDataCounter;
28 using browsing_data::HistoryCounter;
29
30 class HistoryCounterTest : public InProcessBrowserTest {
31 public:
HistoryCounterTest()32 HistoryCounterTest() {}
~HistoryCounterTest()33 ~HistoryCounterTest() override {}
34
SetUpOnMainThread()35 void SetUpOnMainThread() override {
36 time_ = base::Time::Now();
37 history_service_ = HistoryServiceFactory::GetForProfileWithoutCreating(
38 browser()->profile());
39 fake_web_history_service_ =
40 std::make_unique<history::FakeWebHistoryService>();
41
42 SetHistoryDeletionPref(true);
43 SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
44 }
45
AddVisit(const std::string url)46 void AddVisit(const std::string url) {
47 history_service_->AddPage(GURL(url), time_, history::SOURCE_BROWSED);
48 }
49
GetCurrentTime()50 const base::Time& GetCurrentTime() {
51 return time_;
52 }
53
SetTime(base::Time time)54 void SetTime(base::Time time) { time_ = time; }
55
RevertTimeInDays(int days)56 void RevertTimeInDays(int days) {
57 time_ -= base::TimeDelta::FromDays(days);
58 }
59
SetHistoryDeletionPref(bool value)60 void SetHistoryDeletionPref(bool value) {
61 browser()->profile()->GetPrefs()->SetBoolean(
62 browsing_data::prefs::kDeleteBrowsingHistory, value);
63 }
64
SetDeletionPeriodPref(browsing_data::TimePeriod period)65 void SetDeletionPeriodPref(browsing_data::TimePeriod period) {
66 browser()->profile()->GetPrefs()->SetInteger(
67 browsing_data::prefs::kDeleteTimePeriod, static_cast<int>(period));
68 }
69
WaitForCounting()70 void WaitForCounting() {
71 run_loop_.reset(new base::RunLoop());
72 run_loop_->Run();
73 }
74
GetLocalResult()75 BrowsingDataCounter::ResultInt GetLocalResult() {
76 DCHECK(finished_);
77 return local_result_;
78 }
79
HasSyncedVisits()80 bool HasSyncedVisits() {
81 DCHECK(finished_);
82 return has_synced_visits_;
83 }
84
Callback(std::unique_ptr<BrowsingDataCounter::Result> result)85 void Callback(std::unique_ptr<BrowsingDataCounter::Result> result) {
86 finished_ = result->Finished();
87
88 if (finished_) {
89 auto* history_result =
90 static_cast<HistoryCounter::HistoryResult*>(result.get());
91
92 local_result_ = history_result->Value();
93 has_synced_visits_ = history_result->has_synced_visits();
94 }
95
96 if (run_loop_ && finished_)
97 run_loop_->Quit();
98 }
99
GetFakeWebHistoryService(Profile * profile,bool check_sync_status)100 history::WebHistoryService* GetFakeWebHistoryService(Profile* profile,
101 bool check_sync_status) {
102 // |check_sync_status| is true when the factory should check if
103 // history sync is enabled.
104 if (!check_sync_status ||
105 WebHistoryServiceFactory::GetForProfile(profile)) {
106 return fake_web_history_service_.get();
107 }
108 return nullptr;
109 }
110
GetRealWebHistoryService(Profile * profile)111 history::WebHistoryService* GetRealWebHistoryService(Profile* profile) {
112 return WebHistoryServiceFactory::GetForProfile(profile);
113 }
114
GetHistoryService()115 history::HistoryService* GetHistoryService() { return history_service_; }
116
117 private:
118 std::unique_ptr<base::RunLoop> run_loop_;
119 history::HistoryService* history_service_;
120 std::unique_ptr<history::FakeWebHistoryService> fake_web_history_service_;
121 base::Time time_;
122
123 bool finished_;
124 BrowsingDataCounter::ResultInt local_result_;
125 bool has_synced_visits_;
126 };
127
128 // Tests that the counter considers duplicate visits from the same day
129 // to be a single item.
IN_PROC_BROWSER_TEST_F(HistoryCounterTest,DuplicateVisits)130 IN_PROC_BROWSER_TEST_F(HistoryCounterTest, DuplicateVisits) {
131 // Start at a fixed day to avoid flakiness due to timezone changes.
132 base::Time time;
133 ASSERT_TRUE(base::Time::FromUTCString("1 Jul 2020 10:00 GMT", &time));
134 SetTime(time);
135
136 AddVisit("https://www.google.com"); // 1 item
137 AddVisit("https://www.google.com");
138 AddVisit("https://www.chrome.com"); // 2 items
139 AddVisit("https://www.chrome.com");
140 AddVisit("https://www.chrome.com");
141 AddVisit("https://www.example.com"); // 3 items
142
143 RevertTimeInDays(1);
144 AddVisit("https://www.google.com"); // 4 items
145 AddVisit("https://www.example.com"); // 5 items
146 AddVisit("https://www.example.com");
147
148 RevertTimeInDays(1);
149 AddVisit("https://www.chrome.com"); // 6 items
150 AddVisit("https://www.chrome.com");
151 AddVisit("https://www.google.com"); // 7 items
152 AddVisit("https://www.chrome.com");
153 AddVisit("https://www.google.com");
154 AddVisit("https://www.google.com");
155 AddVisit("https://www.chrome.com");
156
157 Profile* profile = browser()->profile();
158
159 HistoryCounter counter(
160 GetHistoryService(),
161 base::BindRepeating(&HistoryCounterTest::GetRealWebHistoryService,
162 base::Unretained(this), base::Unretained(profile)),
163 ProfileSyncServiceFactory::GetForProfile(profile));
164
165 counter.Init(profile->GetPrefs(),
166 browsing_data::ClearBrowsingDataTab::ADVANCED,
167 base::BindRepeating(&HistoryCounterTest::Callback,
168 base::Unretained(this)));
169 counter.Restart();
170
171 WaitForCounting();
172 EXPECT_EQ(7u, GetLocalResult());
173 }
174
175 // Tests that the counter works without |web_history_service_callback| and
176 // |sync_service|.
IN_PROC_BROWSER_TEST_F(HistoryCounterTest,WithoutSyncService)177 IN_PROC_BROWSER_TEST_F(HistoryCounterTest, WithoutSyncService) {
178 AddVisit("https://www.google.com");
179 AddVisit("https://www.chrome.com");
180
181 Profile* profile = browser()->profile();
182
183 browsing_data::HistoryCounter counter(
184 GetHistoryService(),
185 browsing_data::HistoryCounter::GetUpdatedWebHistoryServiceCallback(),
186 nullptr /* sync_service */);
187
188 counter.Init(profile->GetPrefs(),
189 browsing_data::ClearBrowsingDataTab::ADVANCED,
190 base::BindRepeating(&HistoryCounterTest::Callback,
191 base::Unretained(this)));
192 counter.Restart();
193
194 WaitForCounting();
195 EXPECT_EQ(2u, GetLocalResult());
196 }
197
198 // Tests that the counter starts counting automatically when the deletion
199 // pref changes to true.
IN_PROC_BROWSER_TEST_F(HistoryCounterTest,PrefChanged)200 IN_PROC_BROWSER_TEST_F(HistoryCounterTest, PrefChanged) {
201 SetHistoryDeletionPref(false);
202 AddVisit("https://www.google.com");
203 AddVisit("https://www.chrome.com");
204
205 Profile* profile = browser()->profile();
206
207 HistoryCounter counter(
208 GetHistoryService(),
209 base::BindRepeating(&HistoryCounterTest::GetRealWebHistoryService,
210 base::Unretained(this), base::Unretained(profile)),
211 ProfileSyncServiceFactory::GetForProfile(profile));
212
213 counter.Init(profile->GetPrefs(),
214 browsing_data::ClearBrowsingDataTab::ADVANCED,
215 base::BindRepeating(&HistoryCounterTest::Callback,
216 base::Unretained(this)));
217 SetHistoryDeletionPref(true);
218
219 WaitForCounting();
220 EXPECT_EQ(2u, GetLocalResult());
221 }
222
223 // Tests that changing the deletion period restarts the counting, and that
224 // the result takes visit dates into account.
IN_PROC_BROWSER_TEST_F(HistoryCounterTest,PeriodChanged)225 IN_PROC_BROWSER_TEST_F(HistoryCounterTest, PeriodChanged) {
226 AddVisit("https://www.google.com");
227
228 RevertTimeInDays(2);
229 AddVisit("https://www.google.com");
230 AddVisit("https://www.example.com");
231
232 RevertTimeInDays(4);
233 AddVisit("https://www.chrome.com");
234 AddVisit("https://www.chrome.com");
235 AddVisit("https://www.example.com");
236
237 RevertTimeInDays(20);
238 AddVisit("https://www.google.com");
239 AddVisit("https://www.chrome.com");
240 AddVisit("https://www.example.com");
241
242 RevertTimeInDays(10);
243 AddVisit("https://www.example.com");
244 AddVisit("https://www.example.com");
245 AddVisit("https://www.example.com");
246
247 RevertTimeInDays(100);
248 AddVisit("https://www.google.com");
249 AddVisit("https://www.example.com");
250 AddVisit("https://www.example.com");
251
252 Profile* profile = browser()->profile();
253
254 HistoryCounter counter(
255 GetHistoryService(),
256 base::BindRepeating(&HistoryCounterTest::GetRealWebHistoryService,
257 base::Unretained(this), base::Unretained(profile)),
258 ProfileSyncServiceFactory::GetForProfile(profile));
259
260 counter.Init(profile->GetPrefs(),
261 browsing_data::ClearBrowsingDataTab::ADVANCED,
262 base::BindRepeating(&HistoryCounterTest::Callback,
263 base::Unretained(this)));
264
265 SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_HOUR);
266 WaitForCounting();
267 EXPECT_EQ(1u, GetLocalResult());
268
269 SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_DAY);
270 WaitForCounting();
271 EXPECT_EQ(1u, GetLocalResult());
272
273 SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_WEEK);
274 WaitForCounting();
275 EXPECT_EQ(5u, GetLocalResult());
276
277 SetDeletionPeriodPref(browsing_data::TimePeriod::FOUR_WEEKS);
278 WaitForCounting();
279 EXPECT_EQ(8u, GetLocalResult());
280
281 SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
282 WaitForCounting();
283 EXPECT_EQ(11u, GetLocalResult());
284
285 SetDeletionPeriodPref(browsing_data::TimePeriod::OLDER_THAN_30_DAYS);
286 WaitForCounting();
287 EXPECT_EQ(3u, GetLocalResult());
288 }
289
290 // Test the behavior for a profile that syncs history.
IN_PROC_BROWSER_TEST_F(HistoryCounterTest,Synced)291 IN_PROC_BROWSER_TEST_F(HistoryCounterTest, Synced) {
292 // WebHistoryService makes network requests, so we need to use a fake one
293 // for testing.
294 Profile* profile = browser()->profile();
295
296 HistoryCounter counter(
297 GetHistoryService(),
298 base::BindRepeating(&HistoryCounterTest::GetFakeWebHistoryService,
299 base::Unretained(this), base::Unretained(profile),
300 false),
301 ProfileSyncServiceFactory::GetForProfile(profile));
302
303 counter.Init(profile->GetPrefs(),
304 browsing_data::ClearBrowsingDataTab::ADVANCED,
305 base::BindRepeating(&HistoryCounterTest::Callback,
306 base::Unretained(this)));
307
308 history::FakeWebHistoryService* service =
309 static_cast<history::FakeWebHistoryService*>(GetFakeWebHistoryService(
310 profile, false));
311
312 // No entries locally and no entries in Sync.
313 service->SetupFakeResponse(true /* success */, net::HTTP_OK);
314 counter.Restart();
315 WaitForCounting();
316 EXPECT_EQ(0u, GetLocalResult());
317 EXPECT_FALSE(HasSyncedVisits());
318
319 // No entries locally. There are some entries in Sync, but they are out of the
320 // time range.
321 SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_HOUR);
322 service->AddSyncedVisit(
323 "www.google.com", GetCurrentTime() - base::TimeDelta::FromHours(2));
324 service->AddSyncedVisit(
325 "www.chrome.com", GetCurrentTime() - base::TimeDelta::FromHours(2));
326 service->SetupFakeResponse(true /* success */, net::HTTP_OK);
327 counter.Restart();
328 WaitForCounting();
329 EXPECT_EQ(0u, GetLocalResult());
330 EXPECT_FALSE(HasSyncedVisits());
331
332 // No entries locally, but some entries in Sync.
333 service->AddSyncedVisit("www.google.com", GetCurrentTime());
334 service->SetupFakeResponse(true /* success */, net::HTTP_OK);
335 counter.Restart();
336 WaitForCounting();
337 EXPECT_EQ(0u, GetLocalResult());
338 EXPECT_TRUE(HasSyncedVisits());
339
340 // To err on the safe side, if the server request fails, we assume that there
341 // might be some items on the server.
342 service->SetupFakeResponse(true /* success */,
343 net::HTTP_INTERNAL_SERVER_ERROR);
344 counter.Restart();
345 WaitForCounting();
346 EXPECT_EQ(0u, GetLocalResult());
347 EXPECT_TRUE(HasSyncedVisits());
348
349 // Same when the entire query fails.
350 service->SetupFakeResponse(false /* success */,
351 net::HTTP_INTERNAL_SERVER_ERROR);
352 counter.Restart();
353 WaitForCounting();
354 EXPECT_EQ(0u, GetLocalResult());
355 EXPECT_TRUE(HasSyncedVisits());
356
357 // Nonzero local count, nonempty sync.
358 AddVisit("https://www.google.com");
359 AddVisit("https://www.chrome.com");
360 service->SetupFakeResponse(true /* success */, net::HTTP_OK);
361 counter.Restart();
362 WaitForCounting();
363 EXPECT_EQ(2u, GetLocalResult());
364 EXPECT_TRUE(HasSyncedVisits());
365
366 // Nonzero local count, empty sync.
367 service->ClearSyncedVisits();
368 service->SetupFakeResponse(true /* success */, net::HTTP_OK);
369 counter.Restart();
370 WaitForCounting();
371 EXPECT_EQ(2u, GetLocalResult());
372 EXPECT_FALSE(HasSyncedVisits());
373 }
374
375 } // namespace
376