- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / top_sites_impl_unittest.cc
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 "base/bind.h"
6 #include "base/memory/weak_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/path_service.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/history/history_db_task.h"
11 #include "chrome/browser/history/history_service_factory.h"
12 #include "chrome/browser/history/history_types.h"
13 #include "chrome/browser/history/history_unittest_base.h"
14 #include "chrome/browser/history/top_sites_cache.h"
15 #include "chrome/browser/history/top_sites_impl.h"
16 #include "chrome/common/cancelable_task_tracker.h"
17 #include "chrome/common/chrome_constants.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/test/base/testing_profile.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "ui/gfx/codec/jpeg_codec.h"
24 #include "url/gurl.h"
25
26 using content::BrowserThread;
27
28 namespace history {
29
30 namespace {
31
32 // Used by WaitForHistory, see it for details.
33 class WaitForHistoryTask : public HistoryDBTask {
34  public:
35   WaitForHistoryTask() {}
36
37   virtual bool RunOnDBThread(HistoryBackend* backend,
38                              HistoryDatabase* db) OVERRIDE {
39     return true;
40   }
41
42   virtual void DoneRunOnMainThread() OVERRIDE {
43     base::MessageLoop::current()->Quit();
44   }
45
46  private:
47   virtual ~WaitForHistoryTask() {}
48
49   DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
50 };
51
52 // Used for querying top sites. Either runs sequentially, or runs a nested
53 // nested message loop until the response is complete. The later is used when
54 // TopSites is queried before it finishes loading.
55 class TopSitesQuerier {
56  public:
57   TopSitesQuerier()
58       : weak_ptr_factory_(this),
59         number_of_callbacks_(0),
60         waiting_(false) {}
61
62   // Queries top sites. If |wait| is true a nested message loop is run until the
63   // callback is notified.
64   void QueryTopSites(TopSitesImpl* top_sites, bool wait) {
65     int start_number_of_callbacks = number_of_callbacks_;
66     top_sites->GetMostVisitedURLs(
67         base::Bind(&TopSitesQuerier::OnTopSitesAvailable,
68                    weak_ptr_factory_.GetWeakPtr()));
69     if (wait && start_number_of_callbacks == number_of_callbacks_) {
70       waiting_ = true;
71       base::MessageLoop::current()->Run();
72     }
73   }
74
75   void CancelRequest() {
76     weak_ptr_factory_.InvalidateWeakPtrs();
77   }
78
79   void set_urls(const MostVisitedURLList& urls) { urls_ = urls; }
80   const MostVisitedURLList& urls() const { return urls_; }
81
82   int number_of_callbacks() const { return number_of_callbacks_; }
83
84  private:
85   // Callback for TopSitesImpl::GetMostVisitedURLs.
86   void OnTopSitesAvailable(const history::MostVisitedURLList& data) {
87     urls_ = data;
88     number_of_callbacks_++;
89     if (waiting_) {
90       base::MessageLoop::current()->Quit();
91       waiting_ = false;
92     }
93   }
94
95   base::WeakPtrFactory<TopSitesQuerier> weak_ptr_factory_;
96   MostVisitedURLList urls_;
97   int number_of_callbacks_;
98   bool waiting_;
99
100   DISALLOW_COPY_AND_ASSIGN(TopSitesQuerier);
101 };
102
103 // Extracts the data from |t1| into a SkBitmap. This is intended for usage of
104 // thumbnail data, which is stored as jpgs.
105 SkBitmap ExtractThumbnail(const base::RefCountedMemory& t1) {
106   scoped_ptr<SkBitmap> image(gfx::JPEGCodec::Decode(t1.front(),
107                                                     t1.size()));
108   return image.get() ? *image : SkBitmap();
109 }
110
111 // Returns true if t1 and t2 contain the same data.
112 bool ThumbnailsAreEqual(base::RefCountedMemory* t1,
113                         base::RefCountedMemory* t2) {
114   if (!t1 || !t2)
115     return false;
116   if (t1->size() != t2->size())
117     return false;
118   return !memcmp(t1->front(), t2->front(), t1->size());
119 }
120
121 }  // namespace
122
123 class TopSitesImplTest : public HistoryUnitTestBase {
124  public:
125   TopSitesImplTest()
126       : ui_thread_(BrowserThread::UI, &message_loop_),
127         db_thread_(BrowserThread::DB, &message_loop_) {
128   }
129
130   virtual void SetUp() {
131     profile_.reset(new TestingProfile);
132     if (CreateHistoryAndTopSites()) {
133       ASSERT_TRUE(profile_->CreateHistoryService(false, false));
134       profile_->CreateTopSites();
135       profile_->BlockUntilTopSitesLoaded();
136     }
137   }
138
139   virtual void TearDown() {
140     profile_.reset();
141   }
142
143   // Returns true if history and top sites should be created in SetUp.
144   virtual bool CreateHistoryAndTopSites() {
145     return true;
146   }
147
148   // Gets the thumbnail for |url| from TopSites.
149   SkBitmap GetThumbnail(const GURL& url) {
150     scoped_refptr<base::RefCountedMemory> data;
151     return top_sites()->GetPageThumbnail(url, false, &data) ?
152         ExtractThumbnail(*data.get()) : SkBitmap();
153   }
154
155   // Creates a bitmap of the specified color. Caller takes ownership.
156   gfx::Image CreateBitmap(SkColor color) {
157     SkBitmap thumbnail;
158     thumbnail.setConfig(SkBitmap::kARGB_8888_Config, 4, 4);
159     thumbnail.allocPixels();
160     thumbnail.eraseColor(color);
161     return gfx::Image::CreateFrom1xBitmap(thumbnail);  // adds ref.
162   }
163
164   // Forces top sites to load top sites from history, then recreates top sites.
165   // Recreating top sites makes sure the changes from history are saved and
166   // loaded from the db.
167   void RefreshTopSitesAndRecreate() {
168     StartQueryForMostVisited();
169     WaitForHistory();
170     RecreateTopSitesAndBlock();
171   }
172
173   // Blocks the caller until history processes a task. This is useful if you
174   // need to wait until you know history has processed a task.
175   void WaitForHistory() {
176     history_service()->ScheduleDBTask(new WaitForHistoryTask(), &consumer_);
177     base::MessageLoop::current()->Run();
178   }
179
180   // Waits for top sites to finish processing a task. This is useful if you need
181   // to wait until top sites finishes processing a task.
182   void WaitForTopSites() {
183     top_sites()->backend_->DoEmptyRequest(
184         base::Bind(&TopSitesImplTest::QuitCallback, base::Unretained(this)),
185         &cancelable_task_tracker_);
186     base::MessageLoop::current()->Run();
187   }
188
189   TopSitesImpl* top_sites() {
190     return static_cast<TopSitesImpl*>(profile_->GetTopSites());
191   }
192   CancelableRequestConsumer* consumer() { return &consumer_; }
193   TestingProfile* profile() {return profile_.get();}
194   HistoryService* history_service() {
195     return HistoryServiceFactory::GetForProfile(profile_.get(),
196                                                 Profile::EXPLICIT_ACCESS);
197   }
198
199   MostVisitedURLList GetPrepopulatePages() {
200     return top_sites()->GetPrepopulatePages();
201   }
202
203   // Returns true if the TopSitesQuerier contains the prepopulate data starting
204   // at |start_index|.
205   void ContainsPrepopulatePages(const TopSitesQuerier& querier,
206                                 size_t start_index) {
207     MostVisitedURLList prepopulate_urls = GetPrepopulatePages();
208     ASSERT_LE(start_index + prepopulate_urls.size(), querier.urls().size());
209     for (size_t i = 0; i < prepopulate_urls.size(); ++i) {
210       EXPECT_EQ(prepopulate_urls[i].url.spec(),
211                 querier.urls()[start_index + i].url.spec()) << " @ index " <<
212           i;
213     }
214   }
215
216   // Used for callbacks from history.
217   void EmptyCallback() {
218   }
219
220   // Quit the current message loop when invoked. Useful when running a nested
221   // message loop.
222   void QuitCallback() {
223     base::MessageLoop::current()->Quit();
224   }
225
226   // Adds a page to history.
227   void AddPageToHistory(const GURL& url) {
228     RedirectList redirects;
229     redirects.push_back(url);
230     history_service()->AddPage(
231         url, base::Time::Now(), static_cast<void*>(this), 0, GURL(),
232         redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
233         false);
234   }
235
236   // Adds a page to history.
237   void AddPageToHistory(const GURL& url, const string16& title) {
238     RedirectList redirects;
239     redirects.push_back(url);
240     history_service()->AddPage(
241         url, base::Time::Now(), static_cast<void*>(this), 0, GURL(),
242         redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
243         false);
244     history_service()->SetPageTitle(url, title);
245   }
246
247   // Adds a page to history.
248   void AddPageToHistory(const GURL& url,
249                         const string16& title,
250                         const history::RedirectList& redirects,
251                         base::Time time) {
252     history_service()->AddPage(
253         url, time, static_cast<void*>(this), 0, GURL(),
254         redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
255         false);
256     history_service()->SetPageTitle(url, title);
257   }
258
259   // Delets a url.
260   void DeleteURL(const GURL& url) {
261     history_service()->DeleteURL(url);
262   }
263
264   // Returns true if the thumbnail equals the specified bytes.
265   bool ThumbnailEqualsBytes(const gfx::Image& image,
266                             base::RefCountedMemory* bytes) {
267     scoped_refptr<base::RefCountedBytes> encoded_image;
268     TopSitesImpl::EncodeBitmap(image, &encoded_image);
269     return ThumbnailsAreEqual(encoded_image.get(), bytes);
270   }
271
272   // Recreates top sites. This forces top sites to reread from the db.
273   void RecreateTopSitesAndBlock() {
274     // Recreate TopSites and wait for it to load.
275     profile()->CreateTopSites();
276     // As history already loaded we have to fake this call.
277     profile()->BlockUntilTopSitesLoaded();
278   }
279
280   // Wrappers that allow private TopSites functions to be called from the
281   // individual tests without making them all be friends.
282   GURL GetCanonicalURL(const GURL& url) {
283     return top_sites()->cache_->GetCanonicalURL(url);
284   }
285
286   void SetTopSites(const MostVisitedURLList& new_top_sites) {
287     top_sites()->SetTopSites(new_top_sites);
288   }
289
290   void StartQueryForMostVisited() {
291     top_sites()->StartQueryForMostVisited();
292   }
293
294   void SetLastNumUrlsChanged(size_t value) {
295     top_sites()->last_num_urls_changed_ = value;
296   }
297
298   size_t last_num_urls_changed() { return top_sites()->last_num_urls_changed_; }
299
300   base::TimeDelta GetUpdateDelay() {
301     return top_sites()->GetUpdateDelay();
302   }
303
304   bool IsTopSitesLoaded() { return top_sites()->loaded_; }
305
306   bool AddPrepopulatedPages(MostVisitedURLList* urls) {
307     return top_sites()->AddPrepopulatedPages(urls);
308   }
309
310  private:
311   base::MessageLoopForUI message_loop_;
312   content::TestBrowserThread ui_thread_;
313   content::TestBrowserThread db_thread_;
314   scoped_ptr<TestingProfile> profile_;
315
316   // To cancel HistoryService tasks.
317   CancelableRequestConsumer consumer_;
318
319   // To cancel TopSitesBackend tasks.
320   CancelableTaskTracker cancelable_task_tracker_;
321
322   DISALLOW_COPY_AND_ASSIGN(TopSitesImplTest);
323 };  // Class TopSitesImplTest
324
325 // Helper function for appending a URL to a vector of "most visited" URLs,
326 // using the default values for everything but the URL.
327 static void AppendMostVisitedURL(std::vector<MostVisitedURL>* list,
328                                  const GURL& url) {
329   MostVisitedURL mv;
330   mv.url = url;
331   mv.redirects.push_back(url);
332   list->push_back(mv);
333 }
334
335 // Same as AppendMostVisitedURL except that it adds a redirect from the first
336 // URL to the second.
337 static void AppendMostVisitedURLWithRedirect(
338     std::vector<MostVisitedURL>* list,
339     const GURL& redirect_source, const GURL& redirect_dest) {
340   MostVisitedURL mv;
341   mv.url = redirect_dest;
342   mv.redirects.push_back(redirect_source);
343   mv.redirects.push_back(redirect_dest);
344   list->push_back(mv);
345 }
346
347 // Tests GetCanonicalURL.
348 TEST_F(TopSitesImplTest, GetCanonicalURL) {
349   // Have two chains:
350   //   google.com -> www.google.com
351   //   news.google.com (no redirects)
352   GURL news("http://news.google.com/");
353   GURL source("http://google.com/");
354   GURL dest("http://www.google.com/");
355
356   std::vector<MostVisitedURL> most_visited;
357   AppendMostVisitedURLWithRedirect(&most_visited, source, dest);
358   AppendMostVisitedURL(&most_visited, news);
359   SetTopSites(most_visited);
360
361   // Random URLs not in the database are returned unchanged.
362   GURL result = GetCanonicalURL(GURL("http://fark.com/"));
363   EXPECT_EQ(GURL("http://fark.com/"), result);
364
365   // Easy case, there are no redirects and the exact URL is stored.
366   result = GetCanonicalURL(news);
367   EXPECT_EQ(news, result);
368
369   // The URL in question is the source URL in a redirect list.
370   result = GetCanonicalURL(source);
371   EXPECT_EQ(dest, result);
372
373   // The URL in question is the destination of a redirect.
374   result = GetCanonicalURL(dest);
375   EXPECT_EQ(dest, result);
376 }
377
378 // Tests DiffMostVisited.
379 TEST_F(TopSitesImplTest, DiffMostVisited) {
380   GURL stays_the_same("http://staysthesame/");
381   GURL gets_added_1("http://getsadded1/");
382   GURL gets_added_2("http://getsadded2/");
383   GURL gets_deleted_1("http://getsdeleted2/");
384   GURL gets_moved_1("http://getsmoved1/");
385
386   std::vector<MostVisitedURL> old_list;
387   AppendMostVisitedURL(&old_list, stays_the_same);  // 0  (unchanged)
388   AppendMostVisitedURL(&old_list, gets_deleted_1);  // 1  (deleted)
389   AppendMostVisitedURL(&old_list, gets_moved_1);    // 2  (moved to 3)
390
391   std::vector<MostVisitedURL> new_list;
392   AppendMostVisitedURL(&new_list, stays_the_same);  // 0  (unchanged)
393   AppendMostVisitedURL(&new_list, gets_added_1);    // 1  (added)
394   AppendMostVisitedURL(&new_list, gets_added_2);    // 2  (added)
395   AppendMostVisitedURL(&new_list, gets_moved_1);    // 3  (moved from 2)
396
397   history::TopSitesDelta delta;
398   history::TopSitesImpl::DiffMostVisited(old_list, new_list, &delta);
399
400   ASSERT_EQ(2u, delta.added.size());
401   ASSERT_TRUE(gets_added_1 == delta.added[0].url.url);
402   ASSERT_EQ(1, delta.added[0].rank);
403   ASSERT_TRUE(gets_added_2 == delta.added[1].url.url);
404   ASSERT_EQ(2, delta.added[1].rank);
405
406   ASSERT_EQ(1u, delta.deleted.size());
407   ASSERT_TRUE(gets_deleted_1 == delta.deleted[0].url);
408
409   ASSERT_EQ(1u, delta.moved.size());
410   ASSERT_TRUE(gets_moved_1 == delta.moved[0].url.url);
411   ASSERT_EQ(3, delta.moved[0].rank);
412 }
413
414 // Tests SetPageThumbnail.
415 TEST_F(TopSitesImplTest, SetPageThumbnail) {
416   GURL url1a("http://google.com/");
417   GURL url1b("http://www.google.com/");
418   GURL url2("http://images.google.com/");
419   GURL invalid_url("chrome://favicon/http://google.com/");
420
421   std::vector<MostVisitedURL> list;
422   AppendMostVisitedURL(&list, url2);
423
424   MostVisitedURL mv;
425   mv.url = url1b;
426   mv.redirects.push_back(url1a);
427   mv.redirects.push_back(url1b);
428   list.push_back(mv);
429
430   // Save our most visited data containing that one site.
431   SetTopSites(list);
432
433   // Create a dummy thumbnail.
434   gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
435
436   base::Time now = base::Time::Now();
437   ThumbnailScore low_score(1.0, true, true, now);
438   ThumbnailScore medium_score(0.5, true, true, now);
439   ThumbnailScore high_score(0.0, true, true, now);
440
441   // Setting the thumbnail for invalid pages should fail.
442   EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
443                                              thumbnail, medium_score));
444
445   // Setting the thumbnail for url2 should succeed, lower scores shouldn't
446   // replace it, higher scores should.
447   EXPECT_TRUE(top_sites()->SetPageThumbnail(url2, thumbnail, medium_score));
448   EXPECT_FALSE(top_sites()->SetPageThumbnail(url2, thumbnail, low_score));
449   EXPECT_TRUE(top_sites()->SetPageThumbnail(url2, thumbnail, high_score));
450
451   // Set on the redirect source should succeed. It should be replacable by
452   // the same score on the redirect destination, which in turn should not
453   // be replaced by the source again.
454   EXPECT_TRUE(top_sites()->SetPageThumbnail(url1a, thumbnail, medium_score));
455   EXPECT_TRUE(top_sites()->SetPageThumbnail(url1b, thumbnail, medium_score));
456   EXPECT_FALSE(top_sites()->SetPageThumbnail(url1a, thumbnail, medium_score));
457 }
458
459 // Makes sure a thumbnail is correctly removed when the page is removed.
460 TEST_F(TopSitesImplTest, ThumbnailRemoved) {
461   GURL url("http://google.com/");
462
463   // Configure top sites with 'google.com'.
464   std::vector<MostVisitedURL> list;
465   AppendMostVisitedURL(&list, url);
466   SetTopSites(list);
467
468   // Create a dummy thumbnail.
469   gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
470
471   base::Time now = base::Time::Now();
472   ThumbnailScore low_score(1.0, true, true, now);
473   ThumbnailScore medium_score(0.5, true, true, now);
474   ThumbnailScore high_score(0.0, true, true, now);
475
476   // Set the thumbnail.
477   EXPECT_TRUE(top_sites()->SetPageThumbnail(url, thumbnail, medium_score));
478
479   // Make sure the thumbnail was actually set.
480   scoped_refptr<base::RefCountedMemory> result;
481   EXPECT_TRUE(top_sites()->GetPageThumbnail(url, false, &result));
482   EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
483
484   // Reset the thumbnails and make sure we don't get it back.
485   SetTopSites(MostVisitedURLList());
486   RefreshTopSitesAndRecreate();
487   EXPECT_FALSE(top_sites()->GetPageThumbnail(url, false, &result));
488 }
489
490 // Tests GetPageThumbnail.
491 TEST_F(TopSitesImplTest, GetPageThumbnail) {
492   MostVisitedURLList url_list;
493   MostVisitedURL url1;
494   url1.url = GURL("http://asdf.com");
495   url1.redirects.push_back(url1.url);
496   url_list.push_back(url1);
497
498   MostVisitedURL url2;
499   url2.url = GURL("http://gmail.com");
500   url2.redirects.push_back(url2.url);
501   url2.redirects.push_back(GURL("http://mail.google.com"));
502   url_list.push_back(url2);
503
504   SetTopSites(url_list);
505
506   // Create a dummy thumbnail.
507   gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
508   ThumbnailScore score(0.5, true, true, base::Time::Now());
509
510   scoped_refptr<base::RefCountedMemory> result;
511   EXPECT_TRUE(top_sites()->SetPageThumbnail(url1.url, thumbnail, score));
512   EXPECT_TRUE(top_sites()->GetPageThumbnail(url1.url, false, &result));
513
514   EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://gmail.com"),
515                                             thumbnail, score));
516   EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://gmail.com"),
517                                             false,
518                                             &result));
519   // Get a thumbnail via a redirect.
520   EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://mail.google.com"),
521                                             false,
522                                             &result));
523
524   EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://mail.google.com"),
525                                             thumbnail, score));
526   EXPECT_TRUE(top_sites()->GetPageThumbnail(url2.url, false, &result));
527
528   EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
529 }
530
531 // Tests GetMostVisitedURLs.
532 TEST_F(TopSitesImplTest, GetMostVisited) {
533   GURL news("http://news.google.com/");
534   GURL google("http://google.com/");
535
536   AddPageToHistory(news);
537   AddPageToHistory(google);
538
539   StartQueryForMostVisited();
540   WaitForHistory();
541
542   TopSitesQuerier querier;
543   querier.QueryTopSites(top_sites(), false);
544
545   ASSERT_EQ(1, querier.number_of_callbacks());
546
547   // 2 extra prepopulated URLs.
548   ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
549   EXPECT_EQ(news, querier.urls()[0].url);
550   EXPECT_EQ(google, querier.urls()[1].url);
551   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
552 }
553
554 // Makes sure changes done to top sites get mirrored to the db.
555 TEST_F(TopSitesImplTest, SaveToDB) {
556   MostVisitedURL url;
557   GURL asdf_url("http://asdf.com");
558   string16 asdf_title(ASCIIToUTF16("ASDF"));
559   GURL google_url("http://google.com");
560   string16 google_title(ASCIIToUTF16("Google"));
561   GURL news_url("http://news.google.com");
562   string16 news_title(ASCIIToUTF16("Google News"));
563
564   // Add asdf_url to history.
565   AddPageToHistory(asdf_url, asdf_title);
566
567   // Make TopSites reread from the db.
568   StartQueryForMostVisited();
569   WaitForHistory();
570
571   // Add a thumbnail.
572   gfx::Image tmp_bitmap(CreateBitmap(SK_ColorBLUE));
573   ASSERT_TRUE(top_sites()->SetPageThumbnail(asdf_url, tmp_bitmap,
574                                             ThumbnailScore()));
575
576   RecreateTopSitesAndBlock();
577
578   {
579     TopSitesQuerier querier;
580     querier.QueryTopSites(top_sites(), false);
581     ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
582     EXPECT_EQ(asdf_url, querier.urls()[0].url);
583     EXPECT_EQ(asdf_title, querier.urls()[0].title);
584     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
585
586     scoped_refptr<base::RefCountedMemory> read_data;
587     EXPECT_TRUE(top_sites()->GetPageThumbnail(asdf_url, false, &read_data));
588     EXPECT_TRUE(ThumbnailEqualsBytes(tmp_bitmap, read_data.get()));
589   }
590
591   MostVisitedURL url2;
592   url2.url = google_url;
593   url2.title = google_title;
594   url2.redirects.push_back(url2.url);
595
596   AddPageToHistory(url2.url, url2.title);
597
598   // Add new thumbnail at rank 0 and shift the other result to 1.
599   ASSERT_TRUE(top_sites()->SetPageThumbnail(google_url,
600                                             tmp_bitmap,
601                                             ThumbnailScore()));
602
603   // Make TopSites reread from the db.
604   RefreshTopSitesAndRecreate();
605
606   {
607     TopSitesQuerier querier;
608     querier.QueryTopSites(top_sites(), false);
609     ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
610     EXPECT_EQ(asdf_url, querier.urls()[0].url);
611     EXPECT_EQ(asdf_title, querier.urls()[0].title);
612     EXPECT_EQ(google_url, querier.urls()[1].url);
613     EXPECT_EQ(google_title, querier.urls()[1].title);
614     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
615   }
616 }
617
618 // More permutations of saving to db.
619 TEST_F(TopSitesImplTest, RealDatabase) {
620   MostVisitedURL url;
621   GURL asdf_url("http://asdf.com");
622   string16 asdf_title(ASCIIToUTF16("ASDF"));
623   GURL google1_url("http://google.com");
624   GURL google2_url("http://google.com/redirect");
625   GURL google3_url("http://www.google.com");
626   string16 google_title(ASCIIToUTF16("Google"));
627   GURL news_url("http://news.google.com");
628   string16 news_title(ASCIIToUTF16("Google News"));
629
630   url.url = asdf_url;
631   url.title = asdf_title;
632   url.redirects.push_back(url.url);
633   gfx::Image asdf_thumbnail(CreateBitmap(SK_ColorRED));
634   ASSERT_TRUE(top_sites()->SetPageThumbnail(
635                   asdf_url, asdf_thumbnail, ThumbnailScore()));
636
637   base::Time add_time(base::Time::Now());
638   AddPageToHistory(url.url, url.title, url.redirects, add_time);
639
640   RefreshTopSitesAndRecreate();
641
642   {
643     TopSitesQuerier querier;
644     querier.QueryTopSites(top_sites(), false);
645
646     ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
647     EXPECT_EQ(asdf_url, querier.urls()[0].url);
648     EXPECT_EQ(asdf_title, querier.urls()[0].title);
649     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
650
651     scoped_refptr<base::RefCountedMemory> read_data;
652     EXPECT_TRUE(top_sites()->GetPageThumbnail(asdf_url, false, &read_data));
653     EXPECT_TRUE(ThumbnailEqualsBytes(asdf_thumbnail, read_data.get()));
654   }
655
656   MostVisitedURL url2;
657   url2.url = google3_url;
658   url2.title = google_title;
659   url2.redirects.push_back(google1_url);
660   url2.redirects.push_back(google2_url);
661   url2.redirects.push_back(google3_url);
662
663   AddPageToHistory(google3_url, url2.title, url2.redirects,
664                    add_time - base::TimeDelta::FromMinutes(1));
665   // Add google twice so that it becomes the first visited site.
666   AddPageToHistory(google3_url, url2.title, url2.redirects,
667                    add_time - base::TimeDelta::FromMinutes(2));
668
669   gfx::Image google_thumbnail(CreateBitmap(SK_ColorBLUE));
670   ASSERT_TRUE(top_sites()->SetPageThumbnail(
671                   url2.url, google_thumbnail, ThumbnailScore()));
672
673   RefreshTopSitesAndRecreate();
674
675   {
676     scoped_refptr<base::RefCountedMemory> read_data;
677     TopSitesQuerier querier;
678     querier.QueryTopSites(top_sites(), false);
679
680     ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
681     EXPECT_EQ(google1_url, querier.urls()[0].url);
682     EXPECT_EQ(google_title, querier.urls()[0].title);
683     ASSERT_EQ(3u, querier.urls()[0].redirects.size());
684     EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, false, &read_data));
685     EXPECT_TRUE(ThumbnailEqualsBytes(google_thumbnail, read_data.get()));
686
687     EXPECT_EQ(asdf_url, querier.urls()[1].url);
688     EXPECT_EQ(asdf_title, querier.urls()[1].title);
689     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
690   }
691
692   gfx::Image weewar_bitmap(CreateBitmap(SK_ColorYELLOW));
693
694   base::Time thumbnail_time(base::Time::Now());
695   ThumbnailScore low_score(1.0, true, true, thumbnail_time);
696   ThumbnailScore medium_score(0.5, true, true, thumbnail_time);
697   ThumbnailScore high_score(0.0, true, true, thumbnail_time);
698
699   // 1. Set to weewar. (Writes the thumbnail to the DB.)
700   EXPECT_TRUE(top_sites()->SetPageThumbnail(google3_url,
701                                             weewar_bitmap,
702                                             medium_score));
703   RefreshTopSitesAndRecreate();
704   {
705     scoped_refptr<base::RefCountedMemory> read_data;
706     EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, false, &read_data));
707     EXPECT_TRUE(ThumbnailEqualsBytes(weewar_bitmap, read_data.get()));
708   }
709
710   gfx::Image green_bitmap(CreateBitmap(SK_ColorGREEN));
711
712   // 2. Set to google - low score.
713   EXPECT_FALSE(top_sites()->SetPageThumbnail(google3_url,
714                                              green_bitmap,
715                                              low_score));
716
717   // 3. Set to google - high score.
718   EXPECT_TRUE(top_sites()->SetPageThumbnail(google1_url,
719                                             green_bitmap,
720                                             high_score));
721
722   // Check that the thumbnail was updated.
723   RefreshTopSitesAndRecreate();
724   {
725     scoped_refptr<base::RefCountedMemory> read_data;
726     EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, false, &read_data));
727     EXPECT_FALSE(ThumbnailEqualsBytes(weewar_bitmap, read_data.get()));
728     EXPECT_TRUE(ThumbnailEqualsBytes(green_bitmap, read_data.get()));
729   }
730 }
731
732 TEST_F(TopSitesImplTest, DeleteNotifications) {
733   GURL google1_url("http://google.com");
734   GURL google2_url("http://google.com/redirect");
735   GURL google3_url("http://www.google.com");
736   string16 google_title(ASCIIToUTF16("Google"));
737   GURL news_url("http://news.google.com");
738   string16 news_title(ASCIIToUTF16("Google News"));
739
740   AddPageToHistory(google1_url, google_title);
741   AddPageToHistory(news_url, news_title);
742
743   RefreshTopSitesAndRecreate();
744
745   {
746     TopSitesQuerier querier;
747     querier.QueryTopSites(top_sites(), false);
748
749     ASSERT_EQ(GetPrepopulatePages().size() + 2, querier.urls().size());
750   }
751
752   DeleteURL(news_url);
753
754   // Wait for history to process the deletion.
755   WaitForHistory();
756
757   {
758     TopSitesQuerier querier;
759     querier.QueryTopSites(top_sites(), false);
760
761     ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
762     EXPECT_EQ(google_title, querier.urls()[0].title);
763     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
764   }
765
766   // Now reload. This verifies topsites actually wrote the deletion to disk.
767   RefreshTopSitesAndRecreate();
768
769   {
770     TopSitesQuerier querier;
771     querier.QueryTopSites(top_sites(), false);
772
773     ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
774     EXPECT_EQ(google_title, querier.urls()[0].title);
775     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
776   }
777
778   DeleteURL(google1_url);
779
780   // Wait for history to process the deletion.
781   WaitForHistory();
782
783   {
784     TopSitesQuerier querier;
785     querier.QueryTopSites(top_sites(), false);
786
787     ASSERT_EQ(GetPrepopulatePages().size(), querier.urls().size());
788     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
789   }
790
791   // Now reload. This verifies topsites actually wrote the deletion to disk.
792   RefreshTopSitesAndRecreate();
793
794   {
795     TopSitesQuerier querier;
796     querier.QueryTopSites(top_sites(), false);
797
798     ASSERT_EQ(GetPrepopulatePages().size(), querier.urls().size());
799     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
800   }
801 }
802
803 // Makes sure GetUpdateDelay is updated appropriately.
804 TEST_F(TopSitesImplTest, GetUpdateDelay) {
805   SetLastNumUrlsChanged(0);
806   EXPECT_EQ(30, GetUpdateDelay().InSeconds());
807
808   MostVisitedURLList url_list;
809   url_list.resize(20);
810   GURL tmp_url(GURL("http://x"));
811   for (size_t i = 0; i < url_list.size(); ++i) {
812     url_list[i].url = tmp_url;
813     url_list[i].redirects.push_back(tmp_url);
814   }
815   SetTopSites(url_list);
816   EXPECT_EQ(20u, last_num_urls_changed());
817   SetLastNumUrlsChanged(0);
818   EXPECT_EQ(60, GetUpdateDelay().InMinutes());
819
820   SetLastNumUrlsChanged(3);
821   EXPECT_EQ(52, GetUpdateDelay().InMinutes());
822
823   SetLastNumUrlsChanged(20);
824   EXPECT_EQ(1, GetUpdateDelay().InMinutes());
825 }
826
827 // Verifies that callbacks are notified correctly if requested before top sites
828 // has loaded.
829 TEST_F(TopSitesImplTest, NotifyCallbacksWhenLoaded) {
830   // Recreate top sites. It won't be loaded now.
831   profile()->CreateTopSites();
832
833   EXPECT_FALSE(IsTopSitesLoaded());
834
835   TopSitesQuerier querier1;
836   TopSitesQuerier querier2;
837   TopSitesQuerier querier3;
838
839   // Starts the queries.
840   querier1.QueryTopSites(top_sites(), false);
841   querier2.QueryTopSites(top_sites(), false);
842   querier3.QueryTopSites(top_sites(), false);
843
844   // We shouldn't have gotten a callback.
845   EXPECT_EQ(0, querier1.number_of_callbacks());
846   EXPECT_EQ(0, querier2.number_of_callbacks());
847   EXPECT_EQ(0, querier3.number_of_callbacks());
848
849   // Wait for loading to complete.
850   profile()->BlockUntilTopSitesLoaded();
851
852   // Now we should have gotten the callbacks.
853   EXPECT_EQ(1, querier1.number_of_callbacks());
854   EXPECT_EQ(GetPrepopulatePages().size(), querier1.urls().size());
855   EXPECT_EQ(1, querier2.number_of_callbacks());
856   EXPECT_EQ(GetPrepopulatePages().size(), querier2.urls().size());
857   EXPECT_EQ(1, querier3.number_of_callbacks());
858   EXPECT_EQ(GetPrepopulatePages().size(), querier3.urls().size());
859
860   // Reset the top sites.
861   MostVisitedURLList pages;
862   MostVisitedURL url;
863   url.url = GURL("http://1.com/");
864   url.redirects.push_back(url.url);
865   pages.push_back(url);
866   url.url = GURL("http://2.com/");
867   url.redirects.push_back(url.url);
868   pages.push_back(url);
869   SetTopSites(pages);
870
871   // Recreate top sites. It won't be loaded now.
872   profile()->CreateTopSites();
873
874   EXPECT_FALSE(IsTopSitesLoaded());
875
876   TopSitesQuerier querier4;
877
878   // Query again.
879   querier4.QueryTopSites(top_sites(), false);
880
881   // We shouldn't have gotten a callback.
882   EXPECT_EQ(0, querier4.number_of_callbacks());
883
884   // Wait for loading to complete.
885   profile()->BlockUntilTopSitesLoaded();
886
887   // Now we should have gotten the callbacks.
888   EXPECT_EQ(1, querier4.number_of_callbacks());
889   ASSERT_EQ(2u + GetPrepopulatePages().size(), querier4.urls().size());
890
891   EXPECT_EQ("http://1.com/", querier4.urls()[0].url.spec());
892   EXPECT_EQ("http://2.com/", querier4.urls()[1].url.spec());
893   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier4, 2));
894
895   // Reset the top sites again, this time don't reload.
896   url.url = GURL("http://3.com/");
897   url.redirects.push_back(url.url);
898   pages.push_back(url);
899   SetTopSites(pages);
900
901   // Query again.
902   TopSitesQuerier querier5;
903   querier5.QueryTopSites(top_sites(), true);
904
905   EXPECT_EQ(1, querier5.number_of_callbacks());
906
907   ASSERT_EQ(3u + GetPrepopulatePages().size(), querier5.urls().size());
908   EXPECT_EQ("http://1.com/", querier5.urls()[0].url.spec());
909   EXPECT_EQ("http://2.com/", querier5.urls()[1].url.spec());
910   EXPECT_EQ("http://3.com/", querier5.urls()[2].url.spec());
911   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier5, 3));
912 }
913
914 // Makes sure canceled requests are not notified.
915 TEST_F(TopSitesImplTest, CancelingRequestsForTopSites) {
916   // Recreate top sites. It won't be loaded now.
917   profile()->CreateTopSites();
918
919   EXPECT_FALSE(IsTopSitesLoaded());
920
921   TopSitesQuerier querier1;
922   TopSitesQuerier querier2;
923
924   // Starts the queries.
925   querier1.QueryTopSites(top_sites(), false);
926   querier2.QueryTopSites(top_sites(), false);
927
928   // We shouldn't have gotten a callback.
929   EXPECT_EQ(0, querier1.number_of_callbacks());
930   EXPECT_EQ(0, querier2.number_of_callbacks());
931
932   querier2.CancelRequest();
933
934   // Wait for loading to complete.
935   profile()->BlockUntilTopSitesLoaded();
936
937   // The first callback should succeed.
938   EXPECT_EQ(1, querier1.number_of_callbacks());
939   EXPECT_EQ(GetPrepopulatePages().size(), querier1.urls().size());
940
941   // And the canceled callback should not be notified.
942   EXPECT_EQ(0, querier2.number_of_callbacks());
943 }
944
945 // Makes sure temporary thumbnails are copied over correctly.
946 TEST_F(TopSitesImplTest, AddTemporaryThumbnail) {
947   GURL unknown_url("http://news.google.com/");
948   GURL invalid_url("chrome://thumb/http://google.com/");
949   GURL url1a("http://google.com/");
950   GURL url1b("http://www.google.com/");
951
952   // Create a dummy thumbnail.
953   gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
954
955   ThumbnailScore medium_score(0.5, true, true, base::Time::Now());
956
957   // Don't store thumbnails for Javascript URLs.
958   EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
959                                              thumbnail,
960                                              medium_score));
961   // Store thumbnails for unknown (but valid) URLs temporarily - calls
962   // AddTemporaryThumbnail.
963   EXPECT_TRUE(top_sites()->SetPageThumbnail(unknown_url,
964                                             thumbnail,
965                                             medium_score));
966
967   // We shouldn't get the thumnail back though (the url isn't in to sites yet).
968   scoped_refptr<base::RefCountedMemory> out;
969   EXPECT_FALSE(top_sites()->GetPageThumbnail(unknown_url, false, &out));
970   // But we should be able to get the temporary page thumbnail score.
971   ThumbnailScore out_score;
972   EXPECT_TRUE(top_sites()->GetTemporaryPageThumbnailScore(unknown_url,
973                                                           &out_score));
974   EXPECT_TRUE(medium_score.Equals(out_score));
975
976   std::vector<MostVisitedURL> list;
977
978   MostVisitedURL mv;
979   mv.url = unknown_url;
980   mv.redirects.push_back(mv.url);
981   mv.redirects.push_back(url1a);
982   mv.redirects.push_back(url1b);
983   list.push_back(mv);
984
985   // Update URLs. This should result in using thumbnail.
986   SetTopSites(list);
987
988   ASSERT_TRUE(top_sites()->GetPageThumbnail(unknown_url, false, &out));
989   EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, out.get()));
990 }
991
992 // Tests variations of blacklisting.
993 TEST_F(TopSitesImplTest, Blacklisting) {
994   MostVisitedURLList pages;
995   MostVisitedURL url, url1;
996   url.url = GURL("http://bbc.com/");
997   url.redirects.push_back(url.url);
998   pages.push_back(url);
999   url1.url = GURL("http://google.com/");
1000   url1.redirects.push_back(url1.url);
1001   pages.push_back(url1);
1002
1003   SetTopSites(pages);
1004   EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
1005
1006   // Blacklist google.com.
1007   top_sites()->AddBlacklistedURL(GURL("http://google.com/"));
1008
1009   GURL prepopulate_url = GetPrepopulatePages()[0].url;
1010
1011   EXPECT_TRUE(top_sites()->HasBlacklistedItems());
1012   EXPECT_TRUE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
1013   EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
1014   EXPECT_FALSE(top_sites()->IsBlacklisted(prepopulate_url));
1015
1016   // Make sure the blacklisted site isn't returned in the results.
1017   {
1018     TopSitesQuerier q;
1019     q.QueryTopSites(top_sites(), true);
1020     ASSERT_EQ(1u + GetPrepopulatePages().size(), q.urls().size());
1021     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
1022     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
1023   }
1024
1025   // Recreate top sites and make sure blacklisted url was correctly read.
1026   RecreateTopSitesAndBlock();
1027   {
1028     TopSitesQuerier q;
1029     q.QueryTopSites(top_sites(), true);
1030     ASSERT_EQ(1u + GetPrepopulatePages().size(), q.urls().size());
1031     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
1032     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
1033   }
1034
1035   // Blacklist one of the prepopulate urls.
1036   top_sites()->AddBlacklistedURL(prepopulate_url);
1037   EXPECT_TRUE(top_sites()->HasBlacklistedItems());
1038
1039   // Make sure the blacklisted prepopulate url isn't returned.
1040   {
1041     TopSitesQuerier q;
1042     q.QueryTopSites(top_sites(), true);
1043     ASSERT_EQ(1u + GetPrepopulatePages().size() - 1, q.urls().size());
1044     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
1045     for (size_t i = 1; i < q.urls().size(); ++i)
1046       EXPECT_NE(prepopulate_url.spec(), q.urls()[i].url.spec());
1047   }
1048
1049   // Mark google as no longer blacklisted.
1050   top_sites()->RemoveBlacklistedURL(GURL("http://google.com/"));
1051   EXPECT_TRUE(top_sites()->HasBlacklistedItems());
1052   EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
1053
1054   // Make sure google is returned now.
1055   {
1056     TopSitesQuerier q;
1057     q.QueryTopSites(top_sites(), true);
1058     ASSERT_EQ(2u + GetPrepopulatePages().size() - 1, q.urls().size());
1059     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
1060     EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
1061     // Android has only one prepopulated page which has been blacklisted, so
1062     // only 2 urls are returned.
1063     if (q.urls().size() > 2)
1064       EXPECT_NE(prepopulate_url.spec(), q.urls()[2].url.spec());
1065     else
1066       EXPECT_EQ(1u, GetPrepopulatePages().size());
1067   }
1068
1069   // Remove all blacklisted sites.
1070   top_sites()->ClearBlacklistedURLs();
1071   EXPECT_FALSE(top_sites()->HasBlacklistedItems());
1072
1073   {
1074     TopSitesQuerier q;
1075     q.QueryTopSites(top_sites(), true);
1076     ASSERT_EQ(2u + GetPrepopulatePages().size(), q.urls().size());
1077     EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
1078     EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
1079     ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 2));
1080   }
1081 }
1082
1083 // Makes sure prepopulated pages exist.
1084 TEST_F(TopSitesImplTest, AddPrepopulatedPages) {
1085   TopSitesQuerier q;
1086   q.QueryTopSites(top_sites(), true);
1087   EXPECT_EQ(GetPrepopulatePages().size(), q.urls().size());
1088   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
1089
1090   MostVisitedURLList pages = q.urls();
1091   EXPECT_FALSE(AddPrepopulatedPages(&pages));
1092
1093   EXPECT_EQ(GetPrepopulatePages().size(), pages.size());
1094   q.set_urls(pages);
1095   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
1096 }
1097
1098 }  // namespace history