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.
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"
26 using content::BrowserThread;
32 // Used by WaitForHistory, see it for details.
33 class WaitForHistoryTask : public HistoryDBTask {
35 WaitForHistoryTask() {}
37 virtual bool RunOnDBThread(HistoryBackend* backend,
38 HistoryDatabase* db) OVERRIDE {
42 virtual void DoneRunOnMainThread() OVERRIDE {
43 base::MessageLoop::current()->Quit();
47 virtual ~WaitForHistoryTask() {}
49 DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
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 {
58 : weak_ptr_factory_(this),
59 number_of_callbacks_(0),
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_) {
71 base::MessageLoop::current()->Run();
75 void CancelRequest() {
76 weak_ptr_factory_.InvalidateWeakPtrs();
79 void set_urls(const MostVisitedURLList& urls) { urls_ = urls; }
80 const MostVisitedURLList& urls() const { return urls_; }
82 int number_of_callbacks() const { return number_of_callbacks_; }
85 // Callback for TopSitesImpl::GetMostVisitedURLs.
86 void OnTopSitesAvailable(const history::MostVisitedURLList& data) {
88 number_of_callbacks_++;
90 base::MessageLoop::current()->Quit();
95 base::WeakPtrFactory<TopSitesQuerier> weak_ptr_factory_;
96 MostVisitedURLList urls_;
97 int number_of_callbacks_;
100 DISALLOW_COPY_AND_ASSIGN(TopSitesQuerier);
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(),
108 return image.get() ? *image : SkBitmap();
111 // Returns true if t1 and t2 contain the same data.
112 bool ThumbnailsAreEqual(base::RefCountedMemory* t1,
113 base::RefCountedMemory* t2) {
116 if (t1->size() != t2->size())
118 return !memcmp(t1->front(), t2->front(), t1->size());
123 class TopSitesImplTest : public HistoryUnitTestBase {
126 : ui_thread_(BrowserThread::UI, &message_loop_),
127 db_thread_(BrowserThread::DB, &message_loop_) {
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();
139 virtual void TearDown() {
143 // Returns true if history and top sites should be created in SetUp.
144 virtual bool CreateHistoryAndTopSites() {
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();
155 // Creates a bitmap of the specified color. Caller takes ownership.
156 gfx::Image CreateBitmap(SkColor color) {
158 thumbnail.setConfig(SkBitmap::kARGB_8888_Config, 4, 4);
159 thumbnail.allocPixels();
160 thumbnail.eraseColor(color);
161 return gfx::Image::CreateFrom1xBitmap(thumbnail); // adds ref.
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();
170 RecreateTopSitesAndBlock();
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();
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();
189 TopSitesImpl* top_sites() {
190 return static_cast<TopSitesImpl*>(profile_->GetTopSites());
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);
199 MostVisitedURLList GetPrepopulatePages() {
200 return top_sites()->GetPrepopulatePages();
203 // Returns true if the TopSitesQuerier contains the prepopulate data starting
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 " <<
216 // Used for callbacks from history.
217 void EmptyCallback() {
220 // Quit the current message loop when invoked. Useful when running a nested
222 void QuitCallback() {
223 base::MessageLoop::current()->Quit();
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,
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,
244 history_service()->SetPageTitle(url, title);
247 // Adds a page to history.
248 void AddPageToHistory(const GURL& url,
249 const string16& title,
250 const history::RedirectList& redirects,
252 history_service()->AddPage(
253 url, time, static_cast<void*>(this), 0, GURL(),
254 redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
256 history_service()->SetPageTitle(url, title);
260 void DeleteURL(const GURL& url) {
261 history_service()->DeleteURL(url);
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);
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();
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);
286 void SetTopSites(const MostVisitedURLList& new_top_sites) {
287 top_sites()->SetTopSites(new_top_sites);
290 void StartQueryForMostVisited() {
291 top_sites()->StartQueryForMostVisited();
294 void SetLastNumUrlsChanged(size_t value) {
295 top_sites()->last_num_urls_changed_ = value;
298 size_t last_num_urls_changed() { return top_sites()->last_num_urls_changed_; }
300 base::TimeDelta GetUpdateDelay() {
301 return top_sites()->GetUpdateDelay();
304 bool IsTopSitesLoaded() { return top_sites()->loaded_; }
306 bool AddPrepopulatedPages(MostVisitedURLList* urls) {
307 return top_sites()->AddPrepopulatedPages(urls);
311 base::MessageLoopForUI message_loop_;
312 content::TestBrowserThread ui_thread_;
313 content::TestBrowserThread db_thread_;
314 scoped_ptr<TestingProfile> profile_;
316 // To cancel HistoryService tasks.
317 CancelableRequestConsumer consumer_;
319 // To cancel TopSitesBackend tasks.
320 CancelableTaskTracker cancelable_task_tracker_;
322 DISALLOW_COPY_AND_ASSIGN(TopSitesImplTest);
323 }; // Class TopSitesImplTest
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,
331 mv.redirects.push_back(url);
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) {
341 mv.url = redirect_dest;
342 mv.redirects.push_back(redirect_source);
343 mv.redirects.push_back(redirect_dest);
347 // Tests GetCanonicalURL.
348 TEST_F(TopSitesImplTest, GetCanonicalURL) {
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/");
356 std::vector<MostVisitedURL> most_visited;
357 AppendMostVisitedURLWithRedirect(&most_visited, source, dest);
358 AppendMostVisitedURL(&most_visited, news);
359 SetTopSites(most_visited);
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);
365 // Easy case, there are no redirects and the exact URL is stored.
366 result = GetCanonicalURL(news);
367 EXPECT_EQ(news, result);
369 // The URL in question is the source URL in a redirect list.
370 result = GetCanonicalURL(source);
371 EXPECT_EQ(dest, result);
373 // The URL in question is the destination of a redirect.
374 result = GetCanonicalURL(dest);
375 EXPECT_EQ(dest, result);
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/");
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)
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)
397 history::TopSitesDelta delta;
398 history::TopSitesImpl::DiffMostVisited(old_list, new_list, &delta);
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);
406 ASSERT_EQ(1u, delta.deleted.size());
407 ASSERT_TRUE(gets_deleted_1 == delta.deleted[0].url);
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);
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/");
421 std::vector<MostVisitedURL> list;
422 AppendMostVisitedURL(&list, url2);
426 mv.redirects.push_back(url1a);
427 mv.redirects.push_back(url1b);
430 // Save our most visited data containing that one site.
433 // Create a dummy thumbnail.
434 gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
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);
441 // Setting the thumbnail for invalid pages should fail.
442 EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
443 thumbnail, medium_score));
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));
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));
459 // Makes sure a thumbnail is correctly removed when the page is removed.
460 TEST_F(TopSitesImplTest, ThumbnailRemoved) {
461 GURL url("http://google.com/");
463 // Configure top sites with 'google.com'.
464 std::vector<MostVisitedURL> list;
465 AppendMostVisitedURL(&list, url);
468 // Create a dummy thumbnail.
469 gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
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);
476 // Set the thumbnail.
477 EXPECT_TRUE(top_sites()->SetPageThumbnail(url, thumbnail, medium_score));
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()));
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));
490 // Tests GetPageThumbnail.
491 TEST_F(TopSitesImplTest, GetPageThumbnail) {
492 MostVisitedURLList url_list;
494 url1.url = GURL("http://asdf.com");
495 url1.redirects.push_back(url1.url);
496 url_list.push_back(url1);
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);
504 SetTopSites(url_list);
506 // Create a dummy thumbnail.
507 gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
508 ThumbnailScore score(0.5, true, true, base::Time::Now());
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));
514 EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://gmail.com"),
516 EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://gmail.com"),
519 // Get a thumbnail via a redirect.
520 EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://mail.google.com"),
524 EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://mail.google.com"),
526 EXPECT_TRUE(top_sites()->GetPageThumbnail(url2.url, false, &result));
528 EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
531 // Tests GetMostVisitedURLs.
532 TEST_F(TopSitesImplTest, GetMostVisited) {
533 GURL news("http://news.google.com/");
534 GURL google("http://google.com/");
536 AddPageToHistory(news);
537 AddPageToHistory(google);
539 StartQueryForMostVisited();
542 TopSitesQuerier querier;
543 querier.QueryTopSites(top_sites(), false);
545 ASSERT_EQ(1, querier.number_of_callbacks());
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));
554 // Makes sure changes done to top sites get mirrored to the db.
555 TEST_F(TopSitesImplTest, SaveToDB) {
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"));
564 // Add asdf_url to history.
565 AddPageToHistory(asdf_url, asdf_title);
567 // Make TopSites reread from the db.
568 StartQueryForMostVisited();
572 gfx::Image tmp_bitmap(CreateBitmap(SK_ColorBLUE));
573 ASSERT_TRUE(top_sites()->SetPageThumbnail(asdf_url, tmp_bitmap,
576 RecreateTopSitesAndBlock();
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));
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()));
592 url2.url = google_url;
593 url2.title = google_title;
594 url2.redirects.push_back(url2.url);
596 AddPageToHistory(url2.url, url2.title);
598 // Add new thumbnail at rank 0 and shift the other result to 1.
599 ASSERT_TRUE(top_sites()->SetPageThumbnail(google_url,
603 // Make TopSites reread from the db.
604 RefreshTopSitesAndRecreate();
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));
618 // More permutations of saving to db.
619 TEST_F(TopSitesImplTest, RealDatabase) {
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"));
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()));
637 base::Time add_time(base::Time::Now());
638 AddPageToHistory(url.url, url.title, url.redirects, add_time);
640 RefreshTopSitesAndRecreate();
643 TopSitesQuerier querier;
644 querier.QueryTopSites(top_sites(), false);
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));
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()));
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);
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));
669 gfx::Image google_thumbnail(CreateBitmap(SK_ColorBLUE));
670 ASSERT_TRUE(top_sites()->SetPageThumbnail(
671 url2.url, google_thumbnail, ThumbnailScore()));
673 RefreshTopSitesAndRecreate();
676 scoped_refptr<base::RefCountedMemory> read_data;
677 TopSitesQuerier querier;
678 querier.QueryTopSites(top_sites(), false);
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()));
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));
692 gfx::Image weewar_bitmap(CreateBitmap(SK_ColorYELLOW));
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);
699 // 1. Set to weewar. (Writes the thumbnail to the DB.)
700 EXPECT_TRUE(top_sites()->SetPageThumbnail(google3_url,
703 RefreshTopSitesAndRecreate();
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()));
710 gfx::Image green_bitmap(CreateBitmap(SK_ColorGREEN));
712 // 2. Set to google - low score.
713 EXPECT_FALSE(top_sites()->SetPageThumbnail(google3_url,
717 // 3. Set to google - high score.
718 EXPECT_TRUE(top_sites()->SetPageThumbnail(google1_url,
722 // Check that the thumbnail was updated.
723 RefreshTopSitesAndRecreate();
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()));
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"));
740 AddPageToHistory(google1_url, google_title);
741 AddPageToHistory(news_url, news_title);
743 RefreshTopSitesAndRecreate();
746 TopSitesQuerier querier;
747 querier.QueryTopSites(top_sites(), false);
749 ASSERT_EQ(GetPrepopulatePages().size() + 2, querier.urls().size());
754 // Wait for history to process the deletion.
758 TopSitesQuerier querier;
759 querier.QueryTopSites(top_sites(), false);
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));
766 // Now reload. This verifies topsites actually wrote the deletion to disk.
767 RefreshTopSitesAndRecreate();
770 TopSitesQuerier querier;
771 querier.QueryTopSites(top_sites(), false);
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));
778 DeleteURL(google1_url);
780 // Wait for history to process the deletion.
784 TopSitesQuerier querier;
785 querier.QueryTopSites(top_sites(), false);
787 ASSERT_EQ(GetPrepopulatePages().size(), querier.urls().size());
788 ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
791 // Now reload. This verifies topsites actually wrote the deletion to disk.
792 RefreshTopSitesAndRecreate();
795 TopSitesQuerier querier;
796 querier.QueryTopSites(top_sites(), false);
798 ASSERT_EQ(GetPrepopulatePages().size(), querier.urls().size());
799 ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
803 // Makes sure GetUpdateDelay is updated appropriately.
804 TEST_F(TopSitesImplTest, GetUpdateDelay) {
805 SetLastNumUrlsChanged(0);
806 EXPECT_EQ(30, GetUpdateDelay().InSeconds());
808 MostVisitedURLList url_list;
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);
815 SetTopSites(url_list);
816 EXPECT_EQ(20u, last_num_urls_changed());
817 SetLastNumUrlsChanged(0);
818 EXPECT_EQ(60, GetUpdateDelay().InMinutes());
820 SetLastNumUrlsChanged(3);
821 EXPECT_EQ(52, GetUpdateDelay().InMinutes());
823 SetLastNumUrlsChanged(20);
824 EXPECT_EQ(1, GetUpdateDelay().InMinutes());
827 // Verifies that callbacks are notified correctly if requested before top sites
829 TEST_F(TopSitesImplTest, NotifyCallbacksWhenLoaded) {
830 // Recreate top sites. It won't be loaded now.
831 profile()->CreateTopSites();
833 EXPECT_FALSE(IsTopSitesLoaded());
835 TopSitesQuerier querier1;
836 TopSitesQuerier querier2;
837 TopSitesQuerier querier3;
839 // Starts the queries.
840 querier1.QueryTopSites(top_sites(), false);
841 querier2.QueryTopSites(top_sites(), false);
842 querier3.QueryTopSites(top_sites(), false);
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());
849 // Wait for loading to complete.
850 profile()->BlockUntilTopSitesLoaded();
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());
860 // Reset the top sites.
861 MostVisitedURLList pages;
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);
871 // Recreate top sites. It won't be loaded now.
872 profile()->CreateTopSites();
874 EXPECT_FALSE(IsTopSitesLoaded());
876 TopSitesQuerier querier4;
879 querier4.QueryTopSites(top_sites(), false);
881 // We shouldn't have gotten a callback.
882 EXPECT_EQ(0, querier4.number_of_callbacks());
884 // Wait for loading to complete.
885 profile()->BlockUntilTopSitesLoaded();
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());
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));
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);
902 TopSitesQuerier querier5;
903 querier5.QueryTopSites(top_sites(), true);
905 EXPECT_EQ(1, querier5.number_of_callbacks());
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));
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();
919 EXPECT_FALSE(IsTopSitesLoaded());
921 TopSitesQuerier querier1;
922 TopSitesQuerier querier2;
924 // Starts the queries.
925 querier1.QueryTopSites(top_sites(), false);
926 querier2.QueryTopSites(top_sites(), false);
928 // We shouldn't have gotten a callback.
929 EXPECT_EQ(0, querier1.number_of_callbacks());
930 EXPECT_EQ(0, querier2.number_of_callbacks());
932 querier2.CancelRequest();
934 // Wait for loading to complete.
935 profile()->BlockUntilTopSitesLoaded();
937 // The first callback should succeed.
938 EXPECT_EQ(1, querier1.number_of_callbacks());
939 EXPECT_EQ(GetPrepopulatePages().size(), querier1.urls().size());
941 // And the canceled callback should not be notified.
942 EXPECT_EQ(0, querier2.number_of_callbacks());
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/");
952 // Create a dummy thumbnail.
953 gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
955 ThumbnailScore medium_score(0.5, true, true, base::Time::Now());
957 // Don't store thumbnails for Javascript URLs.
958 EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
961 // Store thumbnails for unknown (but valid) URLs temporarily - calls
962 // AddTemporaryThumbnail.
963 EXPECT_TRUE(top_sites()->SetPageThumbnail(unknown_url,
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,
974 EXPECT_TRUE(medium_score.Equals(out_score));
976 std::vector<MostVisitedURL> list;
979 mv.url = unknown_url;
980 mv.redirects.push_back(mv.url);
981 mv.redirects.push_back(url1a);
982 mv.redirects.push_back(url1b);
985 // Update URLs. This should result in using thumbnail.
988 ASSERT_TRUE(top_sites()->GetPageThumbnail(unknown_url, false, &out));
989 EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, out.get()));
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);
1004 EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
1006 // Blacklist google.com.
1007 top_sites()->AddBlacklistedURL(GURL("http://google.com/"));
1009 GURL prepopulate_url = GetPrepopulatePages()[0].url;
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));
1016 // Make sure the blacklisted site isn't returned in the results.
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));
1025 // Recreate top sites and make sure blacklisted url was correctly read.
1026 RecreateTopSitesAndBlock();
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));
1035 // Blacklist one of the prepopulate urls.
1036 top_sites()->AddBlacklistedURL(prepopulate_url);
1037 EXPECT_TRUE(top_sites()->HasBlacklistedItems());
1039 // Make sure the blacklisted prepopulate url isn't returned.
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());
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/")));
1054 // Make sure google is returned now.
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());
1066 EXPECT_EQ(1u, GetPrepopulatePages().size());
1069 // Remove all blacklisted sites.
1070 top_sites()->ClearBlacklistedURLs();
1071 EXPECT_FALSE(top_sites()->HasBlacklistedItems());
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));
1083 // Makes sure prepopulated pages exist.
1084 TEST_F(TopSitesImplTest, AddPrepopulatedPages) {
1086 q.QueryTopSites(top_sites(), true);
1087 EXPECT_EQ(GetPrepopulatePages().size(), q.urls().size());
1088 ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
1090 MostVisitedURLList pages = q.urls();
1091 EXPECT_FALSE(AddPrepopulatedPages(&pages));
1093 EXPECT_EQ(GetPrepopulatePages().size(), pages.size());
1095 ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
1098 } // namespace history