blob: 4974e9915976788fbcbbf8624609b689a89ef0fd [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/top_sites_factory.h"
#include "chrome/browser/history/top_sites_impl.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/testing_profile.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/top_sites.h"
#include "components/history/core/browser/top_sites_cache.h"
#include "components/history/core/browser/top_sites_observer.h"
#include "components/history/core/test/history_unittest_base.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace history {
namespace {
static const char kPrepopulatedPageURL[] =
"http://www.google.com/int/chrome/welcome.html";
// Create a TopSites implementation for testing.
scoped_refptr<RefcountedKeyedService> BuildTopSitesImpl(
content::BrowserContext* context) {
PrepopulatedPageList prepopulated_pages;
prepopulated_pages.push_back(PrepopulatedPage(GURL(kPrepopulatedPageURL),
base::string16(), -1, -1, 0));
scoped_refptr<TopSitesImpl> top_sites =
new TopSitesImpl(static_cast<Profile*>(context), prepopulated_pages);
top_sites->Init(
context->GetPath().Append(chrome::kTopSitesFilename),
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
return top_sites;
}
// Used by WaitForHistory, see it for details.
class WaitForHistoryTask : public HistoryDBTask {
public:
WaitForHistoryTask() {}
bool RunOnDBThread(HistoryBackend* backend, HistoryDatabase* db) override {
return true;
}
void DoneRunOnMainThread() override { base::MessageLoop::current()->Quit(); }
private:
~WaitForHistoryTask() override {}
DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
};
// Used for querying top sites. Either runs sequentially, or runs a nested
// nested message loop until the response is complete. The later is used when
// TopSites is queried before it finishes loading.
class TopSitesQuerier {
public:
TopSitesQuerier()
: number_of_callbacks_(0),
waiting_(false),
weak_ptr_factory_(this) {}
// Queries top sites. If |wait| is true a nested message loop is run until the
// callback is notified.
void QueryTopSites(TopSitesImpl* top_sites, bool wait) {
QueryAllTopSites(top_sites, wait, false);
}
// Queries top sites, including potentially forced URLs if
// |include_forced_urls| is true.
void QueryAllTopSites(TopSitesImpl* top_sites,
bool wait,
bool include_forced_urls) {
int start_number_of_callbacks = number_of_callbacks_;
top_sites->GetMostVisitedURLs(
base::Bind(&TopSitesQuerier::OnTopSitesAvailable,
weak_ptr_factory_.GetWeakPtr()),
include_forced_urls);
if (wait && start_number_of_callbacks == number_of_callbacks_) {
waiting_ = true;
base::MessageLoop::current()->Run();
}
}
void CancelRequest() {
weak_ptr_factory_.InvalidateWeakPtrs();
}
void set_urls(const MostVisitedURLList& urls) { urls_ = urls; }
const MostVisitedURLList& urls() const { return urls_; }
int number_of_callbacks() const { return number_of_callbacks_; }
private:
// Callback for TopSitesImpl::GetMostVisitedURLs.
void OnTopSitesAvailable(const history::MostVisitedURLList& data) {
urls_ = data;
number_of_callbacks_++;
if (waiting_) {
base::MessageLoop::current()->Quit();
waiting_ = false;
}
}
MostVisitedURLList urls_;
int number_of_callbacks_;
bool waiting_;
base::WeakPtrFactory<TopSitesQuerier> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(TopSitesQuerier);
};
// Extracts the data from |t1| into a SkBitmap. This is intended for usage of
// thumbnail data, which is stored as jpgs.
SkBitmap ExtractThumbnail(const base::RefCountedMemory& t1) {
scoped_ptr<SkBitmap> image(gfx::JPEGCodec::Decode(t1.front(),
t1.size()));
return image.get() ? *image : SkBitmap();
}
// Returns true if t1 and t2 contain the same data.
bool ThumbnailsAreEqual(base::RefCountedMemory* t1,
base::RefCountedMemory* t2) {
if (!t1 || !t2)
return false;
if (t1->size() != t2->size())
return false;
return !memcmp(t1->front(), t2->front(), t1->size());
}
} // namespace
class TopSitesImplTest : public HistoryUnitTestBase {
public:
TopSitesImplTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
db_thread_(BrowserThread::DB, &message_loop_) {
}
void SetUp() override {
profile_.reset(new TestingProfile);
if (CreateHistoryAndTopSites()) {
ASSERT_TRUE(profile_->CreateHistoryService(false, false));
ResetTopSites();
profile_->BlockUntilTopSitesLoaded();
}
}
void TearDown() override {
profile_.reset();
}
// Returns true if history and top sites should be created in SetUp.
virtual bool CreateHistoryAndTopSites() {
return true;
}
// Gets the thumbnail for |url| from TopSites.
SkBitmap GetThumbnail(const GURL& url) {
scoped_refptr<base::RefCountedMemory> data;
return top_sites()->GetPageThumbnail(url, false, &data) ?
ExtractThumbnail(*data.get()) : SkBitmap();
}
// Creates a bitmap of the specified color. Caller takes ownership.
gfx::Image CreateBitmap(SkColor color) {
SkBitmap thumbnail;
thumbnail.allocN32Pixels(4, 4);
thumbnail.eraseColor(color);
return gfx::Image::CreateFrom1xBitmap(thumbnail); // adds ref.
}
// Forces top sites to load top sites from history, then recreates top sites.
// Recreating top sites makes sure the changes from history are saved and
// loaded from the db.
void RefreshTopSitesAndRecreate() {
StartQueryForMostVisited();
WaitForHistory();
RecreateTopSitesAndBlock();
}
// Blocks the caller until history processes a task. This is useful if you
// need to wait until you know history has processed a task.
void WaitForHistory() {
history_service()->ScheduleDBTask(
scoped_ptr<history::HistoryDBTask>(new WaitForHistoryTask()),
&history_tracker_);
base::MessageLoop::current()->Run();
}
// Waits for top sites to finish processing a task. This is useful if you need
// to wait until top sites finishes processing a task.
void WaitForTopSites() {
top_sites()->backend_->DoEmptyRequest(
base::Bind(&TopSitesImplTest::QuitCallback, base::Unretained(this)),
&top_sites_tracker_);
base::MessageLoop::current()->Run();
}
TopSitesImpl* top_sites() {
return static_cast<TopSitesImpl*>(
TopSitesFactory::GetForProfile(profile_.get()).get());
}
TestingProfile* profile() {return profile_.get();}
HistoryService* history_service() {
return HistoryServiceFactory::GetForProfile(
profile_.get(), ServiceAccessType::EXPLICIT_ACCESS);
}
PrepopulatedPageList GetPrepopulatedPages() {
return top_sites()->GetPrepopulatedPages();
}
// Returns true if the TopSitesQuerier contains the prepopulate data starting
// at |start_index|.
void ContainsPrepopulatePages(const TopSitesQuerier& querier,
size_t start_index) {
PrepopulatedPageList prepopulate_pages = GetPrepopulatedPages();
ASSERT_LE(start_index + prepopulate_pages.size(), querier.urls().size());
for (size_t i = 0; i < prepopulate_pages.size(); ++i) {
EXPECT_EQ(prepopulate_pages[i].most_visited.url.spec(),
querier.urls()[start_index + i].url.spec())
<< " @ index " << i;
}
}
// Quit the current message loop when invoked. Useful when running a nested
// message loop.
void QuitCallback() {
base::MessageLoop::current()->Quit();
}
// Adds a page to history.
void AddPageToHistory(const GURL& url) {
RedirectList redirects;
redirects.push_back(url);
history_service()->AddPage(
url, base::Time::Now(), reinterpret_cast<ContextID>(1), 0, GURL(),
redirects, ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
false);
}
// Adds a page to history.
void AddPageToHistory(const GURL& url, const base::string16& title) {
RedirectList redirects;
redirects.push_back(url);
history_service()->AddPage(
url, base::Time::Now(), reinterpret_cast<ContextID>(1), 0, GURL(),
redirects, ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
false);
history_service()->SetPageTitle(url, title);
}
// Adds a page to history.
void AddPageToHistory(const GURL& url,
const base::string16& title,
const history::RedirectList& redirects,
base::Time time) {
history_service()->AddPage(
url, time, reinterpret_cast<ContextID>(1), 0, GURL(),
redirects, ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
false);
history_service()->SetPageTitle(url, title);
}
// Delets a url.
void DeleteURL(const GURL& url) {
history_service()->DeleteURL(url);
}
// Returns true if the thumbnail equals the specified bytes.
bool ThumbnailEqualsBytes(const gfx::Image& image,
base::RefCountedMemory* bytes) {
scoped_refptr<base::RefCountedBytes> encoded_image;
TopSitesImpl::EncodeBitmap(image, &encoded_image);
return ThumbnailsAreEqual(encoded_image.get(), bytes);
}
// Recreates top sites. This forces top sites to reread from the db.
void RecreateTopSitesAndBlock() {
// Recreate TopSites and wait for it to load.
ResetTopSites();
// As history already loaded we have to fake this call.
profile()->BlockUntilTopSitesLoaded();
}
// Wrappers that allow private TopSites functions to be called from the
// individual tests without making them all be friends.
GURL GetCanonicalURL(const GURL& url) {
return top_sites()->cache_->GetCanonicalURL(url);
}
void SetTopSites(const MostVisitedURLList& new_top_sites) {
top_sites()->SetTopSites(new_top_sites);
}
bool AddForcedURL(const GURL& url, base::Time time) {
return top_sites()->AddForcedURL(url, time);
}
void StartQueryForMostVisited() {
top_sites()->StartQueryForMostVisited();
}
void SetLastNumUrlsChanged(size_t value) {
top_sites()->last_num_urls_changed_ = value;
}
size_t last_num_urls_changed() { return top_sites()->last_num_urls_changed_; }
base::TimeDelta GetUpdateDelay() {
return top_sites()->GetUpdateDelay();
}
bool IsTopSitesLoaded() { return top_sites()->loaded_; }
bool AddPrepopulatedPages(MostVisitedURLList* urls) {
return top_sites()->AddPrepopulatedPages(urls, 0u);
}
void EmptyThreadSafeCache() {
base::AutoLock lock(top_sites()->lock_);
MostVisitedURLList empty;
top_sites()->thread_safe_cache_->SetTopSites(empty);
}
void ResetTopSites() {
// TopSites shutdown takes some time as it happens on the DB thread and does
// not support the existence of two TopSitesImpl for a single profile (due
// to database locking). TestingProfile::DestroyTopSites() waits for the
// TopSites cleanup to complete before returning.
profile_->DestroyTopSites();
TopSitesFactory::GetInstance()->SetTestingFactory(profile_.get(),
BuildTopSitesImpl);
}
private:
base::MessageLoopForUI message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread db_thread_;
scoped_ptr<TestingProfile> profile_;
// To cancel HistoryService tasks.
base::CancelableTaskTracker history_tracker_;
// To cancel TopSitesBackend tasks.
base::CancelableTaskTracker top_sites_tracker_;
DISALLOW_COPY_AND_ASSIGN(TopSitesImplTest);
}; // Class TopSitesImplTest
// Helper function for appending a URL to a vector of "most visited" URLs,
// using the default values for everything but the URL.
static void AppendMostVisitedURL(std::vector<MostVisitedURL>* list,
const GURL& url) {
MostVisitedURL mv;
mv.url = url;
mv.redirects.push_back(url);
list->push_back(mv);
}
// Helper function for appending a URL to a vector of "most visited" URLs,
// using the default values for everything but the URL.
static void AppendForcedMostVisitedURL(std::vector<MostVisitedURL>* list,
const GURL& url,
double last_forced_time) {
MostVisitedURL mv;
mv.url = url;
mv.last_forced_time = base::Time::FromJsTime(last_forced_time);
mv.redirects.push_back(url);
list->push_back(mv);
}
// Same as AppendMostVisitedURL except that it adds a redirect from the first
// URL to the second.
static void AppendMostVisitedURLWithRedirect(
std::vector<MostVisitedURL>* list,
const GURL& redirect_source, const GURL& redirect_dest) {
MostVisitedURL mv;
mv.url = redirect_dest;
mv.redirects.push_back(redirect_source);
mv.redirects.push_back(redirect_dest);
list->push_back(mv);
}
// Tests GetCanonicalURL.
TEST_F(TopSitesImplTest, GetCanonicalURL) {
// Have two chains:
// google.com -> www.google.com
// news.google.com (no redirects)
GURL news("http://news.google.com/");
GURL source("http://google.com/");
GURL dest("http://www.google.com/");
std::vector<MostVisitedURL> most_visited;
AppendMostVisitedURLWithRedirect(&most_visited, source, dest);
AppendMostVisitedURL(&most_visited, news);
SetTopSites(most_visited);
// Random URLs not in the database are returned unchanged.
GURL result = GetCanonicalURL(GURL("http://fark.com/"));
EXPECT_EQ(GURL("http://fark.com/"), result);
// Easy case, there are no redirects and the exact URL is stored.
result = GetCanonicalURL(news);
EXPECT_EQ(news, result);
// The URL in question is the source URL in a redirect list.
result = GetCanonicalURL(source);
EXPECT_EQ(dest, result);
// The URL in question is the destination of a redirect.
result = GetCanonicalURL(dest);
EXPECT_EQ(dest, result);
}
// Tests DiffMostVisited.
TEST_F(TopSitesImplTest, DiffMostVisited) {
GURL stays_the_same("http://staysthesame/");
GURL gets_added_1("http://getsadded1/");
GURL gets_added_2("http://getsadded2/");
GURL gets_deleted_1("http://getsdeleted1/");
GURL gets_moved_1("http://getsmoved1/");
std::vector<MostVisitedURL> old_list;
AppendMostVisitedURL(&old_list, stays_the_same); // 0 (unchanged)
AppendMostVisitedURL(&old_list, gets_deleted_1); // 1 (deleted)
AppendMostVisitedURL(&old_list, gets_moved_1); // 2 (moved to 3)
std::vector<MostVisitedURL> new_list;
AppendMostVisitedURL(&new_list, stays_the_same); // 0 (unchanged)
AppendMostVisitedURL(&new_list, gets_added_1); // 1 (added)
AppendMostVisitedURL(&new_list, gets_added_2); // 2 (added)
AppendMostVisitedURL(&new_list, gets_moved_1); // 3 (moved from 2)
history::TopSitesDelta delta;
history::TopSitesImpl::DiffMostVisited(old_list, new_list, &delta);
ASSERT_EQ(2u, delta.added.size());
EXPECT_TRUE(gets_added_1 == delta.added[0].url.url);
EXPECT_EQ(1, delta.added[0].rank);
EXPECT_TRUE(gets_added_2 == delta.added[1].url.url);
EXPECT_EQ(2, delta.added[1].rank);
ASSERT_EQ(1u, delta.deleted.size());
EXPECT_TRUE(gets_deleted_1 == delta.deleted[0].url);
ASSERT_EQ(1u, delta.moved.size());
EXPECT_TRUE(gets_moved_1 == delta.moved[0].url.url);
EXPECT_EQ(3, delta.moved[0].rank);
}
// Tests DiffMostVisited with forced URLs.
TEST_F(TopSitesImplTest, DiffMostVisitedWithForced) {
// Forced URLs.
GURL stays_the_same_1("http://staysthesame1/");
GURL new_last_forced_time("http://newlastforcedtime/");
GURL stays_the_same_2("http://staysthesame2/");
GURL move_to_nonforced("http://movetononforced/");
GURL gets_added_1("http://getsadded1/");
GURL gets_deleted_1("http://getsdeleted1/");
// Non-forced URLs.
GURL move_to_forced("http://movetoforced/");
GURL stays_the_same_3("http://staysthesame3/");
GURL gets_added_2("http://getsadded2/");
GURL gets_deleted_2("http://getsdeleted2/");
GURL gets_moved_1("http://getsmoved1/");
std::vector<MostVisitedURL> old_list;
AppendForcedMostVisitedURL(&old_list, stays_the_same_1, 1000);
AppendForcedMostVisitedURL(&old_list, new_last_forced_time, 2000);
AppendForcedMostVisitedURL(&old_list, stays_the_same_2, 3000);
AppendForcedMostVisitedURL(&old_list, move_to_nonforced, 4000);
AppendForcedMostVisitedURL(&old_list, gets_deleted_1, 5000);
AppendMostVisitedURL(&old_list, move_to_forced);
AppendMostVisitedURL(&old_list, stays_the_same_3);
AppendMostVisitedURL(&old_list, gets_deleted_2);
AppendMostVisitedURL(&old_list, gets_moved_1);
std::vector<MostVisitedURL> new_list;
AppendForcedMostVisitedURL(&new_list, stays_the_same_1, 1000);
AppendForcedMostVisitedURL(&new_list, stays_the_same_2, 3000);
AppendForcedMostVisitedURL(&new_list, new_last_forced_time, 4000);
AppendForcedMostVisitedURL(&new_list, gets_added_1, 5000);
AppendForcedMostVisitedURL(&new_list, move_to_forced, 6000);
AppendMostVisitedURL(&new_list, move_to_nonforced);
AppendMostVisitedURL(&new_list, stays_the_same_3);
AppendMostVisitedURL(&new_list, gets_added_2);
AppendMostVisitedURL(&new_list, gets_moved_1);
history::TopSitesDelta delta;
history::TopSitesImpl::DiffMostVisited(old_list, new_list, &delta);
ASSERT_EQ(2u, delta.added.size());
EXPECT_TRUE(gets_added_1 == delta.added[0].url.url);
EXPECT_EQ(-1, delta.added[0].rank);
EXPECT_TRUE(gets_added_2 == delta.added[1].url.url);
EXPECT_EQ(2, delta.added[1].rank);
ASSERT_EQ(2u, delta.deleted.size());
EXPECT_TRUE(gets_deleted_1 == delta.deleted[0].url);
EXPECT_TRUE(gets_deleted_2 == delta.deleted[1].url);
ASSERT_EQ(3u, delta.moved.size());
EXPECT_TRUE(new_last_forced_time == delta.moved[0].url.url);
EXPECT_EQ(-1, delta.moved[0].rank);
EXPECT_EQ(base::Time::FromJsTime(4000), delta.moved[0].url.last_forced_time);
EXPECT_TRUE(move_to_forced == delta.moved[1].url.url);
EXPECT_EQ(-1, delta.moved[1].rank);
EXPECT_EQ(base::Time::FromJsTime(6000), delta.moved[1].url.last_forced_time);
EXPECT_TRUE(move_to_nonforced == delta.moved[2].url.url);
EXPECT_EQ(0, delta.moved[2].rank);
EXPECT_TRUE(delta.moved[2].url.last_forced_time.is_null());
}
// Tests SetPageThumbnail.
TEST_F(TopSitesImplTest, SetPageThumbnail) {
GURL url1a("http://google.com/");
GURL url1b("http://www.google.com/");
GURL url2("http://images.google.com/");
GURL invalid_url("chrome://favicon/http://google.com/");
std::vector<MostVisitedURL> list;
AppendMostVisitedURL(&list, url2);
MostVisitedURL mv;
mv.url = url1b;
mv.redirects.push_back(url1a);
mv.redirects.push_back(url1b);
list.push_back(mv);
// Save our most visited data containing that one site.
SetTopSites(list);
// Create a dummy thumbnail.
gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
base::Time now = base::Time::Now();
ThumbnailScore low_score(1.0, true, true, now);
ThumbnailScore medium_score(0.5, true, true, now);
ThumbnailScore high_score(0.0, true, true, now);
// Setting the thumbnail for invalid pages should fail.
EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
thumbnail, medium_score));
// Setting the thumbnail for url2 should succeed, lower scores shouldn't
// replace it, higher scores should.
EXPECT_TRUE(top_sites()->SetPageThumbnail(url2, thumbnail, medium_score));
EXPECT_FALSE(top_sites()->SetPageThumbnail(url2, thumbnail, low_score));
EXPECT_TRUE(top_sites()->SetPageThumbnail(url2, thumbnail, high_score));
// Set on the redirect source should succeed. It should be replacable by
// the same score on the redirect destination, which in turn should not
// be replaced by the source again.
EXPECT_TRUE(top_sites()->SetPageThumbnail(url1a, thumbnail, medium_score));
EXPECT_TRUE(top_sites()->SetPageThumbnail(url1b, thumbnail, medium_score));
EXPECT_FALSE(top_sites()->SetPageThumbnail(url1a, thumbnail, medium_score));
}
// Makes sure a thumbnail is correctly removed when the page is removed.
TEST_F(TopSitesImplTest, ThumbnailRemoved) {
GURL url("http://google.com/");
// Configure top sites with 'google.com'.
std::vector<MostVisitedURL> list;
AppendMostVisitedURL(&list, url);
SetTopSites(list);
// Create a dummy thumbnail.
gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
base::Time now = base::Time::Now();
ThumbnailScore low_score(1.0, true, true, now);
ThumbnailScore medium_score(0.5, true, true, now);
ThumbnailScore high_score(0.0, true, true, now);
// Set the thumbnail.
EXPECT_TRUE(top_sites()->SetPageThumbnail(url, thumbnail, medium_score));
// Make sure the thumbnail was actually set.
scoped_refptr<base::RefCountedMemory> result;
EXPECT_TRUE(top_sites()->GetPageThumbnail(url, false, &result));
EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
// Reset the thumbnails and make sure we don't get it back.
SetTopSites(MostVisitedURLList());
RefreshTopSitesAndRecreate();
EXPECT_FALSE(top_sites()->GetPageThumbnail(url, false, &result));
}
// Tests GetPageThumbnail.
TEST_F(TopSitesImplTest, GetPageThumbnail) {
MostVisitedURLList url_list;
MostVisitedURL url1;
url1.url = GURL("http://asdf.com");
url1.redirects.push_back(url1.url);
url_list.push_back(url1);
MostVisitedURL url2;
url2.url = GURL("http://gmail.com");
url2.redirects.push_back(url2.url);
url2.redirects.push_back(GURL("http://mail.google.com"));
url_list.push_back(url2);
SetTopSites(url_list);
// Create a dummy thumbnail.
gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
ThumbnailScore score(0.5, true, true, base::Time::Now());
scoped_refptr<base::RefCountedMemory> result;
EXPECT_TRUE(top_sites()->SetPageThumbnail(url1.url, thumbnail, score));
EXPECT_TRUE(top_sites()->GetPageThumbnail(url1.url, false, &result));
EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://gmail.com"),
thumbnail, score));
EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://gmail.com"),
false,
&result));
// Get a thumbnail via a redirect.
EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://mail.google.com"),
false,
&result));
EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://mail.google.com"),
thumbnail, score));
EXPECT_TRUE(top_sites()->GetPageThumbnail(url2.url, false, &result));
EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
}
// Tests GetMostVisitedURLs.
TEST_F(TopSitesImplTest, GetMostVisited) {
GURL news("http://news.google.com/");
GURL google("http://google.com/");
AddPageToHistory(news);
AddPageToHistory(google);
StartQueryForMostVisited();
WaitForHistory();
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(1, querier.number_of_callbacks());
// 2 extra prepopulated URLs.
ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(news, querier.urls()[0].url);
EXPECT_EQ(google, querier.urls()[1].url);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
}
// Makes sure changes done to top sites get mirrored to the db.
TEST_F(TopSitesImplTest, SaveToDB) {
MostVisitedURL url;
GURL asdf_url("http://asdf.com");
base::string16 asdf_title(base::ASCIIToUTF16("ASDF"));
GURL google_url("http://google.com");
base::string16 google_title(base::ASCIIToUTF16("Google"));
GURL news_url("http://news.google.com");
base::string16 news_title(base::ASCIIToUTF16("Google News"));
// Add asdf_url to history.
AddPageToHistory(asdf_url, asdf_title);
// Make TopSites reread from the db.
StartQueryForMostVisited();
WaitForHistory();
// Add a thumbnail.
gfx::Image tmp_bitmap(CreateBitmap(SK_ColorBLUE));
ASSERT_TRUE(top_sites()->SetPageThumbnail(asdf_url, tmp_bitmap,
ThumbnailScore()));
RecreateTopSitesAndBlock();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(asdf_url, querier.urls()[0].url);
EXPECT_EQ(asdf_title, querier.urls()[0].title);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
scoped_refptr<base::RefCountedMemory> read_data;
EXPECT_TRUE(top_sites()->GetPageThumbnail(asdf_url, false, &read_data));
EXPECT_TRUE(ThumbnailEqualsBytes(tmp_bitmap, read_data.get()));
}
MostVisitedURL url2;
url2.url = google_url;
url2.title = google_title;
url2.redirects.push_back(url2.url);
AddPageToHistory(url2.url, url2.title);
// Add new thumbnail at rank 0 and shift the other result to 1.
ASSERT_TRUE(top_sites()->SetPageThumbnail(google_url,
tmp_bitmap,
ThumbnailScore()));
// Make TopSites reread from the db.
RefreshTopSitesAndRecreate();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(asdf_url, querier.urls()[0].url);
EXPECT_EQ(asdf_title, querier.urls()[0].title);
EXPECT_EQ(google_url, querier.urls()[1].url);
EXPECT_EQ(google_title, querier.urls()[1].title);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
}
}
// Makes sure forced URLs in top sites get mirrored to the db.
TEST_F(TopSitesImplTest, SaveForcedToDB) {
MostVisitedURL url;
GURL asdf_url("http://asdf.com");
base::string16 asdf_title(base::ASCIIToUTF16("ASDF"));
GURL google_url("http://google.com");
base::string16 google_title(base::ASCIIToUTF16("Google"));
GURL news_url("http://news.google.com");
base::string16 news_title(base::ASCIIToUTF16("Google News"));
// Add a number of forced URLs.
std::vector<MostVisitedURL> list;
AppendForcedMostVisitedURL(&list, GURL("http://forced1"), 1000);
list[0].title = base::ASCIIToUTF16("forced1");
AppendForcedMostVisitedURL(&list, GURL("http://forced2"), 2000);
AppendForcedMostVisitedURL(&list, GURL("http://forced3"), 3000);
AppendForcedMostVisitedURL(&list, GURL("http://forced4"), 4000);
SetTopSites(list);
// Add a thumbnail.
gfx::Image red_thumbnail(CreateBitmap(SK_ColorRED));
ASSERT_TRUE(top_sites()->SetPageThumbnail(
GURL("http://forced1"), red_thumbnail, ThumbnailScore()));
// Get the original thumbnail for later comparison. Some compression can
// happen in |top_sites| and we don't want to depend on that.
SkBitmap orig_thumbnail = GetThumbnail(GURL("http://forced1"));
// Force-flush the cache to ensure we don't reread from it inadvertently.
EmptyThreadSafeCache();
// Make TopSites reread from the db.
StartQueryForMostVisited();
WaitForHistory();
TopSitesQuerier querier;
querier.QueryAllTopSites(top_sites(), true, true);
ASSERT_EQ(4u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(GURL("http://forced1"), querier.urls()[0].url);
EXPECT_EQ(base::ASCIIToUTF16("forced1"), querier.urls()[0].title);
SkBitmap thumbnail = GetThumbnail(GURL("http://forced1"));
ASSERT_EQ(orig_thumbnail.getSize(), thumbnail.getSize());
orig_thumbnail.lockPixels();
thumbnail.lockPixels();
EXPECT_EQ(0, memcmp(orig_thumbnail.getPixels(), thumbnail.getPixels(),
orig_thumbnail.getSize()));
thumbnail.unlockPixels();
orig_thumbnail.unlockPixels();
EXPECT_EQ(base::Time::FromJsTime(1000), querier.urls()[0].last_forced_time);
EXPECT_EQ(GURL("http://forced2"), querier.urls()[1].url);
EXPECT_EQ(base::Time::FromJsTime(2000), querier.urls()[1].last_forced_time);
EXPECT_EQ(GURL("http://forced3"), querier.urls()[2].url);
EXPECT_EQ(base::Time::FromJsTime(3000), querier.urls()[2].last_forced_time);
EXPECT_EQ(GURL("http://forced4"), querier.urls()[3].url);
EXPECT_EQ(base::Time::FromJsTime(4000), querier.urls()[3].last_forced_time);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 4));
}
// More permutations of saving to db.
TEST_F(TopSitesImplTest, RealDatabase) {
MostVisitedURL url;
GURL asdf_url("http://asdf.com");
base::string16 asdf_title(base::ASCIIToUTF16("ASDF"));
GURL google1_url("http://google.com");
GURL google2_url("http://google.com/redirect");
GURL google3_url("http://www.google.com");
base::string16 google_title(base::ASCIIToUTF16("Google"));
GURL news_url("http://news.google.com");
base::string16 news_title(base::ASCIIToUTF16("Google News"));
url.url = asdf_url;
url.title = asdf_title;
url.redirects.push_back(url.url);
gfx::Image asdf_thumbnail(CreateBitmap(SK_ColorRED));
ASSERT_TRUE(top_sites()->SetPageThumbnail(
asdf_url, asdf_thumbnail, ThumbnailScore()));
base::Time add_time(base::Time::Now());
AddPageToHistory(url.url, url.title, url.redirects, add_time);
RefreshTopSitesAndRecreate();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(asdf_url, querier.urls()[0].url);
EXPECT_EQ(asdf_title, querier.urls()[0].title);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
scoped_refptr<base::RefCountedMemory> read_data;
EXPECT_TRUE(top_sites()->GetPageThumbnail(asdf_url, false, &read_data));
EXPECT_TRUE(ThumbnailEqualsBytes(asdf_thumbnail, read_data.get()));
}
MostVisitedURL url2;
url2.url = google3_url;
url2.title = google_title;
url2.redirects.push_back(google1_url);
url2.redirects.push_back(google2_url);
url2.redirects.push_back(google3_url);
AddPageToHistory(google3_url, url2.title, url2.redirects,
add_time - base::TimeDelta::FromMinutes(1));
// Add google twice so that it becomes the first visited site.
AddPageToHistory(google3_url, url2.title, url2.redirects,
add_time - base::TimeDelta::FromMinutes(2));
gfx::Image google_thumbnail(CreateBitmap(SK_ColorBLUE));
ASSERT_TRUE(top_sites()->SetPageThumbnail(
url2.url, google_thumbnail, ThumbnailScore()));
RefreshTopSitesAndRecreate();
{
scoped_refptr<base::RefCountedMemory> read_data;
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(google1_url, querier.urls()[0].url);
EXPECT_EQ(google_title, querier.urls()[0].title);
ASSERT_EQ(3u, querier.urls()[0].redirects.size());
EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, false, &read_data));
EXPECT_TRUE(ThumbnailEqualsBytes(google_thumbnail, read_data.get()));
EXPECT_EQ(asdf_url, querier.urls()[1].url);
EXPECT_EQ(asdf_title, querier.urls()[1].title);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
}
gfx::Image weewar_bitmap(CreateBitmap(SK_ColorYELLOW));
base::Time thumbnail_time(base::Time::Now());
ThumbnailScore low_score(1.0, true, true, thumbnail_time);
ThumbnailScore medium_score(0.5, true, true, thumbnail_time);
ThumbnailScore high_score(0.0, true, true, thumbnail_time);
// 1. Set to weewar. (Writes the thumbnail to the DB.)
EXPECT_TRUE(top_sites()->SetPageThumbnail(google3_url,
weewar_bitmap,
medium_score));
RefreshTopSitesAndRecreate();
{
scoped_refptr<base::RefCountedMemory> read_data;
EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, false, &read_data));
EXPECT_TRUE(ThumbnailEqualsBytes(weewar_bitmap, read_data.get()));
}
gfx::Image green_bitmap(CreateBitmap(SK_ColorGREEN));
// 2. Set to google - low score.
EXPECT_FALSE(top_sites()->SetPageThumbnail(google3_url,
green_bitmap,
low_score));
// 3. Set to google - high score.
EXPECT_TRUE(top_sites()->SetPageThumbnail(google1_url,
green_bitmap,
high_score));
// Check that the thumbnail was updated.
RefreshTopSitesAndRecreate();
{
scoped_refptr<base::RefCountedMemory> read_data;
EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, false, &read_data));
EXPECT_FALSE(ThumbnailEqualsBytes(weewar_bitmap, read_data.get()));
EXPECT_TRUE(ThumbnailEqualsBytes(green_bitmap, read_data.get()));
}
}
TEST_F(TopSitesImplTest, DeleteNotifications) {
GURL google1_url("http://google.com");
GURL google2_url("http://google.com/redirect");
GURL google3_url("http://www.google.com");
base::string16 google_title(base::ASCIIToUTF16("Google"));
GURL news_url("http://news.google.com");
base::string16 news_title(base::ASCIIToUTF16("Google News"));
AddPageToHistory(google1_url, google_title);
AddPageToHistory(news_url, news_title);
RefreshTopSitesAndRecreate();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(GetPrepopulatedPages().size() + 2, querier.urls().size());
}
DeleteURL(news_url);
// Wait for history to process the deletion.
WaitForHistory();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(google_title, querier.urls()[0].title);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
}
// Now reload. This verifies topsites actually wrote the deletion to disk.
RefreshTopSitesAndRecreate();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(1u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(google_title, querier.urls()[0].title);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
}
DeleteURL(google1_url);
// Wait for history to process the deletion.
WaitForHistory();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(GetPrepopulatedPages().size(), querier.urls().size());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
}
// Now reload. This verifies topsites actually wrote the deletion to disk.
RefreshTopSitesAndRecreate();
{
TopSitesQuerier querier;
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(GetPrepopulatedPages().size(), querier.urls().size());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
}
}
// Makes sure GetUpdateDelay is updated appropriately.
TEST_F(TopSitesImplTest, GetUpdateDelay) {
SetLastNumUrlsChanged(0);
EXPECT_EQ(30, GetUpdateDelay().InSeconds());
MostVisitedURLList url_list;
url_list.resize(20);
GURL tmp_url(GURL("http://x"));
for (size_t i = 0; i < url_list.size(); ++i) {
url_list[i].url = tmp_url;
url_list[i].redirects.push_back(tmp_url);
}
SetTopSites(url_list);
EXPECT_EQ(20u, last_num_urls_changed());
SetLastNumUrlsChanged(0);
EXPECT_EQ(60, GetUpdateDelay().InMinutes());
SetLastNumUrlsChanged(3);
EXPECT_EQ(52, GetUpdateDelay().InMinutes());
SetLastNumUrlsChanged(20);
EXPECT_EQ(1, GetUpdateDelay().InMinutes());
}
// Verifies that callbacks are notified correctly if requested before top sites
// has loaded.
TEST_F(TopSitesImplTest, NotifyCallbacksWhenLoaded) {
// Recreate top sites. It won't be loaded now.
ResetTopSites();
EXPECT_FALSE(IsTopSitesLoaded());
TopSitesQuerier querier1;
TopSitesQuerier querier2;
TopSitesQuerier querier3;
// Starts the queries.
querier1.QueryTopSites(top_sites(), false);
querier2.QueryTopSites(top_sites(), false);
querier3.QueryTopSites(top_sites(), false);
// We shouldn't have gotten a callback.
EXPECT_EQ(0, querier1.number_of_callbacks());
EXPECT_EQ(0, querier2.number_of_callbacks());
EXPECT_EQ(0, querier3.number_of_callbacks());
// Wait for loading to complete.
profile()->BlockUntilTopSitesLoaded();
// Now we should have gotten the callbacks.
EXPECT_EQ(1, querier1.number_of_callbacks());
EXPECT_EQ(GetPrepopulatedPages().size(), querier1.urls().size());
EXPECT_EQ(1, querier2.number_of_callbacks());
EXPECT_EQ(GetPrepopulatedPages().size(), querier2.urls().size());
EXPECT_EQ(1, querier3.number_of_callbacks());
EXPECT_EQ(GetPrepopulatedPages().size(), querier3.urls().size());
// Reset the top sites.
MostVisitedURLList pages;
MostVisitedURL url;
url.url = GURL("http://1.com/");
url.redirects.push_back(url.url);
pages.push_back(url);
url.url = GURL("http://2.com/");
url.redirects.push_back(url.url);
pages.push_back(url);
SetTopSites(pages);
// Recreate top sites. It won't be loaded now.
ResetTopSites();
EXPECT_FALSE(IsTopSitesLoaded());
TopSitesQuerier querier4;
// Query again.
querier4.QueryTopSites(top_sites(), false);
// We shouldn't have gotten a callback.
EXPECT_EQ(0, querier4.number_of_callbacks());
// Wait for loading to complete.
profile()->BlockUntilTopSitesLoaded();
// Now we should have gotten the callbacks.
EXPECT_EQ(1, querier4.number_of_callbacks());
ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier4.urls().size());
EXPECT_EQ("http://1.com/", querier4.urls()[0].url.spec());
EXPECT_EQ("http://2.com/", querier4.urls()[1].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier4, 2));
// Reset the top sites again, this time don't reload.
url.url = GURL("http://3.com/");
url.redirects.push_back(url.url);
pages.push_back(url);
SetTopSites(pages);
// Query again.
TopSitesQuerier querier5;
querier5.QueryTopSites(top_sites(), true);
EXPECT_EQ(1, querier5.number_of_callbacks());
ASSERT_EQ(3u + GetPrepopulatedPages().size(), querier5.urls().size());
EXPECT_EQ("http://1.com/", querier5.urls()[0].url.spec());
EXPECT_EQ("http://2.com/", querier5.urls()[1].url.spec());
EXPECT_EQ("http://3.com/", querier5.urls()[2].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier5, 3));
}
// Makes sure canceled requests are not notified.
TEST_F(TopSitesImplTest, CancelingRequestsForTopSites) {
// Recreate top sites. It won't be loaded now.
ResetTopSites();
EXPECT_FALSE(IsTopSitesLoaded());
TopSitesQuerier querier1;
TopSitesQuerier querier2;
// Starts the queries.
querier1.QueryTopSites(top_sites(), false);
querier2.QueryTopSites(top_sites(), false);
// We shouldn't have gotten a callback.
EXPECT_EQ(0, querier1.number_of_callbacks());
EXPECT_EQ(0, querier2.number_of_callbacks());
querier2.CancelRequest();
// Wait for loading to complete.
profile()->BlockUntilTopSitesLoaded();
// The first callback should succeed.
EXPECT_EQ(1, querier1.number_of_callbacks());
EXPECT_EQ(GetPrepopulatedPages().size(), querier1.urls().size());
// And the canceled callback should not be notified.
EXPECT_EQ(0, querier2.number_of_callbacks());
}
// Makes sure temporary thumbnails are copied over correctly.
TEST_F(TopSitesImplTest, AddTemporaryThumbnail) {
GURL unknown_url("http://news.google.com/");
GURL invalid_url("chrome://thumb/http://google.com/");
GURL url1a("http://google.com/");
GURL url1b("http://www.google.com/");
// Create a dummy thumbnail.
gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
ThumbnailScore medium_score(0.5, true, true, base::Time::Now());
// Don't store thumbnails for Javascript URLs.
EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
thumbnail,
medium_score));
// Store thumbnails for unknown (but valid) URLs temporarily - calls
// AddTemporaryThumbnail.
EXPECT_TRUE(top_sites()->SetPageThumbnail(unknown_url,
thumbnail,
medium_score));
// We shouldn't get the thumnail back though (the url isn't in to sites yet).
scoped_refptr<base::RefCountedMemory> out;
EXPECT_FALSE(top_sites()->GetPageThumbnail(unknown_url, false, &out));
// But we should be able to get the temporary page thumbnail score.
ThumbnailScore out_score;
EXPECT_TRUE(top_sites()->GetTemporaryPageThumbnailScore(unknown_url,
&out_score));
EXPECT_TRUE(medium_score.Equals(out_score));
std::vector<MostVisitedURL> list;
MostVisitedURL mv;
mv.url = unknown_url;
mv.redirects.push_back(mv.url);
mv.redirects.push_back(url1a);
mv.redirects.push_back(url1b);
list.push_back(mv);
// Update URLs. This should result in using thumbnail.
SetTopSites(list);
ASSERT_TRUE(top_sites()->GetPageThumbnail(unknown_url, false, &out));
EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, out.get()));
}
// Tests variations of blacklisting without testing prepopulated page
// blacklisting.
TEST_F(TopSitesImplTest, BlacklistingWithoutPrepopulated) {
MostVisitedURLList pages;
MostVisitedURL url, url1;
url.url = GURL("http://bbc.com/");
url.redirects.push_back(url.url);
pages.push_back(url);
url1.url = GURL("http://google.com/");
url1.redirects.push_back(url1.url);
pages.push_back(url1);
SetTopSites(pages);
EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
// Blacklist google.com.
top_sites()->AddBlacklistedURL(GURL("http://google.com/"));
EXPECT_TRUE(top_sites()->HasBlacklistedItems());
EXPECT_TRUE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
// Make sure the blacklisted site isn't returned in the results.
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
}
// Recreate top sites and make sure blacklisted url was correctly read.
RecreateTopSitesAndBlock();
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
}
// Mark google as no longer blacklisted.
top_sites()->RemoveBlacklistedURL(GURL("http://google.com/"));
EXPECT_FALSE(top_sites()->HasBlacklistedItems());
EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
// Make sure google is returned now.
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
}
// Remove all blacklisted sites.
top_sites()->ClearBlacklistedURLs();
EXPECT_FALSE(top_sites()->HasBlacklistedItems());
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 2));
}
}
// Tests variations of blacklisting including blacklisting prepopulated pages.
// This test is disable for Android because Android does not have any
// prepopulated pages.
TEST_F(TopSitesImplTest, BlacklistingWithPrepopulated) {
MostVisitedURLList pages;
MostVisitedURL url, url1;
url.url = GURL("http://bbc.com/");
url.redirects.push_back(url.url);
pages.push_back(url);
url1.url = GURL("http://google.com/");
url1.redirects.push_back(url1.url);
pages.push_back(url1);
SetTopSites(pages);
EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
// Blacklist google.com.
top_sites()->AddBlacklistedURL(GURL("http://google.com/"));
DCHECK_GE(GetPrepopulatedPages().size(), 1u);
GURL prepopulate_url = GetPrepopulatedPages()[0].most_visited.url;
EXPECT_TRUE(top_sites()->HasBlacklistedItems());
EXPECT_TRUE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
EXPECT_FALSE(top_sites()->IsBlacklisted(prepopulate_url));
// Make sure the blacklisted site isn't returned in the results.
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
ASSERT_EQ(1u + GetPrepopulatedPages().size(), q.urls().size());
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
}
// Recreate top sites and make sure blacklisted url was correctly read.
RecreateTopSitesAndBlock();
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
ASSERT_EQ(1u + GetPrepopulatedPages().size(), q.urls().size());
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
}
// Blacklist one of the prepopulate urls.
top_sites()->AddBlacklistedURL(prepopulate_url);
EXPECT_TRUE(top_sites()->HasBlacklistedItems());
// Make sure the blacklisted prepopulate url isn't returned.
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
ASSERT_EQ(1u + GetPrepopulatedPages().size() - 1, q.urls().size());
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
for (size_t i = 1; i < q.urls().size(); ++i)
EXPECT_NE(prepopulate_url.spec(), q.urls()[i].url.spec());
}
// Mark google as no longer blacklisted.
top_sites()->RemoveBlacklistedURL(GURL("http://google.com/"));
EXPECT_TRUE(top_sites()->HasBlacklistedItems());
EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
// Make sure google is returned now.
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
ASSERT_EQ(2u + GetPrepopulatedPages().size() - 1, q.urls().size());
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
// Android has only one prepopulated page which has been blacklisted, so
// only 2 urls are returned.
if (q.urls().size() > 2)
EXPECT_NE(prepopulate_url.spec(), q.urls()[2].url.spec());
else
EXPECT_EQ(1u, GetPrepopulatedPages().size());
}
// Remove all blacklisted sites.
top_sites()->ClearBlacklistedURLs();
EXPECT_FALSE(top_sites()->HasBlacklistedItems());
{
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
ASSERT_EQ(2u + GetPrepopulatedPages().size(), q.urls().size());
EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 2));
}
}
// Makes sure prepopulated pages exist.
TEST_F(TopSitesImplTest, AddPrepopulatedPages) {
TopSitesQuerier q;
q.QueryTopSites(top_sites(), true);
EXPECT_EQ(GetPrepopulatedPages().size(), q.urls().size());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
MostVisitedURLList pages = q.urls();
EXPECT_FALSE(AddPrepopulatedPages(&pages));
EXPECT_EQ(GetPrepopulatedPages().size(), pages.size());
q.set_urls(pages);
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
}
// Ensure calling SetTopSites with forced sites already in the DB works.
// This test both eviction and
TEST_F(TopSitesImplTest, SetForcedTopSites) {
// Create forced elements in old URL list.
MostVisitedURLList old_url_list;
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/0"), 1000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/1"), 4000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/2"), 7000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/3"), 10000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/4"), 11000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/5"), 12000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/6"), 13000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/7"), 18000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://oldforced/8"), 21000);
const size_t kNumOldForcedURLs = 9;
// Create forced elements in new URL list.
MostVisitedURLList new_url_list;
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/0"), 2000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/1"), 3000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/2"), 5000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/3"), 6000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/4"), 8000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/5"), 9000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/6"), 14000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/7"), 15000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/8"), 16000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/9"), 17000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/10"), 19000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/11"), 20000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://newforced/12"), 22000);
// Setup a number non-forced URLs in both old and new list.
const size_t kNumNonForcedURLs = 20; // Maximum number of non-forced URLs.
for (size_t i = 0; i < kNumNonForcedURLs; ++i) {
std::ostringstream url;
url << "http://oldnonforced/" << i;
AppendMostVisitedURL(&old_url_list, GURL(url.str()));
url.str("");
url << "http://newnonforced/" << i;
AppendMostVisitedURL(&new_url_list, GURL(url.str()));
}
// Set the initial list of URLs.
SetTopSites(old_url_list);
EXPECT_EQ(kNumOldForcedURLs + kNumNonForcedURLs, last_num_urls_changed());
TopSitesQuerier querier;
// Query only non-forced URLs first.
querier.QueryTopSites(top_sites(), false);
ASSERT_EQ(kNumNonForcedURLs, querier.urls().size());
// Check first URL.
EXPECT_EQ("http://oldnonforced/0", querier.urls()[0].url.spec());
// Query all URLs.
querier.QueryAllTopSites(top_sites(), false, true);
EXPECT_EQ(kNumOldForcedURLs + kNumNonForcedURLs, querier.urls().size());
// Check first URLs.
EXPECT_EQ("http://oldforced/0", querier.urls()[0].url.spec());
EXPECT_EQ("http://oldnonforced/0",
querier.urls()[kNumOldForcedURLs].url.spec());
// Set the new list of URLs.
SetTopSites(new_url_list);
// Query all URLs.
querier.QueryAllTopSites(top_sites(), false, true);
// We should have reached the maximum of 20 forced URLs.
ASSERT_EQ(20 + kNumNonForcedURLs, querier.urls().size());
// Check forced URLs. They follow the order of timestamps above, smaller
// timestamps since they were evicted.
EXPECT_EQ("http://newforced/1", querier.urls()[0].url.spec());
EXPECT_EQ(3000, querier.urls()[0].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/1", querier.urls()[1].url.spec());
EXPECT_EQ(4000, querier.urls()[1].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/2", querier.urls()[2].url.spec());
EXPECT_EQ(5000, querier.urls()[2].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/3", querier.urls()[3].url.spec());
EXPECT_EQ(6000, querier.urls()[3].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/2", querier.urls()[4].url.spec());
EXPECT_EQ(7000, querier.urls()[4].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/4", querier.urls()[5].url.spec());
EXPECT_EQ(8000, querier.urls()[5].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/5", querier.urls()[6].url.spec());
EXPECT_EQ(9000, querier.urls()[6].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/3", querier.urls()[7].url.spec());
EXPECT_EQ(10000, querier.urls()[7].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/4", querier.urls()[8].url.spec());
EXPECT_EQ(11000, querier.urls()[8].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/5", querier.urls()[9].url.spec());
EXPECT_EQ(12000, querier.urls()[9].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/6", querier.urls()[10].url.spec());
EXPECT_EQ(13000, querier.urls()[10].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/6", querier.urls()[11].url.spec());
EXPECT_EQ(14000, querier.urls()[11].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/7", querier.urls()[12].url.spec());
EXPECT_EQ(15000, querier.urls()[12].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/8", querier.urls()[13].url.spec());
EXPECT_EQ(16000, querier.urls()[13].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/9", querier.urls()[14].url.spec());
EXPECT_EQ(17000, querier.urls()[14].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/7", querier.urls()[15].url.spec());
EXPECT_EQ(18000, querier.urls()[15].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/10", querier.urls()[16].url.spec());
EXPECT_EQ(19000, querier.urls()[16].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/11", querier.urls()[17].url.spec());
EXPECT_EQ(20000, querier.urls()[17].last_forced_time.ToJsTime());
EXPECT_EQ("http://oldforced/8", querier.urls()[18].url.spec());
EXPECT_EQ(21000, querier.urls()[18].last_forced_time.ToJsTime());
EXPECT_EQ("http://newforced/12", querier.urls()[19].url.spec());
EXPECT_EQ(22000, querier.urls()[19].last_forced_time.ToJsTime());
// Check first and last non-forced URLs.
EXPECT_EQ("http://newnonforced/0", querier.urls()[20].url.spec());
EXPECT_TRUE(querier.urls()[20].last_forced_time.is_null());
EXPECT_EQ("http://newnonforced/19", querier.urls()[39].url.spec());
EXPECT_TRUE(querier.urls()[39].last_forced_time.is_null());
}
TEST_F(TopSitesImplTest, SetForcedTopSitesWithCollisions) {
// Setup an old URL list in order to generate some collisions.
MostVisitedURLList old_url_list;
AppendForcedMostVisitedURL(&old_url_list, GURL("http://url/0"), 1000);
// The following three will be evicted.
AppendForcedMostVisitedURL(&old_url_list, GURL("http://collision/0"), 4000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://collision/1"), 6000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://collision/2"), 7000);
// The following is evicted since all non-forced URLs are, therefore it
// doesn't cause a collision.
AppendMostVisitedURL(&old_url_list, GURL("http://noncollision/0"));
SetTopSites(old_url_list);
// Setup a new URL list that will cause collisions.
MostVisitedURLList new_url_list;
AppendForcedMostVisitedURL(&new_url_list, GURL("http://collision/1"), 2000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://url/2"), 3000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://collision/0"), 5000);
AppendForcedMostVisitedURL(&new_url_list, GURL("http://noncollision/0"),
9000);
AppendMostVisitedURL(&new_url_list, GURL("http://collision/2"));
AppendMostVisitedURL(&new_url_list, GURL("http://url/3"));
SetTopSites(new_url_list);
// Query all URLs.
TopSitesQuerier querier;
querier.QueryAllTopSites(top_sites(), false, true);
// Check URLs. When collision occurs, the incoming one is always preferred.
ASSERT_EQ(7u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ("http://url/0", querier.urls()[0].url.spec());
EXPECT_EQ(1000u, querier.urls()[0].last_forced_time.ToJsTime());
EXPECT_EQ("http://collision/1", querier.urls()[1].url.spec());
EXPECT_EQ(2000u, querier.urls()[1].last_forced_time.ToJsTime());
EXPECT_EQ("http://url/2", querier.urls()[2].url.spec());
EXPECT_EQ(3000u, querier.urls()[2].last_forced_time.ToJsTime());
EXPECT_EQ("http://collision/0", querier.urls()[3].url.spec());
EXPECT_EQ(5000u, querier.urls()[3].last_forced_time.ToJsTime());
EXPECT_EQ("http://noncollision/0", querier.urls()[4].url.spec());
EXPECT_EQ(9000u, querier.urls()[4].last_forced_time.ToJsTime());
EXPECT_EQ("http://collision/2", querier.urls()[5].url.spec());
EXPECT_TRUE(querier.urls()[5].last_forced_time.is_null());
EXPECT_EQ("http://url/3", querier.urls()[6].url.spec());
EXPECT_TRUE(querier.urls()[6].last_forced_time.is_null());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 7));
}
TEST_F(TopSitesImplTest, SetTopSitesIdentical) {
// Set the initial list of URLs.
MostVisitedURLList url_list;
AppendForcedMostVisitedURL(&url_list, GURL("http://url/0"), 1000);
AppendMostVisitedURL(&url_list, GURL("http://url/1"));
AppendMostVisitedURL(&url_list, GURL("http://url/2"));
SetTopSites(url_list);
// Set the new list of URLs to be exactly the same.
SetTopSites(MostVisitedURLList(url_list));
// Query all URLs.
TopSitesQuerier querier;
querier.QueryAllTopSites(top_sites(), false, true);
// Check URLs. When collision occurs, the incoming one is always preferred.
ASSERT_EQ(3u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ("http://url/0", querier.urls()[0].url.spec());
EXPECT_EQ(1000u, querier.urls()[0].last_forced_time.ToJsTime());
EXPECT_EQ("http://url/1", querier.urls()[1].url.spec());
EXPECT_EQ("http://url/2", querier.urls()[2].url.spec());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 3));
}
TEST_F(TopSitesImplTest, SetTopSitesWithAlreadyExistingForcedURLs) {
// Set the initial list of URLs.
MostVisitedURLList old_url_list;
AppendForcedMostVisitedURL(&old_url_list, GURL("http://url/0/redir"), 1000);
AppendForcedMostVisitedURL(&old_url_list, GURL("http://url/1"), 2000);
SetTopSites(old_url_list);
// Setup a new URL list that will cause collisions.
MostVisitedURLList new_url_list;
AppendMostVisitedURLWithRedirect(&new_url_list, GURL("http://url/0/redir"),
GURL("http://url/0"));
AppendMostVisitedURL(&new_url_list, GURL("http://url/1"));
SetTopSites(new_url_list);
// Query all URLs.
TopSitesQuerier querier;
querier.QueryAllTopSites(top_sites(), false, true);
// Check URLs. When collision occurs, the non-forced one is always preferred.
ASSERT_EQ(2u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ("http://url/0", querier.urls()[0].url.spec());
EXPECT_EQ("http://url/0/redir", querier.urls()[0].redirects[0].spec());
EXPECT_TRUE(querier.urls()[0].last_forced_time.is_null());
EXPECT_EQ("http://url/1", querier.urls()[1].url.spec());
EXPECT_TRUE(querier.urls()[1].last_forced_time.is_null());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
}
TEST_F(TopSitesImplTest, AddForcedURL) {
// Set the initial list of URLs.
MostVisitedURLList url_list;
AppendForcedMostVisitedURL(&url_list, GURL("http://forced/0"), 2000);
AppendForcedMostVisitedURL(&url_list, GURL("http://forced/1"), 4000);
AppendMostVisitedURL(&url_list, GURL("http://nonforced/0"));
AppendMostVisitedURL(&url_list, GURL("http://nonforced/1"));
AppendMostVisitedURL(&url_list, GURL("http://nonforced/2"));
SetTopSites(url_list);
// Add forced sites here and there to exercise a couple of cases.
EXPECT_TRUE(AddForcedURL(GURL("http://forced/2"),
base::Time::FromJsTime(5000)));
EXPECT_TRUE(AddForcedURL(GURL("http://forced/3"),
base::Time::FromJsTime(1000)));
EXPECT_TRUE(AddForcedURL(GURL("http://forced/4"),
base::Time::FromJsTime(3000)));
// Check URLs.
TopSitesQuerier querier;
querier.QueryAllTopSites(top_sites(), false, true);
ASSERT_EQ(8u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ("http://forced/3", querier.urls()[0].url.spec());
EXPECT_EQ(1000u, querier.urls()[0].last_forced_time.ToJsTime());
EXPECT_EQ("http://forced/0", querier.urls()[1].url.spec());
EXPECT_EQ(2000u, querier.urls()[1].last_forced_time.ToJsTime());
EXPECT_EQ("http://forced/4", querier.urls()[2].url.spec());
EXPECT_EQ(3000u, querier.urls()[2].last_forced_time.ToJsTime());
EXPECT_EQ("http://forced/1", querier.urls()[3].url.spec());
EXPECT_EQ(4000u, querier.urls()[3].last_forced_time.ToJsTime());
EXPECT_EQ("http://forced/2", querier.urls()[4].url.spec());
EXPECT_EQ(5000u, querier.urls()[4].last_forced_time.ToJsTime());
EXPECT_EQ("http://nonforced/0", querier.urls()[5].url.spec());
EXPECT_TRUE(querier.urls()[5].last_forced_time.is_null());
EXPECT_EQ("http://nonforced/1", querier.urls()[6].url.spec());
EXPECT_TRUE(querier.urls()[6].last_forced_time.is_null());
EXPECT_EQ("http://nonforced/2", querier.urls()[7].url.spec());
EXPECT_TRUE(querier.urls()[7].last_forced_time.is_null());
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 8));
// Add some collisions with forced and non-forced. Non-forced URLs are never
// expected to move.
EXPECT_TRUE(AddForcedURL(GURL("http://forced/3"),
base::Time::FromJsTime(4000)));
EXPECT_TRUE(AddForcedURL(GURL("http://forced/1"),
base::Time::FromJsTime(1000)));
EXPECT_FALSE(AddForcedURL(GURL("http://nonforced/0"),
base::Time::FromJsTime(6000)));
// Check relevant URLs.
querier.QueryAllTopSites(top_sites(), false, true);
ASSERT_EQ(8u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ("http://forced/1", querier.urls()[0].url.spec());
EXPECT_EQ(1000u, querier.urls()[0].last_forced_time.ToJsTime());
EXPECT_EQ("http://forced/3", querier.urls()[3].url.spec());
EXPECT_EQ(4000u, querier.urls()[3].last_forced_time.ToJsTime());
EXPECT_EQ("http://nonforced/0", querier.urls()[5].url.spec());
EXPECT_TRUE(querier.urls()[5].last_forced_time.is_null());
// Add a timestamp collision and make sure things don't break.
EXPECT_TRUE(AddForcedURL(GURL("http://forced/5"),
base::Time::FromJsTime(4000)));
querier.QueryAllTopSites(top_sites(), false, true);
ASSERT_EQ(9u + GetPrepopulatedPages().size(), querier.urls().size());
EXPECT_EQ(4000u, querier.urls()[3].last_forced_time.ToJsTime());
EXPECT_EQ(4000u, querier.urls()[4].last_forced_time.ToJsTime());
// We don't care which order they get sorted in.
if (querier.urls()[3].url.spec() == "http://forced/3") {
EXPECT_EQ("http://forced/3", querier.urls()[3].url.spec());
EXPECT_EQ("http://forced/5", querier.urls()[4].url.spec());
} else {
EXPECT_EQ("http://forced/5", querier.urls()[3].url.spec());
EXPECT_EQ("http://forced/3", querier.urls()[4].url.spec());
}
// Make sure the thumbnail is not lost when the timestamp is updated.
gfx::Image red_thumbnail(CreateBitmap(SK_ColorRED));
ASSERT_TRUE(top_sites()->SetPageThumbnail(
GURL("http://forced/5"), red_thumbnail, ThumbnailScore()));
// Get the original thumbnail for later comparison. Some compression can
// happen in |top_sites| and we don't want to depend on that.
SkBitmap orig_thumbnail = GetThumbnail(GURL("http://forced/5"));
EXPECT_TRUE(AddForcedURL(GURL("http://forced/5"),
base::Time::FromJsTime(6000)));
// Ensure the thumbnail is still there even if the timestamp changed.
querier.QueryAllTopSites(top_sites(), false, true);
EXPECT_EQ("http://forced/5", querier.urls()[5].url.spec());
EXPECT_EQ(6000u, querier.urls()[5].last_forced_time.ToJsTime());
SkBitmap thumbnail = GetThumbnail(GURL("http://forced/5"));
ASSERT_EQ(orig_thumbnail.getSize(), thumbnail.getSize());
orig_thumbnail.lockPixels();
thumbnail.lockPixels();
EXPECT_EQ(0, memcmp(orig_thumbnail.getPixels(), thumbnail.getPixels(),
orig_thumbnail.getSize()));
thumbnail.unlockPixels();
orig_thumbnail.unlockPixels();
}
} // namespace history