diff options
author | nshkrob@chromium.org <nshkrob@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-01 17:23:56 +0000 |
---|---|---|
committer | nshkrob@chromium.org <nshkrob@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-01 17:23:56 +0000 |
commit | 6948947fc9e768ee71444d079ee7ab45b8cb5986 (patch) | |
tree | d725300f85fd312470cbc83981d20b2c6bc760b1 /chrome/browser/history | |
parent | 08e9e134bca95868aa4679b67b4c7a4e1695fced (diff) | |
download | chromium_src-6948947fc9e768ee71444d079ee7ab45b8cb5986.zip chromium_src-6948947fc9e768ee71444d079ee7ab45b8cb5986.tar.gz chromium_src-6948947fc9e768ee71444d079ee7ab45b8cb5986.tar.bz2 |
Adding an SQLite database for TopSites.
BUG=None
TEST=TopSitesTest
Review URL: http://codereview.chromium.org/2249004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48639 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/history')
-rw-r--r-- | chrome/browser/history/top_sites.cc | 5 | ||||
-rw-r--r-- | chrome/browser/history/top_sites.h | 3 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_database.cc | 235 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_database.h | 59 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_unittest.cc | 202 |
5 files changed, 495 insertions, 9 deletions
diff --git a/chrome/browser/history/top_sites.cc b/chrome/browser/history/top_sites.cc index ab610a0..d8ea651 100644 --- a/chrome/browser/history/top_sites.cc +++ b/chrome/browser/history/top_sites.cc @@ -82,14 +82,15 @@ bool TopSites::SetPageThumbnail(const GURL& url, Images& image = top_images_[most_visited.url]; // When comparing the thumbnail scores, we need to take into account the - // redirect hops, which are not generated when the thumbnail is becuase the + // redirect hops, which are not generated when the thumbnail is because the // redirects weren't known. We fill that in here since we know the redirects. ThumbnailScore new_score_with_redirects(score); new_score_with_redirects.redirect_hops_from_dest = GetRedirectDistanceForURL(most_visited, url); if (!ShouldReplaceThumbnailWith(image.thumbnail_score, - new_score_with_redirects)) + new_score_with_redirects) && + image.thumbnail.get()) return false; // The one we already have is better. // Take ownership of the thumbnail data. diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h index 0b9b1e4..4f6f854 100644 --- a/chrome/browser/history/top_sites.h +++ b/chrome/browser/history/top_sites.h @@ -86,7 +86,8 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { friend class base::RefCountedThreadSafe<TopSites>; friend class TopSitesTest; friend class TopSitesTest_GetMostVisited_Test; - friend class TopSitesTest_ReadDatabase_Test; + friend class TopSitesTest_RealDatabase_Test; + friend class TopSitesTest_MockDatabase_Test; ~TopSites(); diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc new file mode 100644 index 0000000..5b13d61 --- /dev/null +++ b/chrome/browser/history/top_sites_database.cc @@ -0,0 +1,235 @@ +// Copyright (c) 2009 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 "app/sql/transaction.h" +#include "base/string_util.h" +#include "chrome/browser/diagnostics/sqlite_diagnostics.h" +#include "chrome/browser/history/top_sites.h" +#include "chrome/browser/history/top_sites_database.h" + +namespace history { + +TopSitesDatabaseImpl::TopSitesDatabaseImpl() { +} + +bool TopSitesDatabaseImpl::Init(const FilePath& db_name) { + // Settings copied from ThumbnailDatabase. + db_.set_error_delegate(GetErrorHandlerForThumbnailDb()); + db_.set_page_size(4096); + db_.set_cache_size(64); + + if (!db_.Open(db_name)) { + LOG(WARNING) << db_.GetErrorMessage(); + return sql::INIT_FAILURE; + } + + return InitThumbnailTable(); +} + +bool TopSitesDatabaseImpl::InitThumbnailTable() { + if (!db_.DoesTableExist("thumbnails")) { + if (!db_.Execute("CREATE TABLE thumbnails (" + "url LONGVARCHAR PRIMARY KEY," + "url_rank INTEGER ," + "title LONGVARCHAR," + "thumbnail BLOB," + "redirects LONGVARCHAR)")) { + LOG(WARNING) << db_.GetErrorMessage(); + return false; + } + } + return true; +} + +MostVisitedURLList TopSitesDatabaseImpl::GetTopURLs() { + MostVisitedURLList result; + sql::Statement select_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "SELECT url, url_rank, title, redirects " + "FROM thumbnails ORDER BY url_rank")); + + if (!select_statement) { + LOG(WARNING) << db_.GetErrorMessage(); + return result; + } + + int row_count = 0; + int max_rank = -1; // -1 is for the case of empty DB. + while (select_statement.Step()) { + // Results are sorted by url_rank. + MostVisitedURL url; + GURL gurl(select_statement.ColumnString(0)); + url.url = gurl; + url.title = select_statement.ColumnString16(2); + std::string redirects = select_statement.ColumnString(3); + SetRedirects(redirects, &url); + result.push_back(url); + } + DCHECK(select_statement.Succeeded()); + DCHECK_EQ(max_rank + 1, row_count); + + return result; +} + +// static +std::string TopSitesDatabaseImpl::GetRedirects(const MostVisitedURL& url) { + std::vector<std::string> redirects; + for (size_t i = 0; i < url.redirects.size(); i++) + redirects.push_back(url.redirects[i].spec()); + return JoinString(redirects, ' '); +} + +// static +void TopSitesDatabaseImpl::SetRedirects(const std::string& redirects, + MostVisitedURL* url) { + std::vector<std::string> redirects_vector; + SplitStringAlongWhitespace(redirects, &redirects_vector); + for (size_t i = 0; i < redirects_vector.size(); i++) + url->redirects.push_back(GURL(redirects_vector[i])); +} + + +void TopSitesDatabaseImpl::SetPageThumbnail(const MostVisitedURL& url, + int new_rank, + const TopSites::Images& thumbnail) { + sql::Transaction transaction(&db_); + transaction.Begin(); + + int prev_rank = GetURLRank(url); + + sql::Statement statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "INSERT OR REPLACE INTO thumbnails " + "(url, url_rank, title, thumbnail, redirects) " + "VALUES (?, ?, ?, ?, ?)")); // TODO(Nik): add the rest of the schema. + if (!statement) + return; + + statement.BindString(0, url.url.spec()); + statement.BindInt(1, -1); // Temporary value + statement.BindString16(2, url.title); + if (thumbnail.thumbnail.get()) { + statement.BindBlob(3, &thumbnail.thumbnail->data.front(), + static_cast<int>(thumbnail.thumbnail->data.size())); + } + statement.BindString(4, GetRedirects(url)); + + if (!statement.Run()) + NOTREACHED() << db_.GetErrorMessage(); + + // Shift the ranks. + if (prev_rank == -1) { + // Shift up + sql::Statement shift_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "UPDATE thumbnails " + "SET url_rank = url_rank + 1 WHERE url_rank >= ?")); + shift_statement.BindInt(0, new_rank); + if (shift_statement) + shift_statement.Run(); + } else if (prev_rank > new_rank) { + // Shift up + sql::Statement shift_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "UPDATE thumbnails " + "SET url_rank = url_rank + 1 " + "WHERE url_rank >= ? AND url_rank < ?")); + shift_statement.BindInt(0, new_rank); + shift_statement.BindInt(1, prev_rank); + if (shift_statement) + shift_statement.Run(); + } else if (prev_rank < new_rank) { + // Shift down + sql::Statement shift_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "UPDATE thumbnails " + "SET url_rank = url_rank - 1 " + "WHERE url_rank > ? AND url_rank <= ?")); + shift_statement.BindInt(0, prev_rank); + shift_statement.BindInt(1, new_rank); + if (shift_statement) + shift_statement.Run(); + } + + // Set the real rank. + sql::Statement set_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "UPDATE thumbnails " + "SET url_rank = ? " + "WHERE url_rank == -1")); + set_statement.BindInt(0, new_rank); + if (set_statement) + set_statement.Run(); + transaction.Commit(); +} + +bool TopSitesDatabaseImpl::GetPageThumbnail(const MostVisitedURL& url, + TopSites::Images* thumbnail) { + sql::Statement select_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "SELECT thumbnail " + "FROM thumbnails WHERE url=?")); + + if (!select_statement) { + LOG(WARNING) << db_.GetErrorMessage(); + return false; + } + + select_statement.BindString(0, url.url.spec()); + if (!select_statement.Step()) + return false; + + std::vector<unsigned char> data; + select_statement.ColumnBlobAsVector(0, &data); + thumbnail->thumbnail = RefCountedBytes::TakeVector(&data); + return true; +} + +int TopSitesDatabaseImpl::GetURLRank(const MostVisitedURL& url) { + int result = -1; + sql::Statement select_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "SELECT url_rank " + "FROM thumbnails WHERE url=?")); + if (!select_statement) { + LOG(WARNING) << db_.GetErrorMessage(); + return result; + } + + select_statement.BindString(0, url.url.spec()); + if (select_statement.Step()) + result = select_statement.ColumnInt(0); + + return result; +} + +// Remove the record for this URL. Returns true iff removed successfully. +bool TopSitesDatabaseImpl::RemoveURL(const MostVisitedURL& url) { + int old_rank = GetURLRank(url); + sql::Transaction transaction(&db_); + transaction.Begin(); + // Decrement all following ranks. + sql::Statement shift_statement(db_.GetCachedStatement( + SQL_FROM_HERE, + "UPDATE thumbnails " + "SET url_rank = url_rank - 1 " + "WHERE url_rank > ?")); + if (!shift_statement) + return false; + shift_statement.BindInt(0, old_rank); + shift_statement.Run(); + + sql::Statement delete_statement( + db_.GetCachedStatement(SQL_FROM_HERE, + "DELETE FROM thumbnails WHERE url = ?")); + if (!delete_statement) + return false; + delete_statement.BindString(0, url.url.spec()); + delete_statement.Run(); + + return transaction.Commit(); +} + +} // namespace history + diff --git a/chrome/browser/history/top_sites_database.h b/chrome/browser/history/top_sites_database.h index 50da75d..2a664a6 100644 --- a/chrome/browser/history/top_sites_database.h +++ b/chrome/browser/history/top_sites_database.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_ #define CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_ +#include <string> #include <vector> #include "app/sql/connection.h" @@ -17,6 +18,7 @@ class FilePath; class RefCountedMemory; class SkBitmap; +class TopSites; namespace base { class Time; @@ -39,17 +41,68 @@ class TopSitesDatabase { // thumbnail. virtual void SetPageThumbnail(const MostVisitedURL& url, int url_rank, - const TopSites::Images thumbnail) = 0; + const TopSites::Images& thumbnail) = 0; // Get a thumbnail for a given page. Returns true iff we have the thumbnail. virtual bool GetPageThumbnail(const MostVisitedURL& url, - TopSites::Images* thumbnail) const = 0; + TopSites::Images* thumbnail) = 0; // Remove the record for this URL. Returns true iff removed successfully. virtual bool RemoveURL(const MostVisitedURL& url) = 0; }; +class TopSitesDatabaseImpl: public TopSitesDatabase { + public: + TopSitesDatabaseImpl(); + ~TopSitesDatabaseImpl() {} + + // Must be called after creation but before any other methods are called. + // Returns true on success. If false, no other functions should be called. + bool Init(const FilePath& db_name); + + // Thumbnails ---------------------------------------------------------------- + + // Returns a list of all URLs currently in the table. + virtual MostVisitedURLList GetTopURLs(); + + // Set a thumbnail for a URL. |url_rank| is the position of the URL + // in the list of TopURLs, zero-based. + // If the URL is not in the table, add it. If it is, replace its + // thumbnail and rank. Shift the ranks of other URLs if necessary. + virtual void SetPageThumbnail(const MostVisitedURL& url, + int new_rank, + const TopSites::Images& thumbnail); + + // Get a thumbnail for a given page. Returns true iff we have the thumbnail. + virtual bool GetPageThumbnail(const MostVisitedURL& url, + TopSites::Images* thumbnail); + + // Remove the record for this URL. Returns true iff removed successfully. + virtual bool RemoveURL(const MostVisitedURL& url); + + private: + // Creates the thumbnail table, returning true if the table already exists + // or was successfully created. + bool InitThumbnailTable(); + + // Returns the URL's current rank or -1 if it is not present. + int GetURLRank(const MostVisitedURL& url); + + // Gets the URL at |rank|. Returns true if the URL is there. + bool GetURLAtRank(int rank, MostVisitedURL* url); + + // Sets the rank of a URL. The URL must be present in the DB. + void SetURLRank(const MostVisitedURL& url, int rank); + + // Encodes redirects into a string. + static std::string GetRedirects(const MostVisitedURL& url); + + // Decodes redirects from a string and sets them for the url. + static void SetRedirects(const std::string& redirects, MostVisitedURL* url); + + sql::Connection db_; +}; + } // namespace history #endif // CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_ - diff --git a/chrome/browser/history/top_sites_unittest.cc b/chrome/browser/history/top_sites_unittest.cc index fbc1aeb..7463075 100644 --- a/chrome/browser/history/top_sites_unittest.cc +++ b/chrome/browser/history/top_sites_unittest.cc @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/scoped_temp_dir.h" #include "base/string_util.h" #include "chrome/browser/history/top_sites.h" +#include "chrome/common/chrome_paths.h" #include "chrome/browser/history/top_sites_database.h" #include "chrome/test/testing_profile.h" +#include "chrome/tools/profiles/thumbnail-inl.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -13,6 +16,9 @@ namespace history { +static const unsigned char kBlob[] = + "12346102356120394751634516591348710478123649165419234519234512349134"; + class TopSitesTest : public testing::Test { public: TopSitesTest() { @@ -21,15 +27,30 @@ class TopSitesTest : public testing::Test { } TopSites& top_sites() { return *top_sites_; } + FilePath& file_name() { return file_name_; } + RefCountedBytes* google_thumbnail() { return google_thumbnail_; } + RefCountedBytes* random_thumbnail() { return random_thumbnail_; } virtual void SetUp() { profile_.reset(new TestingProfile); top_sites_ = new TopSites(profile_.get()); + + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + file_name_ = temp_dir_.path().AppendASCII("TopSites.db"); + EXPECT_TRUE(file_util::Delete(file_name_, false)); + + std::vector<unsigned char> random_data(kBlob, kBlob + sizeof(kBlob)); + std::vector<unsigned char> google_data(kGoogleThumbnail, + kGoogleThumbnail + + sizeof(kGoogleThumbnail)); + random_thumbnail_ = new RefCountedBytes(random_data); + google_thumbnail_ = new RefCountedBytes(google_data); } virtual void TearDown() { profile_.reset(); top_sites_ = NULL; + EXPECT_TRUE(file_util::Delete(file_name_, false)); } // Wrappers that allow private TopSites functions to be called from the @@ -56,6 +77,10 @@ class TopSitesTest : public testing::Test { private: scoped_refptr<TopSites> top_sites_; scoped_ptr<TestingProfile> profile_; + ScopedTempDir temp_dir_; + FilePath file_name_; // Database filename. + scoped_refptr<RefCountedBytes> google_thumbnail_; + scoped_refptr<RefCountedBytes> random_thumbnail_; DISALLOW_COPY_AND_ASSIGN(TopSitesTest); }; @@ -99,7 +124,7 @@ class MockTopSitesDatabaseImpl : public TopSitesDatabase { } virtual void SetPageThumbnail(const MostVisitedURL& url, int url_rank, - const TopSites::Images thumbnail) { + const TopSites::Images& thumbnail) { // Update the list of URLs // Check if this url is in the list, and at which position. MostVisitedURLList::iterator pos = std::find(top_sites_list_.begin(), @@ -123,7 +148,7 @@ class MockTopSitesDatabaseImpl : public TopSitesDatabase { // Get a thumbnail for a given page. Returns true iff we have the thumbnail. virtual bool GetPageThumbnail(const MostVisitedURL& url, - TopSites::Images* thumbnail) const { + TopSites::Images* thumbnail) { std::map<GURL, TopSites::Images>::const_iterator found = thumbnails_map_.find(url.url); if (found == thumbnails_map_.end()) @@ -163,6 +188,16 @@ static void AppendMostVisitedURL(std::vector<MostVisitedURL>* list, list->push_back(mv); } +// Returns true if t1 and t2 contain the same data. +static bool ThumbnailsAreEqual(RefCountedBytes* t1, + RefCountedBytes* t2) { + if (!t1 || !t2) + return false; + return std::equal(t1->data.begin(), + t1->data.end(), + t2->data.begin()); +} + // Same as AppendMostVisitedURL except that it adds a redirect from the first // URL to the second. static void AppendMostVisitedURLWithRedirect( @@ -305,7 +340,7 @@ TEST_F(TopSitesTest, GetMostVisited) { EXPECT_EQ(google, results[1].url); } -TEST_F(TopSitesTest, ReadDatabase) { +TEST_F(TopSitesTest, MockDatabase) { MockTopSitesDatabaseImpl* db = new MockTopSitesDatabaseImpl; // |db| is destroyed when the top_sites is destroyed in TearDown. top_sites().db_.reset(db); @@ -362,4 +397,165 @@ TEST_F(TopSitesTest, ReadDatabase) { EXPECT_EQ(news_title, result[1].title); } +// Test TopSitesDatabaseImpl. +TEST_F(TopSitesTest, TopSitesDB) { + TopSitesDatabaseImpl db; + + ASSERT_TRUE(db.Init(file_name())); + + MostVisitedURL url; + GURL asdf_url("http://asdf.com"); + string16 asdf_title(ASCIIToUTF16("ASDF")); + GURL google_url("http://google.com"); + string16 google_title(ASCIIToUTF16("Google")); + GURL news_url("http://news.google.com"); + string16 news_title(ASCIIToUTF16("Google News")); + + url.url = asdf_url; + url.title = asdf_title; + url.redirects.push_back(url.url); + TopSites::Images thumbnail; + thumbnail.thumbnail = random_thumbnail(); + // Add asdf at rank 0. + db.SetPageThumbnail(url, 0, thumbnail); + + TopSites::Images result; + EXPECT_TRUE(db.GetPageThumbnail(url, &result)); + EXPECT_EQ(thumbnail.thumbnail->data.size(), result.thumbnail->data.size()); + EXPECT_TRUE(ThumbnailsAreEqual(thumbnail.thumbnail, result.thumbnail)); + + MostVisitedURLList urls = db.GetTopURLs(); + ASSERT_EQ(1u, urls.size()); + EXPECT_EQ(asdf_url, urls[0].url); + EXPECT_EQ(asdf_title, urls[0].title); + + url.url = google_url; + url.title = google_title; + + // Add google at rank 1 - no rank shifting. + db.SetPageThumbnail(url, 1, thumbnail); + urls = db.GetTopURLs(); + ASSERT_EQ(2u, urls.size()); + EXPECT_EQ(asdf_url, urls[0].url); + EXPECT_EQ(asdf_title, urls[0].title); + EXPECT_EQ(google_url, urls[1].url); + EXPECT_EQ(google_title, urls[1].title); + + url.url = news_url; + url.title = news_title; + + // Add news at rank 1 - shift google to rank 2. + db.SetPageThumbnail(url, 1, thumbnail); + urls = db.GetTopURLs(); + ASSERT_EQ(3u, urls.size()); + EXPECT_EQ(asdf_url, urls[0].url); + EXPECT_EQ(news_url, urls[1].url); + EXPECT_EQ(google_url, urls[2].url); + + db.GetTopURLs(); + // Move news at rank 0 - shift the rest up. + db.SetPageThumbnail(url, 0, thumbnail); + urls = db.GetTopURLs(); + ASSERT_EQ(3u, urls.size()); + EXPECT_EQ(news_url, urls[0].url); + EXPECT_EQ(asdf_url, urls[1].url); + EXPECT_EQ(google_url, urls[2].url); + + // Move news at rank 2 - shift the rest down. + db.SetPageThumbnail(url, 2, thumbnail); + urls = db.GetTopURLs(); + ASSERT_EQ(3u, urls.size()); + EXPECT_EQ(asdf_url, urls[0].url); + EXPECT_EQ(google_url, urls[1].url); + EXPECT_EQ(news_url, urls[2].url); + + // Delete asdf. + url.url = asdf_url; + db.RemoveURL(url); + + urls = db.GetTopURLs(); + ASSERT_EQ(2u, urls.size()); + EXPECT_EQ(google_url, urls[0].url); + EXPECT_EQ(news_url, urls[1].url); +} + +// Test TopSites with a real database. +TEST_F(TopSitesTest, RealDatabase) { + TopSitesDatabaseImpl* db = new TopSitesDatabaseImpl; + + ASSERT_TRUE(db->Init(file_name())); + // |db| is destroyed when the top_sites is destroyed in TearDown. + top_sites().db_.reset(db); + MostVisitedURL url; + GURL asdf_url("http://asdf.com"); + string16 asdf_title(ASCIIToUTF16("ASDF")); + GURL google1_url("http://google.com"); + GURL google2_url("http://google.com/redirect"); + GURL google3_url("http://www.google.com"); + string16 google_title(ASCIIToUTF16("Google")); + GURL news_url("http://news.google.com"); + string16 news_title(ASCIIToUTF16("Google News")); + + url.url = asdf_url; + url.title = asdf_title; + url.redirects.push_back(url.url); + TopSites::Images thumbnail; + thumbnail.thumbnail = random_thumbnail(); + db->SetPageThumbnail(url, 0, thumbnail); + + top_sites().ReadDatabase(); + + MostVisitedURLList result = top_sites().GetMostVisitedURLs(); + ASSERT_EQ(1u, result.size()); + EXPECT_EQ(asdf_url, result[0].url); + EXPECT_EQ(asdf_title, result[0].title); + + RefCountedBytes* thumbnail_result; + top_sites().GetPageThumbnail(asdf_url, &thumbnail_result); + EXPECT_TRUE(thumbnail_result != NULL); + EXPECT_TRUE(ThumbnailsAreEqual(random_thumbnail(), thumbnail_result)); + + MostVisitedURL url2; + url2.url = google1_url; + url2.title = google_title; + url2.redirects.push_back(google1_url); + url2.redirects.push_back(google2_url); + url2.redirects.push_back(google3_url); + + // Add new thumbnail at rank 0 and shift the other result to 1. + TopSites::Images g_thumbnail; + g_thumbnail.thumbnail = google_thumbnail(); + db->SetPageThumbnail(url2, 0, g_thumbnail); + + top_sites().ReadDatabase(); + + result = top_sites().GetMostVisitedURLs(); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ(google1_url, result[0].url); + EXPECT_EQ(google_title, result[0].title); + top_sites().GetPageThumbnail(google1_url, &thumbnail_result); + EXPECT_TRUE(ThumbnailsAreEqual(google_thumbnail(), thumbnail_result)); + ASSERT_EQ(3u, result[0].redirects.size()); + EXPECT_EQ(google1_url, result[0].redirects[0]); + EXPECT_EQ(google2_url, result[0].redirects[1]); + EXPECT_EQ(google3_url, result[0].redirects[2]); + + EXPECT_EQ(asdf_url, result[1].url); + EXPECT_EQ(asdf_title, result[1].title); + + MockHistoryServiceImpl hs; + // Add one old, one new URL to the history. + hs.AppendMockPage(google1_url, google_title); + hs.AppendMockPage(news_url, news_title); + top_sites().SetMockHistoryService(&hs); + + // This writes the new data to the DB. + top_sites().StartQueryForMostVisited(); + + result = db->GetTopURLs(); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ(google_title, result[0].title); + EXPECT_EQ(news_title, result[1].title); +} + } // namespace history |