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