// Copyright (c) 2011 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 <algorithm> #include <vector> #include "base/basictypes.h" #include "base/command_line.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/memory/ref_counted_memory.h" #include "base/memory/scoped_temp_dir.h" #include "base/path_service.h" #include "chrome/browser/history/history_database.h" #include "chrome/browser/history/history_unittest_base.h" #include "chrome/browser/history/thumbnail_database.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/thumbnail_score.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" #include "ui/gfx/codec/jpeg_codec.h" using base::Time; using base::TimeDelta; namespace history { namespace { // data we'll put into the thumbnail database static const unsigned char blob1[] = "12346102356120394751634516591348710478123649165419234519234512349134"; static const unsigned char blob2[] = "goiwuegrqrcomizqyzkjalitbahxfjytrqvpqeroicxmnlkhlzunacxaneviawrtxcywhgef"; static const unsigned char blob3[] = "3716871354098370776510470746794707624107647054607467847164027"; const double kBoringness = 0.25; const double kWorseBoringness = 0.50; const double kBetterBoringness = 0.10; const double kTotallyBoring = 1.0; const int64 kPage1 = 1234; } // namespace class ThumbnailDatabaseTest : public testing::Test { public: ThumbnailDatabaseTest() { } ~ThumbnailDatabaseTest() { } protected: virtual void SetUp() { // Get a temporary directory for the test DB files. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); file_name_ = temp_dir_.path().AppendASCII("TestThumbnails.db"); new_file_name_ = temp_dir_.path().AppendASCII("TestFavicons.db"); history_db_name_ = temp_dir_.path().AppendASCII("TestHistory.db"); google_bitmap_.reset( gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); } scoped_ptr<SkBitmap> google_bitmap_; ScopedTempDir temp_dir_; FilePath file_name_; FilePath new_file_name_; FilePath history_db_name_; }; class IconMappingMigrationTest : public HistoryUnitTestBase { public: IconMappingMigrationTest() { } ~IconMappingMigrationTest() { } protected: virtual void SetUp() { profile_.reset(new TestingProfile); FilePath data_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); data_path = data_path.AppendASCII("History"); history_db_name_ = profile_->GetPath().Append(chrome::kHistoryFilename); // Set up history and thumbnails as they would be before migration. ASSERT_NO_FATAL_FAILURE( ExecuteSQLScript(data_path.AppendASCII("history.20.sql"), history_db_name_)); thumbnail_db_name_ = profile_->GetPath().Append(chrome::kThumbnailsFilename); ASSERT_NO_FATAL_FAILURE( ExecuteSQLScript(data_path.AppendASCII("thumbnails.3.sql"), thumbnail_db_name_)); } protected: FilePath history_db_name_; FilePath thumbnail_db_name_; private: scoped_ptr<TestingProfile> profile_; }; TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, FAVICON); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_)); base::Time time_out; std::vector<unsigned char> favicon_out; GURL url_out; EXPECT_TRUE(db.GetFavicon(id, &time_out, &favicon_out, &url_out)); EXPECT_EQ(url, url_out); EXPECT_EQ(time.ToTimeT(), time_out.ToTimeT()); ASSERT_EQ(data.size(), favicon_out.size()); EXPECT_TRUE(std::equal(data.begin(), data.end(), favicon_out.begin())); } TEST_F(ThumbnailDatabaseTest, AddIconMapping) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, TOUCH_ICON); EXPECT_NE(0, id); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); EXPECT_NE(0, db.AddIconMapping(url, id)); std::vector<IconMapping> icon_mapping; EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); EXPECT_EQ(1u, icon_mapping.size()); EXPECT_EQ(url, icon_mapping.front().page_url); EXPECT_EQ(id, icon_mapping.front().icon_id); } TEST_F(ThumbnailDatabaseTest, UpdateIconMapping) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, TOUCH_ICON); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); EXPECT_TRUE(0 < db.AddIconMapping(url, id)); std::vector<IconMapping> icon_mapping; EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); ASSERT_EQ(1u, icon_mapping.size()); EXPECT_EQ(url, icon_mapping.front().page_url); EXPECT_EQ(id, icon_mapping.front().icon_id); GURL url1("http://www.google.com/"); FaviconID new_id = db.AddFavicon(url1, TOUCH_ICON); EXPECT_TRUE(db.UpdateIconMapping(icon_mapping.front().mapping_id, new_id)); icon_mapping.clear(); EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); ASSERT_EQ(1u, icon_mapping.size()); EXPECT_EQ(url, icon_mapping.front().page_url); EXPECT_EQ(new_id, icon_mapping.front().icon_id); EXPECT_NE(id, icon_mapping.front().icon_id); } TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, TOUCH_ICON); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); EXPECT_TRUE(0 < db.AddIconMapping(url, id)); FaviconID id2 = db.AddFavicon(url, FAVICON); db.SetFavicon(id2, favicon, time); EXPECT_TRUE(0 < db.AddIconMapping(url, id2)); ASSERT_NE(id, id2); std::vector<IconMapping> icon_mapping; EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); ASSERT_EQ(2u, icon_mapping.size()); EXPECT_EQ(icon_mapping.front().icon_type, TOUCH_ICON); EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAVICON, NULL)); db.DeleteIconMappings(url); EXPECT_FALSE(db.GetIconMappingsForPageURL(url, NULL)); EXPECT_FALSE(db.GetIconMappingForPageURL(url, FAVICON, NULL)); } TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURL) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id1 = db.AddFavicon(url, TOUCH_ICON); base::Time time = base::Time::Now(); db.SetFavicon(id1, favicon, time); EXPECT_TRUE(0 < db.AddIconMapping(url, id1)); FaviconID id2 = db.AddFavicon(url, FAVICON); EXPECT_NE(id1, id2); db.SetFavicon(id2, favicon, time); EXPECT_TRUE(0 < db.AddIconMapping(url, id2)); std::vector<IconMapping> icon_mapping; EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); ASSERT_EQ(2u, icon_mapping.size()); EXPECT_NE(icon_mapping[0].icon_id, icon_mapping[1].icon_id); EXPECT_TRUE(icon_mapping[0].icon_id == id1 && icon_mapping[1].icon_id == id2); } TEST_F(ThumbnailDatabaseTest, UpgradeToVersion4) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); const char* name = "favicons"; std::string sql; sql.append("DROP TABLE IF EXISTS "); sql.append(name); EXPECT_TRUE(db.db_.Execute(sql.c_str())); sql.resize(0); sql.append("CREATE TABLE "); sql.append(name); sql.append("(" "id INTEGER PRIMARY KEY," "url LONGVARCHAR NOT NULL," "last_updated INTEGER DEFAULT 0," "image_data BLOB)"); EXPECT_TRUE(db.db_.Execute(sql.c_str())); EXPECT_TRUE(db.UpgradeToVersion4()); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, TOUCH_ICON); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); EXPECT_TRUE(0 < db.AddIconMapping(url, id)); IconMapping icon_mapping; EXPECT_TRUE(db.GetIconMappingForPageURL(url, TOUCH_ICON, &icon_mapping)); EXPECT_EQ(url, icon_mapping.page_url); EXPECT_EQ(id, icon_mapping.icon_id); } TEST_F(ThumbnailDatabaseTest, TemporayIconMapping) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); EXPECT_TRUE(db.InitTemporaryIconMappingTable()); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, FAVICON); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); db.AddToTemporaryIconMappingTable(url, id); db.CommitTemporaryIconMappingTable(); IconMapping icon_mapping; EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAVICON, &icon_mapping)); EXPECT_EQ(id, icon_mapping.icon_id); EXPECT_EQ(url, icon_mapping.page_url); } TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURLForReturnOrder) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); // Add a favicon std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); GURL url("http://google.com"); FaviconID id = db.AddFavicon(url, FAVICON); base::Time time = base::Time::Now(); db.SetFavicon(id, favicon, time); EXPECT_NE(0, db.AddIconMapping(url, id)); std::vector<IconMapping> icon_mapping; EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); EXPECT_EQ(url, icon_mapping.front().page_url); EXPECT_EQ(id, icon_mapping.front().icon_id); EXPECT_EQ(FAVICON, icon_mapping.front().icon_type); // Add a touch icon std::vector<unsigned char> data2(blob2, blob2 + sizeof(blob2)); scoped_refptr<RefCountedBytes> favicon2(new RefCountedBytes(data)); FaviconID id2 = db.AddFavicon(url, TOUCH_ICON); db.SetFavicon(id2, favicon2, time); EXPECT_NE(0, db.AddIconMapping(url, id2)); icon_mapping.clear(); EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); EXPECT_EQ(url, icon_mapping.front().page_url); EXPECT_EQ(id2, icon_mapping.front().icon_id); EXPECT_EQ(TOUCH_ICON, icon_mapping.front().icon_type); // Add a touch precomposed icon scoped_refptr<RefCountedBytes> favicon3(new RefCountedBytes(data2)); FaviconID id3 = db.AddFavicon(url, TOUCH_PRECOMPOSED_ICON); db.SetFavicon(id3, favicon3, time); EXPECT_NE(0, db.AddIconMapping(url, id3)); icon_mapping.clear(); EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); EXPECT_EQ(url, icon_mapping.front().page_url); EXPECT_EQ(id3, icon_mapping.front().icon_id); EXPECT_EQ(TOUCH_PRECOMPOSED_ICON, icon_mapping.front().icon_type); } TEST_F(ThumbnailDatabaseTest, HasMappingFor) { ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); db.BeginTransaction(); std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); // Add a favicon which will have icon_mappings FaviconID id1 = db.AddFavicon(GURL("http://google.com"), FAVICON); EXPECT_NE(id1, 0); base::Time time = base::Time::Now(); db.SetFavicon(id1, favicon, time); // Add another type of favicon FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"), TOUCH_ICON); EXPECT_NE(id2, 0); time = base::Time::Now(); db.SetFavicon(id2, favicon, time); // Add 3rd favicon FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"), TOUCH_ICON); EXPECT_NE(id3, 0); time = base::Time::Now(); db.SetFavicon(id3, favicon, time); // Add 2 icon mapping GURL page_url("http://www.google.com"); EXPECT_TRUE(db.AddIconMapping(page_url, id1)); EXPECT_TRUE(db.AddIconMapping(page_url, id2)); EXPECT_TRUE(db.HasMappingFor(id1)); EXPECT_TRUE(db.HasMappingFor(id2)); EXPECT_FALSE(db.HasMappingFor(id3)); // Remove all mappings db.DeleteIconMappings(page_url); EXPECT_FALSE(db.HasMappingFor(id1)); EXPECT_FALSE(db.HasMappingFor(id2)); EXPECT_FALSE(db.HasMappingFor(id3)); } TEST_F(IconMappingMigrationTest, TestIconMappingMigration) { HistoryDatabase history_db; ASSERT_TRUE(history_db.db_.Open(history_db_name_)); history_db.BeginTransaction(); const GURL icon1 = GURL("http://www.google.com/favicon.ico"); const GURL icon2 = GURL("http://www.yahoo.com/favicon.ico"); ThumbnailDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(thumbnail_db_name_, NULL, &history_db)); db.BeginTransaction(); // Migration should be done. // Test one icon_mapping. GURL page_url1 = GURL("http://google.com/"); std::vector<IconMapping> icon_mappings; EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url1, &icon_mappings)); ASSERT_EQ(1u, icon_mappings.size()); EXPECT_EQ(FAVICON, icon_mappings[0].icon_type); EXPECT_EQ(page_url1, icon_mappings[0].page_url); EXPECT_EQ(1, icon_mappings[0].icon_id); base::Time time; std::vector<unsigned char> out_data; GURL out_icon_url; ASSERT_TRUE(db.GetFavicon( icon_mappings[0].icon_id, &time, &out_data, &out_icon_url)); EXPECT_EQ(icon1, out_icon_url); // Test a page which has the same icon. GURL page_url3 = GURL("http://www.google.com/"); icon_mappings.clear(); EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url3, &icon_mappings)); ASSERT_EQ(1u, icon_mappings.size()); EXPECT_EQ(FAVICON, icon_mappings[0].icon_type); EXPECT_EQ(page_url3, icon_mappings[0].page_url); EXPECT_EQ(1, icon_mappings[0].icon_id); // Test a icon_mapping with different IconID. GURL page_url2 = GURL("http://yahoo.com/"); icon_mappings.clear(); EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url2, &icon_mappings)); ASSERT_EQ(1u, icon_mappings.size()); EXPECT_EQ(FAVICON, icon_mappings[0].icon_type); EXPECT_EQ(page_url2, icon_mappings[0].page_url); EXPECT_EQ(2, icon_mappings[0].icon_id); ASSERT_TRUE(db.GetFavicon( icon_mappings[0].icon_id, &time, &out_data, &out_icon_url)); EXPECT_EQ(icon2, out_icon_url); // Test a page without icon GURL page_url4 = GURL("http://www.google.com/blank.html"); EXPECT_FALSE(db.GetIconMappingsForPageURL(page_url4, NULL)); } } // namespace history