1 // Copyright (c) 2012 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/history/core/browser/top_sites_impl.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include "base/bind.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/run_loop.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/task/cancelable_task_tracker.h"
17 #include "base/test/task_environment.h"
18 #include "build/build_config.h"
19 #include "components/history/core/browser/history_client.h"
20 #include "components/history/core/browser/history_constants.h"
21 #include "components/history/core/browser/history_database_params.h"
22 #include "components/history/core/browser/history_db_task.h"
23 #include "components/history/core/browser/history_service.h"
24 #include "components/history/core/browser/history_types.h"
25 #include "components/history/core/browser/top_sites.h"
26 #include "components/history/core/browser/top_sites_observer.h"
27 #include "components/history/core/browser/visit_delegate.h"
28 #include "components/history/core/test/history_service_test_util.h"
29 #include "components/history/core/test/history_unittest_base.h"
30 #include "components/history/core/test/test_history_database.h"
31 #include "components/history/core/test/wait_top_sites_loaded_observer.h"
32 #include "components/prefs/pref_registry_simple.h"
33 #include "components/prefs/testing_pref_service.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "url/gurl.h"
37 
38 using testing::ContainerEq;
39 
40 namespace history {
41 
42 namespace {
43 
44 const char kApplicationScheme[] = "application";
45 const char kPrepopulatedPageURL[] =
46     "http://www.google.com/int/chrome/welcome.html";
47 
48 // Returns whether |url| can be added to history.
MockCanAddURLToHistory(const GURL & url)49 bool MockCanAddURLToHistory(const GURL& url) {
50   return url.is_valid() && !url.SchemeIs(kApplicationScheme);
51 }
52 
53 // Used for querying top sites. Either runs sequentially, or runs a nested
54 // nested run loop until the response is complete. The later is used when
55 // TopSites is queried before it finishes loading.
56 class TopSitesQuerier {
57  public:
TopSitesQuerier()58   TopSitesQuerier() : number_of_callbacks_(0), waiting_(false) {}
59 
60   // Queries top sites. If |wait| is true a nested run loop is run until the
61   // callback is notified.
QueryTopSites(TopSitesImpl * top_sites,bool wait)62   void QueryTopSites(TopSitesImpl* top_sites, bool wait) {
63     int start_number_of_callbacks = number_of_callbacks_;
64     base::RunLoop run_loop;
65     top_sites->GetMostVisitedURLs(
66         base::BindOnce(&TopSitesQuerier::OnTopSitesAvailable,
67                        weak_ptr_factory_.GetWeakPtr(), &run_loop));
68     if (wait && start_number_of_callbacks == number_of_callbacks_) {
69       waiting_ = true;
70       run_loop.Run();
71     }
72   }
73 
CancelRequest()74   void CancelRequest() { weak_ptr_factory_.InvalidateWeakPtrs(); }
75 
set_urls(const MostVisitedURLList & urls)76   void set_urls(const MostVisitedURLList& urls) { urls_ = urls; }
urls() const77   const MostVisitedURLList& urls() const { return urls_; }
78 
number_of_callbacks() const79   int number_of_callbacks() const { return number_of_callbacks_; }
80 
81  private:
82   // Callback for TopSitesImpl::GetMostVisitedURLs.
OnTopSitesAvailable(base::RunLoop * run_loop,const history::MostVisitedURLList & data)83   void OnTopSitesAvailable(base::RunLoop* run_loop,
84                            const history::MostVisitedURLList& data) {
85     urls_ = data;
86     number_of_callbacks_++;
87     if (waiting_) {
88       run_loop->QuitWhenIdle();
89       waiting_ = false;
90     }
91   }
92 
93   MostVisitedURLList urls_;
94   int number_of_callbacks_;
95   bool waiting_;
96   base::WeakPtrFactory<TopSitesQuerier> weak_ptr_factory_{this};
97 
98   DISALLOW_COPY_AND_ASSIGN(TopSitesQuerier);
99 };
100 
101 }  // namespace
102 
103 class TopSitesImplTest : public HistoryUnitTestBase {
104  public:
TopSitesImplTest()105   TopSitesImplTest() {}
106 
SetUp()107   void SetUp() override {
108     ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
109     pref_service_.reset(new TestingPrefServiceSimple);
110     TopSitesImpl::RegisterPrefs(pref_service_->registry());
111     history_service_.reset(
112         new HistoryService(nullptr, std::unique_ptr<VisitDelegate>()));
113     ASSERT_TRUE(history_service_->Init(
114         TestHistoryDatabaseParamsForPath(scoped_temp_dir_.GetPath())));
115     ResetTopSites();
116     WaitTopSitesLoaded();
117   }
118 
TearDown()119   void TearDown() override {
120     DestroyTopSites();
121     history_service_->Shutdown();
122     history_service_.reset();
123     pref_service_.reset();
124   }
125 
126   // Forces top sites to load top sites from history, then recreates top sites.
127   // Recreating top sites makes sure the changes from history are saved and
128   // loaded from the db.
RefreshTopSitesAndRecreate()129   void RefreshTopSitesAndRecreate() {
130     StartQueryForMostVisited();
131     WaitForHistory();
132     RecreateTopSitesAndBlock();
133   }
134 
135   // Blocks the caller until history processes a task. This is useful if you
136   // need to wait until you know history has processed a task.
WaitForHistory()137   void WaitForHistory() {
138     BlockUntilHistoryProcessesPendingRequests(history_service());
139   }
140 
top_sites()141   TopSitesImpl* top_sites() { return top_sites_impl_.get(); }
142 
history_service()143   HistoryService* history_service() { return history_service_.get(); }
144 
GetPrepopulatedPages()145   PrepopulatedPageList GetPrepopulatedPages() {
146     return top_sites()->GetPrepopulatedPages();
147   }
148 
149   // Returns true if the TopSitesQuerier contains the prepopulate data starting
150   // at |start_index|.
ContainsPrepopulatePages(const TopSitesQuerier & querier,size_t start_index)151   void ContainsPrepopulatePages(const TopSitesQuerier& querier,
152                                 size_t start_index) {
153     PrepopulatedPageList prepopulate_pages = GetPrepopulatedPages();
154     ASSERT_LE(start_index + prepopulate_pages.size(), querier.urls().size());
155     for (size_t i = 0; i < prepopulate_pages.size(); ++i) {
156       EXPECT_EQ(prepopulate_pages[i].most_visited.url.spec(),
157                 querier.urls()[start_index + i].url.spec())
158           << " @ index " << i;
159     }
160   }
161 
162   // Adds a page to history.
AddPageToHistory(const GURL & url,const base::string16 & title=base::string16 (),base::Time time=base::Time::Now (),RedirectList redirects=RedirectList ())163   void AddPageToHistory(const GURL& url,
164                         const base::string16& title = base::string16(),
165                         base::Time time = base::Time::Now(),
166                         RedirectList redirects = RedirectList()) {
167     if (redirects.empty())
168       redirects.emplace_back(url);
169     history_service()->AddPage(url, time, reinterpret_cast<ContextID>(1), 0,
170                                GURL(), redirects, ui::PAGE_TRANSITION_TYPED,
171                                history::SOURCE_BROWSED, false, false);
172     if (!title.empty())
173       history_service()->SetPageTitle(url, title);
174   }
175 
176   // Delets a url.
DeleteURL(const GURL & url)177   void DeleteURL(const GURL& url) { history_service()->DeleteURLs({url}); }
178 
179   // Recreates top sites. This forces top sites to reread from the db.
RecreateTopSitesAndBlock()180   void RecreateTopSitesAndBlock() {
181     // Recreate TopSites and wait for it to load.
182     ResetTopSites();
183     WaitTopSitesLoaded();
184   }
185 
186   // Wrappers that allow private TopSites functions to be called from the
187   // individual tests without making them all be friends.
SetTopSites(const MostVisitedURLList & new_top_sites)188   void SetTopSites(const MostVisitedURLList& new_top_sites) {
189     top_sites()->SetTopSites(MostVisitedURLList(new_top_sites),
190                              TopSitesImpl::CALL_LOCATION_FROM_OTHER_PLACES);
191   }
192 
StartQueryForMostVisited()193   void StartQueryForMostVisited() { top_sites()->StartQueryForMostVisited(); }
194 
IsTopSitesLoaded()195   bool IsTopSitesLoaded() { return top_sites()->loaded_; }
196 
AddPrepopulatedPages(MostVisitedURLList * urls)197   bool AddPrepopulatedPages(MostVisitedURLList* urls) {
198     return top_sites()->AddPrepopulatedPages(urls);
199   }
200 
EmptyThreadSafeCache()201   void EmptyThreadSafeCache() {
202     base::AutoLock lock(top_sites()->lock_);
203     top_sites()->thread_safe_cache_.clear();
204   }
205 
ResetTopSites()206   void ResetTopSites() {
207     // TopSites shutdown takes some time as it happens on the DB thread and does
208     // not support the existence of two TopSitesImpl for a location (due to
209     // database locking). DestroyTopSites() waits for the TopSites cleanup to
210     // complete before returning.
211     DestroyTopSites();
212     DCHECK(!top_sites_impl_);
213     PrepopulatedPageList prepopulated_pages;
214     prepopulated_pages.push_back(
215         PrepopulatedPage(GURL(kPrepopulatedPageURL), base::string16(), -1, 0));
216     top_sites_impl_ = new TopSitesImpl(
217         pref_service_.get(), history_service_.get(), prepopulated_pages,
218         base::BindRepeating(MockCanAddURLToHistory));
219     top_sites_impl_->Init(scoped_temp_dir_.GetPath().Append(kTopSitesFilename));
220   }
221 
DestroyTopSites()222   void DestroyTopSites() {
223     if (top_sites_impl_) {
224       top_sites_impl_->ShutdownOnUIThread();
225       top_sites_impl_ = nullptr;
226 
227       task_environment_.RunUntilIdle();
228     }
229   }
230 
WaitTopSitesLoaded()231   void WaitTopSitesLoaded() {
232     DCHECK(top_sites_impl_);
233     WaitTopSitesLoadedObserver wait_top_sites_loaded_observer(top_sites_impl_);
234     wait_top_sites_loaded_observer.Run();
235   }
236 
237  private:
238   base::test::TaskEnvironment task_environment_;
239 
240   base::ScopedTempDir scoped_temp_dir_;
241 
242   std::unique_ptr<TestingPrefServiceSimple> pref_service_;
243   std::unique_ptr<HistoryService> history_service_;
244   scoped_refptr<TopSitesImpl> top_sites_impl_;
245 
246   // To cancel HistoryService tasks.
247   base::CancelableTaskTracker history_tracker_;
248 
249   // To cancel TopSitesBackend tasks.
250   base::CancelableTaskTracker top_sites_tracker_;
251 
252   DISALLOW_COPY_AND_ASSIGN(TopSitesImplTest);
253 };  // Class TopSitesImplTest
254 
255 class MockTopSitesObserver : public TopSitesObserver {
256  public:
MockTopSitesObserver()257   MockTopSitesObserver() {}
258 
259   // history::TopSitesObserver:
TopSitesLoaded(TopSites * top_sites)260   void TopSitesLoaded(TopSites* top_sites) override {}
TopSitesChanged(TopSites * top_sites,ChangeReason change_reason)261   void TopSitesChanged(TopSites* top_sites,
262                        ChangeReason change_reason) override {
263     is_notified_ = true;
264   }
265 
ResetIsNotifiedState()266   void ResetIsNotifiedState() { is_notified_ = false; }
is_notified() const267   bool is_notified() const { return is_notified_; }
268 
269  private:
270   bool is_notified_ = false;
271 
272   DISALLOW_COPY_AND_ASSIGN(MockTopSitesObserver);
273 };
274 
275 // Tests DoTitlesDiffer.
TEST_F(TopSitesImplTest,DoTitlesDiffer)276 TEST_F(TopSitesImplTest, DoTitlesDiffer) {
277   GURL url_1("http://url1/");
278   GURL url_2("http://url2/");
279   base::string16 title_1(base::ASCIIToUTF16("title1"));
280   base::string16 title_2(base::ASCIIToUTF16("title2"));
281 
282   MockTopSitesObserver observer;
283   top_sites()->AddObserver(&observer);
284 
285   // TopSites has a new list of sites and should notify its observers.
286   std::vector<MostVisitedURL> list_1;
287   list_1.emplace_back(url_1, title_1);
288   SetTopSites(list_1);
289   EXPECT_TRUE(observer.is_notified());
290   observer.ResetIsNotifiedState();
291   EXPECT_FALSE(observer.is_notified());
292 
293   // list_1 and list_2 have different sizes. TopSites should notify its
294   // observers.
295   std::vector<MostVisitedURL> list_2;
296   list_2.emplace_back(url_1, title_1);
297   list_2.emplace_back(url_2, title_2);
298   SetTopSites(list_2);
299   EXPECT_TRUE(observer.is_notified());
300   observer.ResetIsNotifiedState();
301   EXPECT_FALSE(observer.is_notified());
302 
303   // list_1 and list_2 are exactly the same now. TopSites should not notify its
304   // observers.
305   list_1.emplace_back(url_2, title_2);
306   SetTopSites(list_1);
307   EXPECT_FALSE(observer.is_notified());
308 
309   // Change |url_2|'s title to |title_1| in list_2. The two lists are different
310   // in titles now. TopSites should notify its observers.
311   list_2.pop_back();
312   list_2.emplace_back(url_2, title_1);
313   SetTopSites(list_2);
314   EXPECT_TRUE(observer.is_notified());
315 
316   top_sites()->RemoveObserver(&observer);
317 }
318 
319 // Tests DiffMostVisited.
TEST_F(TopSitesImplTest,DiffMostVisited)320 TEST_F(TopSitesImplTest, DiffMostVisited) {
321   GURL stays_the_same("http://staysthesame/");
322   GURL gets_added_1("http://getsadded1/");
323   GURL gets_added_2("http://getsadded2/");
324   GURL gets_deleted_1("http://getsdeleted1/");
325   GURL gets_moved_1("http://getsmoved1/");
326 
327   std::vector<MostVisitedURL> old_list;
328   old_list.emplace_back(stays_the_same, base::string16());  // 0  (unchanged)
329   old_list.emplace_back(gets_deleted_1, base::string16());  // 1  (deleted)
330   old_list.emplace_back(gets_moved_1, base::string16());    // 2  (moved to 3)
331 
332   std::vector<MostVisitedURL> new_list;
333   new_list.emplace_back(stays_the_same, base::string16());  // 0  (unchanged)
334   new_list.emplace_back(gets_added_1, base::string16());    // 1  (added)
335   new_list.emplace_back(gets_added_2, base::string16());    // 2  (added)
336   new_list.emplace_back(gets_moved_1, base::string16());    // 3  (moved from 2)
337 
338   history::TopSitesDelta delta;
339   TopSitesImpl::DiffMostVisited(old_list, new_list, &delta);
340 
341   ASSERT_EQ(2u, delta.added.size());
342   EXPECT_TRUE(gets_added_1 == delta.added[0].url.url);
343   EXPECT_EQ(1, delta.added[0].rank);
344   EXPECT_TRUE(gets_added_2 == delta.added[1].url.url);
345   EXPECT_EQ(2, delta.added[1].rank);
346 
347   ASSERT_EQ(1u, delta.deleted.size());
348   EXPECT_TRUE(gets_deleted_1 == delta.deleted[0].url);
349 
350   ASSERT_EQ(1u, delta.moved.size());
351   EXPECT_TRUE(gets_moved_1 == delta.moved[0].url.url);
352   EXPECT_EQ(3, delta.moved[0].rank);
353 }
354 
355 // Tests GetMostVisitedURLs.
TEST_F(TopSitesImplTest,GetMostVisited)356 TEST_F(TopSitesImplTest, GetMostVisited) {
357   GURL news("http://news.google.com/");
358   GURL google("http://google.com/");
359 
360   AddPageToHistory(news);
361   AddPageToHistory(google);
362 
363   StartQueryForMostVisited();
364   WaitForHistory();
365 
366   TopSitesQuerier querier;
367   querier.QueryTopSites(top_sites(), false);
368 
369   ASSERT_EQ(1, querier.number_of_callbacks());
370 
371   // 2 extra prepopulated URLs.
372   ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
373   EXPECT_EQ(news, querier.urls()[0].url);
374   EXPECT_EQ(google, querier.urls()[1].url);
375   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
376 }
377 
378 // Tests GetMostVisitedURLs with a redirect.
TEST_F(TopSitesImplTest,GetMostVisitedWithRedirect)379 TEST_F(TopSitesImplTest, GetMostVisitedWithRedirect) {
380   GURL bare("http://cnn.com/");
381   GURL www("https://www.cnn.com/");
382   GURL edition("https://edition.cnn.com/");
383 
384   AddPageToHistory(edition, base::ASCIIToUTF16("CNN"), base::Time::Now(),
385                    history::RedirectList{bare, www, edition});
386   AddPageToHistory(edition);
387 
388   StartQueryForMostVisited();
389   WaitForHistory();
390 
391   TopSitesQuerier querier;
392   querier.QueryTopSites(top_sites(), false);
393 
394   ASSERT_EQ(1, querier.number_of_callbacks());
395 
396   // This behavior is not desirable: even though edition.cnn.com is in the list
397   // of top sites, and the the bare URL cnn.com is just a redirect to it, we're
398   // returning both. Even worse, the NTP will show the same title, and icon for
399   // the site, so to the user it looks like we just have the same thing twice.
400   // (https://crbug.com/567132)
401   std::vector<GURL> expected_urls = {bare, edition};  // should be {edition}.
402 
403   for (const auto& prepopulated : GetPrepopulatedPages()) {
404     expected_urls.push_back(prepopulated.most_visited.url);
405   }
406   std::vector<GURL> actual_urls;
407   for (const auto& actual : querier.urls()) {
408     actual_urls.push_back(actual.url);
409   }
410   EXPECT_THAT(actual_urls, ContainerEq(expected_urls));
411 }
412 
413 // Makes sure changes done to top sites get mirrored to the db.
TEST_F(TopSitesImplTest,SaveToDB)414 TEST_F(TopSitesImplTest, SaveToDB) {
415   MostVisitedURL url;
416   GURL asdf_url("http://asdf.com");
417   base::string16 asdf_title(base::ASCIIToUTF16("ASDF"));
418   GURL google_url("http://google.com");
419   base::string16 google_title(base::ASCIIToUTF16("Google"));
420   GURL news_url("http://news.google.com");
421   base::string16 news_title(base::ASCIIToUTF16("Google News"));
422 
423   // Add asdf_url to history.
424   AddPageToHistory(asdf_url, asdf_title);
425 
426   // Make TopSites reread from the db.
427   StartQueryForMostVisited();
428   WaitForHistory();
429 
430   RecreateTopSitesAndBlock();
431 
432   {
433     TopSitesQuerier querier;
434     querier.QueryTopSites(top_sites(), false);
435     ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
436     EXPECT_EQ(asdf_url, querier.urls()[0].url);
437     EXPECT_EQ(asdf_title, querier.urls()[0].title);
438     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
439   }
440 
441   MostVisitedURL url2;
442   url2.url = google_url;
443   url2.title = google_title;
444 
445   AddPageToHistory(url2.url, url2.title);
446 
447   // Make TopSites reread from the db.
448   RefreshTopSitesAndRecreate();
449 
450   {
451     TopSitesQuerier querier;
452     querier.QueryTopSites(top_sites(), false);
453     ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
454     EXPECT_EQ(asdf_url, querier.urls()[0].url);
455     EXPECT_EQ(asdf_title, querier.urls()[0].title);
456     EXPECT_EQ(google_url, querier.urls()[1].url);
457     EXPECT_EQ(google_title, querier.urls()[1].title);
458     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
459   }
460 }
461 
462 // More permutations of saving to db.
TEST_F(TopSitesImplTest,RealDatabase)463 TEST_F(TopSitesImplTest, RealDatabase) {
464   MostVisitedURL url;
465   GURL asdf_url("http://asdf.com");
466   base::string16 asdf_title(base::ASCIIToUTF16("ASDF"));
467   GURL google1_url("http://google.com");
468   GURL google2_url("http://google.com/redirect");
469   GURL google3_url("http://www.google.com");
470   base::string16 google_title(base::ASCIIToUTF16("Google"));
471   GURL news_url("http://news.google.com");
472   base::string16 news_title(base::ASCIIToUTF16("Google News"));
473 
474   url.url = asdf_url;
475   url.title = asdf_title;
476 
477   base::Time add_time(base::Time::Now());
478   AddPageToHistory(url.url, url.title, add_time);
479 
480   RefreshTopSitesAndRecreate();
481 
482   {
483     TopSitesQuerier querier;
484     querier.QueryTopSites(top_sites(), false);
485 
486     ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
487     EXPECT_EQ(asdf_url, querier.urls()[0].url);
488     EXPECT_EQ(asdf_title, querier.urls()[0].title);
489     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
490   }
491 
492   MostVisitedURL url2;
493   url2.url = google3_url;
494   url2.title = google_title;
495   history::RedirectList url2_redirects;
496   url2_redirects.push_back(google1_url);
497   url2_redirects.push_back(google2_url);
498   url2_redirects.push_back(google3_url);
499 
500   AddPageToHistory(google3_url, url2.title,
501                    add_time - base::TimeDelta::FromMinutes(1), url2_redirects);
502   // Add google twice so that it becomes the first visited site.
503   AddPageToHistory(google3_url, url2.title,
504                    add_time - base::TimeDelta::FromMinutes(2), url2_redirects);
505 
506   RefreshTopSitesAndRecreate();
507 
508   {
509     scoped_refptr<base::RefCountedMemory> read_data;
510     TopSitesQuerier querier;
511     querier.QueryTopSites(top_sites(), false);
512 
513     ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
514     EXPECT_EQ(google1_url, querier.urls()[0].url);
515     EXPECT_EQ(google_title, querier.urls()[0].title);
516 
517     EXPECT_EQ(asdf_url, querier.urls()[1].url);
518     EXPECT_EQ(asdf_title, querier.urls()[1].title);
519     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
520   }
521 }
522 
TEST_F(TopSitesImplTest,DeleteNotifications)523 TEST_F(TopSitesImplTest, DeleteNotifications) {
524   GURL google1_url("http://google.com");
525   GURL google2_url("http://google.com/redirect");
526   GURL google3_url("http://www.google.com");
527   base::string16 google_title(base::ASCIIToUTF16("Google"));
528   GURL news_url("http://news.google.com");
529   base::string16 news_title(base::ASCIIToUTF16("Google News"));
530 
531   AddPageToHistory(google1_url, google_title);
532   AddPageToHistory(news_url, news_title);
533 
534   RefreshTopSitesAndRecreate();
535 
536   {
537     TopSitesQuerier querier;
538     querier.QueryTopSites(top_sites(), false);
539 
540     ASSERT_EQ(GetPrepopulatedPages().size() + 2, querier.urls().size());
541   }
542 
543   DeleteURL(news_url);
544 
545   // Wait for history to process the deletion.
546   WaitForHistory();
547   // The deletion called back to TopSitesImpl (on the main thread), which
548   // triggers a history query. Wait for that to complete.
549   WaitForHistory();
550 
551   {
552     TopSitesQuerier querier;
553     querier.QueryTopSites(top_sites(), false);
554 
555     ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
556     EXPECT_EQ(google_title, querier.urls()[0].title);
557     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
558   }
559 
560   // Now reload. This verifies topsites actually wrote the deletion to disk.
561   RefreshTopSitesAndRecreate();
562 
563   {
564     TopSitesQuerier querier;
565     querier.QueryTopSites(top_sites(), false);
566 
567     ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
568     EXPECT_EQ(google_title, querier.urls()[0].title);
569     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
570   }
571 
572   DeleteURL(google1_url);
573 
574   // Wait for history to process the deletion.
575   WaitForHistory();
576   // The deletion called back to TopSitesImpl (on the main thread), which
577   // triggers a history query. Wait for that to complete.
578   WaitForHistory();
579 
580   {
581     TopSitesQuerier querier;
582     querier.QueryTopSites(top_sites(), false);
583 
584     ASSERT_EQ(GetPrepopulatedPages().size(), querier.urls().size());
585     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
586   }
587 
588   // Now reload. This verifies topsites actually wrote the deletion to disk.
589   RefreshTopSitesAndRecreate();
590 
591   {
592     TopSitesQuerier querier;
593     querier.QueryTopSites(top_sites(), false);
594 
595     ASSERT_EQ(GetPrepopulatedPages().size(), querier.urls().size());
596     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
597   }
598 }
599 
600 // Verifies that callbacks are notified correctly if requested before top sites
601 // has loaded.
TEST_F(TopSitesImplTest,NotifyCallbacksWhenLoaded)602 TEST_F(TopSitesImplTest, NotifyCallbacksWhenLoaded) {
603   // Recreate top sites. It won't be loaded now.
604   ResetTopSites();
605 
606   EXPECT_FALSE(IsTopSitesLoaded());
607 
608   TopSitesQuerier querier1;
609   TopSitesQuerier querier2;
610   TopSitesQuerier querier3;
611 
612   // Starts the queries.
613   querier1.QueryTopSites(top_sites(), false);
614   querier2.QueryTopSites(top_sites(), false);
615   querier3.QueryTopSites(top_sites(), false);
616 
617   // We shouldn't have gotten a callback.
618   EXPECT_EQ(0, querier1.number_of_callbacks());
619   EXPECT_EQ(0, querier2.number_of_callbacks());
620   EXPECT_EQ(0, querier3.number_of_callbacks());
621 
622   // Wait for loading to complete.
623   WaitTopSitesLoaded();
624 
625   // Now we should have gotten the callbacks.
626   EXPECT_EQ(1, querier1.number_of_callbacks());
627   EXPECT_EQ(GetPrepopulatedPages().size(), querier1.urls().size());
628   EXPECT_EQ(1, querier2.number_of_callbacks());
629   EXPECT_EQ(GetPrepopulatedPages().size(), querier2.urls().size());
630   EXPECT_EQ(1, querier3.number_of_callbacks());
631   EXPECT_EQ(GetPrepopulatedPages().size(), querier3.urls().size());
632 
633   // Reset the top sites.
634   MostVisitedURLList pages;
635   MostVisitedURL url;
636   url.url = GURL("http://1.com/");
637   pages.push_back(url);
638   url.url = GURL("http://2.com/");
639   pages.push_back(url);
640   SetTopSites(pages);
641 
642   // Recreate top sites. It won't be loaded now.
643   ResetTopSites();
644 
645   EXPECT_FALSE(IsTopSitesLoaded());
646 
647   TopSitesQuerier querier4;
648 
649   // Query again.
650   querier4.QueryTopSites(top_sites(), false);
651 
652   // We shouldn't have gotten a callback.
653   EXPECT_EQ(0, querier4.number_of_callbacks());
654 
655   // Wait for loading to complete.
656   WaitTopSitesLoaded();
657 
658   // Now we should have gotten the callbacks.
659   EXPECT_EQ(1, querier4.number_of_callbacks());
660   ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier4.urls().size());
661 
662   EXPECT_EQ("http://1.com/", querier4.urls()[0].url.spec());
663   EXPECT_EQ("http://2.com/", querier4.urls()[1].url.spec());
664   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier4, 2));
665 
666   // Reset the top sites again, this time don't reload.
667   url.url = GURL("http://3.com/");
668   pages.push_back(url);
669   SetTopSites(pages);
670 
671   // Query again.
672   TopSitesQuerier querier5;
673   querier5.QueryTopSites(top_sites(), true);
674 
675   EXPECT_EQ(1, querier5.number_of_callbacks());
676 
677   ASSERT_EQ(3u + GetPrepopulatedPages().size(), querier5.urls().size());
678   EXPECT_EQ("http://1.com/", querier5.urls()[0].url.spec());
679   EXPECT_EQ("http://2.com/", querier5.urls()[1].url.spec());
680   EXPECT_EQ("http://3.com/", querier5.urls()[2].url.spec());
681   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier5, 3));
682 }
683 
684 // Makes sure canceled requests are not notified.
TEST_F(TopSitesImplTest,CancelingRequestsForTopSites)685 TEST_F(TopSitesImplTest, CancelingRequestsForTopSites) {
686   // Recreate top sites. It won't be loaded now.
687   ResetTopSites();
688 
689   EXPECT_FALSE(IsTopSitesLoaded());
690 
691   TopSitesQuerier querier1;
692   TopSitesQuerier querier2;
693 
694   // Starts the queries.
695   querier1.QueryTopSites(top_sites(), false);
696   querier2.QueryTopSites(top_sites(), false);
697 
698   // We shouldn't have gotten a callback.
699   EXPECT_EQ(0, querier1.number_of_callbacks());
700   EXPECT_EQ(0, querier2.number_of_callbacks());
701 
702   querier2.CancelRequest();
703 
704   // Wait for loading to complete.
705   WaitTopSitesLoaded();
706 
707   // The first callback should succeed.
708   EXPECT_EQ(1, querier1.number_of_callbacks());
709   EXPECT_EQ(GetPrepopulatedPages().size(), querier1.urls().size());
710 
711   // And the canceled callback should not be notified.
712   EXPECT_EQ(0, querier2.number_of_callbacks());
713 }
714 
715 // Tests variations of blocked urls.
TEST_F(TopSitesImplTest,BlockedUrlsWithoutPrepopulated)716 TEST_F(TopSitesImplTest, BlockedUrlsWithoutPrepopulated) {
717   MostVisitedURLList pages;
718   MostVisitedURL url, url1;
719   url.url = GURL("http://bbc.com/");
720   pages.push_back(url);
721   url1.url = GURL("http://google.com/");
722   pages.push_back(url1);
723 
724   SetTopSites(pages);
725   EXPECT_FALSE(top_sites()->IsBlocked(GURL("http://bbc.com/")));
726 
727   // Block google.com.
728   top_sites()->AddBlockedUrl(GURL("http://google.com/"));
729 
730   EXPECT_TRUE(top_sites()->HasBlockedUrls());
731   EXPECT_TRUE(top_sites()->IsBlocked(GURL("http://google.com/")));
732   EXPECT_FALSE(top_sites()->IsBlocked(GURL("http://bbc.com/")));
733 
734   // Make sure the blocked site isn't returned in the results.
735   {
736     TopSitesQuerier q;
737     q.QueryTopSites(top_sites(), true);
738     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
739   }
740 
741   // Recreate top sites and make sure the blocked url was correctly read.
742   RecreateTopSitesAndBlock();
743   {
744     TopSitesQuerier q;
745     q.QueryTopSites(top_sites(), true);
746     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
747   }
748 
749   // Mark google as no longer blocked.
750   top_sites()->RemoveBlockedUrl(GURL("http://google.com/"));
751   EXPECT_FALSE(top_sites()->HasBlockedUrls());
752   EXPECT_FALSE(top_sites()->IsBlocked(GURL("http://google.com/")));
753 
754   // Make sure google is returned now.
755   {
756     TopSitesQuerier q;
757     q.QueryTopSites(top_sites(), true);
758     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
759     EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
760   }
761 
762   // Remove all blocked urls.
763   top_sites()->ClearBlockedUrls();
764   EXPECT_FALSE(top_sites()->HasBlockedUrls());
765 
766   {
767     TopSitesQuerier q;
768     q.QueryTopSites(top_sites(), true);
769     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
770     EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
771     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 2));
772   }
773 }
774 
775 // Tests variations of blocking including blocking prepopulated pages.
TEST_F(TopSitesImplTest,BlockingPrepopulated)776 TEST_F(TopSitesImplTest, BlockingPrepopulated) {
777   MostVisitedURLList pages;
778   MostVisitedURL url, url1;
779   url.url = GURL("http://bbc.com/");
780   pages.push_back(url);
781   url1.url = GURL("http://google.com/");
782   pages.push_back(url1);
783 
784   SetTopSites(pages);
785   EXPECT_FALSE(top_sites()->IsBlocked(GURL("http://bbc.com/")));
786 
787   // Block google.com.
788   top_sites()->AddBlockedUrl(GURL("http://google.com/"));
789 
790   DCHECK_GE(GetPrepopulatedPages().size(), 1u);
791   GURL prepopulate_url = GetPrepopulatedPages()[0].most_visited.url;
792 
793   EXPECT_TRUE(top_sites()->HasBlockedUrls());
794   EXPECT_TRUE(top_sites()->IsBlocked(GURL("http://google.com/")));
795   EXPECT_FALSE(top_sites()->IsBlocked(GURL("http://bbc.com/")));
796   EXPECT_FALSE(top_sites()->IsBlocked(prepopulate_url));
797 
798   // Make sure the blocked site isn't returned in the results.
799   {
800     TopSitesQuerier q;
801     q.QueryTopSites(top_sites(), true);
802     ASSERT_EQ(1u + GetPrepopulatedPages().size(), q.urls().size());
803     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
804     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
805   }
806 
807   // Recreate top sites and make sure blocked url was correctly read.
808   RecreateTopSitesAndBlock();
809   {
810     TopSitesQuerier q;
811     q.QueryTopSites(top_sites(), true);
812     ASSERT_EQ(1u + GetPrepopulatedPages().size(), q.urls().size());
813     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
814     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
815   }
816 
817   // Block one of the prepopulate urls.
818   top_sites()->AddBlockedUrl(prepopulate_url);
819   EXPECT_TRUE(top_sites()->HasBlockedUrls());
820 
821   // Make sure the blacked prepopulate url isn't returned.
822   {
823     TopSitesQuerier q;
824     q.QueryTopSites(top_sites(), true);
825     ASSERT_EQ(1u + GetPrepopulatedPages().size() - 1, q.urls().size());
826     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
827     for (size_t i = 1; i < q.urls().size(); ++i)
828       EXPECT_NE(prepopulate_url.spec(), q.urls()[i].url.spec());
829   }
830 
831   // Mark google as no longer blocked.
832   top_sites()->RemoveBlockedUrl(GURL("http://google.com/"));
833   EXPECT_TRUE(top_sites()->HasBlockedUrls());
834   EXPECT_FALSE(top_sites()->IsBlocked(GURL("http://google.com/")));
835 
836   // Make sure google is returned now.
837   {
838     TopSitesQuerier q;
839     q.QueryTopSites(top_sites(), true);
840     ASSERT_EQ(2u + GetPrepopulatedPages().size() - 1, q.urls().size());
841     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
842     EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
843     // Android has only one prepopulated page which has been blocked, so
844     // only 2 urls are returned.
845     if (q.urls().size() > 2)
846       EXPECT_NE(prepopulate_url.spec(), q.urls()[2].url.spec());
847     else
848       EXPECT_EQ(1u, GetPrepopulatedPages().size());
849   }
850 
851   // Remove all blocked urls.
852   top_sites()->ClearBlockedUrls();
853   EXPECT_FALSE(top_sites()->HasBlockedUrls());
854 
855   {
856     TopSitesQuerier q;
857     q.QueryTopSites(top_sites(), true);
858     ASSERT_EQ(2u + GetPrepopulatedPages().size(), q.urls().size());
859     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
860     EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
861     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 2));
862   }
863 }
864 
865 // Makes sure prepopulated pages exist.
TEST_F(TopSitesImplTest,AddPrepopulatedPages)866 TEST_F(TopSitesImplTest, AddPrepopulatedPages) {
867   TopSitesQuerier q;
868   q.QueryTopSites(top_sites(), true);
869   EXPECT_EQ(GetPrepopulatedPages().size(), q.urls().size());
870   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
871 
872   MostVisitedURLList pages = q.urls();
873   EXPECT_FALSE(AddPrepopulatedPages(&pages));
874 
875   EXPECT_EQ(GetPrepopulatedPages().size(), pages.size());
876   q.set_urls(pages);
877   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
878 }
879 
880 }  // namespace history
881