1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <algorithm> 6 #include <vector> 7 8 #include "base/basictypes.h" 9 #include "base/command_line.h" 10 #include "base/file_path.h" 11 #include "base/file_util.h" 12 #include "base/memory/ref_counted_memory.h" 13 #include "base/memory/scoped_temp_dir.h" 14 #include "base/path_service.h" 15 #include "chrome/browser/history/history_database.h" 16 #include "chrome/browser/history/history_unittest_base.h" 17 #include "chrome/browser/history/thumbnail_database.h" 18 #include "chrome/common/chrome_constants.h" 19 #include "chrome/common/chrome_paths.h" 20 #include "chrome/common/thumbnail_score.h" 21 #include "chrome/test/testing_profile.h" 22 #include "chrome/tools/profiles/thumbnail-inl.h" 23 #include "googleurl/src/gurl.h" 24 #include "testing/gtest/include/gtest/gtest.h" 25 #include "third_party/skia/include/core/SkBitmap.h" 26 #include "ui/gfx/codec/jpeg_codec.h" 27 28 using base::Time; 29 using base::TimeDelta; 30 31 namespace history { 32 33 namespace { 34 35 // data we'll put into the thumbnail database 36 static const unsigned char blob1[] = 37 "12346102356120394751634516591348710478123649165419234519234512349134"; 38 static const unsigned char blob2[] = 39 "goiwuegrqrcomizqyzkjalitbahxfjytrqvpqeroicxmnlkhlzunacxaneviawrtxcywhgef"; 40 static const unsigned char blob3[] = 41 "3716871354098370776510470746794707624107647054607467847164027"; 42 const double kBoringness = 0.25; 43 const double kWorseBoringness = 0.50; 44 const double kBetterBoringness = 0.10; 45 const double kTotallyBoring = 1.0; 46 47 const int64 kPage1 = 1234; 48 49 } // namespace 50 51 class ThumbnailDatabaseTest : public testing::Test { 52 public: 53 ThumbnailDatabaseTest() { 54 } 55 ~ThumbnailDatabaseTest() { 56 } 57 58 protected: 59 virtual void SetUp() { 60 // Get a temporary directory for the test DB files. 61 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 62 63 file_name_ = temp_dir_.path().AppendASCII("TestThumbnails.db"); 64 new_file_name_ = temp_dir_.path().AppendASCII("TestFavicons.db"); 65 history_db_name_ = temp_dir_.path().AppendASCII("TestHistory.db"); 66 google_bitmap_.reset( 67 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); 68 } 69 70 scoped_ptr<SkBitmap> google_bitmap_; 71 72 ScopedTempDir temp_dir_; 73 FilePath file_name_; 74 FilePath new_file_name_; 75 FilePath history_db_name_; 76 }; 77 78 class IconMappingMigrationTest : public HistoryUnitTestBase { 79 public: 80 IconMappingMigrationTest() { 81 } 82 ~IconMappingMigrationTest() { 83 } 84 85 protected: 86 virtual void SetUp() { 87 profile_.reset(new TestingProfile); 88 89 FilePath data_path; 90 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 91 data_path = data_path.AppendASCII("History"); 92 93 history_db_name_ = profile_->GetPath().Append(chrome::kHistoryFilename); 94 // Set up history and thumbnails as they would be before migration. 95 ASSERT_NO_FATAL_FAILURE( 96 ExecuteSQLScript(data_path.AppendASCII("history.20.sql"), 97 history_db_name_)); 98 thumbnail_db_name_ = 99 profile_->GetPath().Append(chrome::kThumbnailsFilename); 100 ASSERT_NO_FATAL_FAILURE( 101 ExecuteSQLScript(data_path.AppendASCII("thumbnails.3.sql"), 102 thumbnail_db_name_)); 103 } 104 105 protected: 106 FilePath history_db_name_; 107 FilePath thumbnail_db_name_; 108 109 private: 110 scoped_ptr<TestingProfile> profile_; 111 }; 112 113 TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) { 114 ThumbnailDatabase db; 115 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 116 db.BeginTransaction(); 117 118 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 119 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 120 121 GURL url("http://google.com"); 122 FaviconID id = db.AddFavicon(url, FAVICON); 123 base::Time time = base::Time::Now(); 124 db.SetFavicon(id, favicon, time); 125 EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_)); 126 127 base::Time time_out; 128 std::vector<unsigned char> favicon_out; 129 GURL url_out; 130 EXPECT_TRUE(db.GetFavicon(id, &time_out, &favicon_out, &url_out)); 131 EXPECT_EQ(url, url_out); 132 EXPECT_EQ(time.ToTimeT(), time_out.ToTimeT()); 133 ASSERT_EQ(data.size(), favicon_out.size()); 134 EXPECT_TRUE(std::equal(data.begin(), 135 data.end(), 136 favicon_out.begin())); 137 } 138 139 TEST_F(ThumbnailDatabaseTest, AddIconMapping) { 140 ThumbnailDatabase db; 141 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 142 db.BeginTransaction(); 143 144 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 145 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 146 147 GURL url("http://google.com"); 148 FaviconID id = db.AddFavicon(url, TOUCH_ICON); 149 EXPECT_NE(0, id); 150 base::Time time = base::Time::Now(); 151 db.SetFavicon(id, favicon, time); 152 153 EXPECT_NE(0, db.AddIconMapping(url, id)); 154 std::vector<IconMapping> icon_mapping; 155 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 156 EXPECT_EQ(1u, icon_mapping.size()); 157 EXPECT_EQ(url, icon_mapping.front().page_url); 158 EXPECT_EQ(id, icon_mapping.front().icon_id); 159 } 160 161 TEST_F(ThumbnailDatabaseTest, UpdateIconMapping) { 162 ThumbnailDatabase db; 163 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 164 db.BeginTransaction(); 165 166 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 167 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 168 169 GURL url("http://google.com"); 170 FaviconID id = db.AddFavicon(url, TOUCH_ICON); 171 base::Time time = base::Time::Now(); 172 db.SetFavicon(id, favicon, time); 173 174 EXPECT_TRUE(0 < db.AddIconMapping(url, id)); 175 std::vector<IconMapping> icon_mapping; 176 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 177 ASSERT_EQ(1u, icon_mapping.size()); 178 EXPECT_EQ(url, icon_mapping.front().page_url); 179 EXPECT_EQ(id, icon_mapping.front().icon_id); 180 181 GURL url1("http://www.google.com/"); 182 FaviconID new_id = db.AddFavicon(url1, TOUCH_ICON); 183 EXPECT_TRUE(db.UpdateIconMapping(icon_mapping.front().mapping_id, new_id)); 184 185 icon_mapping.clear(); 186 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 187 ASSERT_EQ(1u, icon_mapping.size()); 188 EXPECT_EQ(url, icon_mapping.front().page_url); 189 EXPECT_EQ(new_id, icon_mapping.front().icon_id); 190 EXPECT_NE(id, icon_mapping.front().icon_id); 191 } 192 193 TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) { 194 ThumbnailDatabase db; 195 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 196 db.BeginTransaction(); 197 198 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 199 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 200 201 GURL url("http://google.com"); 202 FaviconID id = db.AddFavicon(url, TOUCH_ICON); 203 base::Time time = base::Time::Now(); 204 db.SetFavicon(id, favicon, time); 205 EXPECT_TRUE(0 < db.AddIconMapping(url, id)); 206 207 FaviconID id2 = db.AddFavicon(url, FAVICON); 208 db.SetFavicon(id2, favicon, time); 209 EXPECT_TRUE(0 < db.AddIconMapping(url, id2)); 210 ASSERT_NE(id, id2); 211 212 std::vector<IconMapping> icon_mapping; 213 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 214 ASSERT_EQ(2u, icon_mapping.size()); 215 EXPECT_EQ(icon_mapping.front().icon_type, TOUCH_ICON); 216 EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAVICON, NULL)); 217 218 db.DeleteIconMappings(url); 219 220 EXPECT_FALSE(db.GetIconMappingsForPageURL(url, NULL)); 221 EXPECT_FALSE(db.GetIconMappingForPageURL(url, FAVICON, NULL)); 222 } 223 224 TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURL) { 225 ThumbnailDatabase db; 226 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 227 db.BeginTransaction(); 228 229 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 230 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 231 232 GURL url("http://google.com"); 233 234 FaviconID id1 = db.AddFavicon(url, TOUCH_ICON); 235 base::Time time = base::Time::Now(); 236 db.SetFavicon(id1, favicon, time); 237 EXPECT_TRUE(0 < db.AddIconMapping(url, id1)); 238 239 FaviconID id2 = db.AddFavicon(url, FAVICON); 240 EXPECT_NE(id1, id2); 241 db.SetFavicon(id2, favicon, time); 242 EXPECT_TRUE(0 < db.AddIconMapping(url, id2)); 243 244 std::vector<IconMapping> icon_mapping; 245 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 246 ASSERT_EQ(2u, icon_mapping.size()); 247 EXPECT_NE(icon_mapping[0].icon_id, icon_mapping[1].icon_id); 248 EXPECT_TRUE(icon_mapping[0].icon_id == id1 && icon_mapping[1].icon_id == id2); 249 } 250 251 TEST_F(ThumbnailDatabaseTest, UpgradeToVersion4) { 252 ThumbnailDatabase db; 253 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 254 db.BeginTransaction(); 255 256 const char* name = "favicons"; 257 std::string sql; 258 sql.append("DROP TABLE IF EXISTS "); 259 sql.append(name); 260 EXPECT_TRUE(db.db_.Execute(sql.c_str())); 261 262 sql.resize(0); 263 sql.append("CREATE TABLE "); 264 sql.append(name); 265 sql.append("(" 266 "id INTEGER PRIMARY KEY," 267 "url LONGVARCHAR NOT NULL," 268 "last_updated INTEGER DEFAULT 0," 269 "image_data BLOB)"); 270 EXPECT_TRUE(db.db_.Execute(sql.c_str())); 271 272 EXPECT_TRUE(db.UpgradeToVersion4()); 273 274 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 275 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 276 277 GURL url("http://google.com"); 278 FaviconID id = db.AddFavicon(url, TOUCH_ICON); 279 base::Time time = base::Time::Now(); 280 db.SetFavicon(id, favicon, time); 281 282 EXPECT_TRUE(0 < db.AddIconMapping(url, id)); 283 IconMapping icon_mapping; 284 EXPECT_TRUE(db.GetIconMappingForPageURL(url, TOUCH_ICON, &icon_mapping)); 285 EXPECT_EQ(url, icon_mapping.page_url); 286 EXPECT_EQ(id, icon_mapping.icon_id); 287 } 288 289 TEST_F(ThumbnailDatabaseTest, TemporayIconMapping) { 290 ThumbnailDatabase db; 291 292 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 293 294 db.BeginTransaction(); 295 296 EXPECT_TRUE(db.InitTemporaryIconMappingTable()); 297 298 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 299 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 300 301 GURL url("http://google.com"); 302 FaviconID id = db.AddFavicon(url, FAVICON); 303 base::Time time = base::Time::Now(); 304 db.SetFavicon(id, favicon, time); 305 306 db.AddToTemporaryIconMappingTable(url, id); 307 db.CommitTemporaryIconMappingTable(); 308 IconMapping icon_mapping; 309 EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAVICON, &icon_mapping)); 310 EXPECT_EQ(id, icon_mapping.icon_id); 311 EXPECT_EQ(url, icon_mapping.page_url); 312 } 313 314 TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURLForReturnOrder) { 315 ThumbnailDatabase db; 316 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 317 db.BeginTransaction(); 318 319 // Add a favicon 320 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 321 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 322 323 GURL url("http://google.com"); 324 FaviconID id = db.AddFavicon(url, FAVICON); 325 base::Time time = base::Time::Now(); 326 db.SetFavicon(id, favicon, time); 327 328 EXPECT_NE(0, db.AddIconMapping(url, id)); 329 std::vector<IconMapping> icon_mapping; 330 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 331 332 EXPECT_EQ(url, icon_mapping.front().page_url); 333 EXPECT_EQ(id, icon_mapping.front().icon_id); 334 EXPECT_EQ(FAVICON, icon_mapping.front().icon_type); 335 336 // Add a touch icon 337 std::vector<unsigned char> data2(blob2, blob2 + sizeof(blob2)); 338 scoped_refptr<RefCountedBytes> favicon2(new RefCountedBytes(data)); 339 340 FaviconID id2 = db.AddFavicon(url, TOUCH_ICON); 341 db.SetFavicon(id2, favicon2, time); 342 EXPECT_NE(0, db.AddIconMapping(url, id2)); 343 344 icon_mapping.clear(); 345 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 346 347 EXPECT_EQ(url, icon_mapping.front().page_url); 348 EXPECT_EQ(id2, icon_mapping.front().icon_id); 349 EXPECT_EQ(TOUCH_ICON, icon_mapping.front().icon_type); 350 351 // Add a touch precomposed icon 352 scoped_refptr<RefCountedBytes> favicon3(new RefCountedBytes(data2)); 353 354 FaviconID id3 = db.AddFavicon(url, TOUCH_PRECOMPOSED_ICON); 355 db.SetFavicon(id3, favicon3, time); 356 EXPECT_NE(0, db.AddIconMapping(url, id3)); 357 358 icon_mapping.clear(); 359 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping)); 360 361 EXPECT_EQ(url, icon_mapping.front().page_url); 362 EXPECT_EQ(id3, icon_mapping.front().icon_id); 363 EXPECT_EQ(TOUCH_PRECOMPOSED_ICON, icon_mapping.front().icon_type); 364 } 365 366 TEST_F(ThumbnailDatabaseTest, HasMappingFor) { 367 ThumbnailDatabase db; 368 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL)); 369 db.BeginTransaction(); 370 371 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1)); 372 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data)); 373 374 // Add a favicon which will have icon_mappings 375 FaviconID id1 = db.AddFavicon(GURL("http://google.com"), FAVICON); 376 EXPECT_NE(id1, 0); 377 base::Time time = base::Time::Now(); 378 db.SetFavicon(id1, favicon, time); 379 380 // Add another type of favicon 381 FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"), TOUCH_ICON); 382 EXPECT_NE(id2, 0); 383 time = base::Time::Now(); 384 db.SetFavicon(id2, favicon, time); 385 386 // Add 3rd favicon 387 FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"), TOUCH_ICON); 388 EXPECT_NE(id3, 0); 389 time = base::Time::Now(); 390 db.SetFavicon(id3, favicon, time); 391 392 // Add 2 icon mapping 393 GURL page_url("http://www.google.com"); 394 EXPECT_TRUE(db.AddIconMapping(page_url, id1)); 395 EXPECT_TRUE(db.AddIconMapping(page_url, id2)); 396 397 EXPECT_TRUE(db.HasMappingFor(id1)); 398 EXPECT_TRUE(db.HasMappingFor(id2)); 399 EXPECT_FALSE(db.HasMappingFor(id3)); 400 401 // Remove all mappings 402 db.DeleteIconMappings(page_url); 403 EXPECT_FALSE(db.HasMappingFor(id1)); 404 EXPECT_FALSE(db.HasMappingFor(id2)); 405 EXPECT_FALSE(db.HasMappingFor(id3)); 406 } 407 408 TEST_F(IconMappingMigrationTest, TestIconMappingMigration) { 409 HistoryDatabase history_db; 410 ASSERT_TRUE(history_db.db_.Open(history_db_name_)); 411 history_db.BeginTransaction(); 412 413 const GURL icon1 = GURL("http://www.google.com/favicon.ico"); 414 const GURL icon2 = GURL("http://www.yahoo.com/favicon.ico"); 415 416 ThumbnailDatabase db; 417 ASSERT_EQ(sql::INIT_OK, db.Init(thumbnail_db_name_, NULL, &history_db)); 418 db.BeginTransaction(); 419 420 // Migration should be done. 421 // Test one icon_mapping. 422 GURL page_url1 = GURL("http://google.com/"); 423 std::vector<IconMapping> icon_mappings; 424 EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url1, &icon_mappings)); 425 ASSERT_EQ(1u, icon_mappings.size()); 426 EXPECT_EQ(FAVICON, icon_mappings[0].icon_type); 427 EXPECT_EQ(page_url1, icon_mappings[0].page_url); 428 EXPECT_EQ(1, icon_mappings[0].icon_id); 429 base::Time time; 430 std::vector<unsigned char> out_data; 431 GURL out_icon_url; 432 ASSERT_TRUE(db.GetFavicon( 433 icon_mappings[0].icon_id, &time, &out_data, &out_icon_url)); 434 EXPECT_EQ(icon1, out_icon_url); 435 436 // Test a page which has the same icon. 437 GURL page_url3 = GURL("http://www.google.com/"); 438 icon_mappings.clear(); 439 EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url3, &icon_mappings)); 440 ASSERT_EQ(1u, icon_mappings.size()); 441 EXPECT_EQ(FAVICON, icon_mappings[0].icon_type); 442 EXPECT_EQ(page_url3, icon_mappings[0].page_url); 443 EXPECT_EQ(1, icon_mappings[0].icon_id); 444 445 // Test a icon_mapping with different IconID. 446 GURL page_url2 = GURL("http://yahoo.com/"); 447 icon_mappings.clear(); 448 EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url2, &icon_mappings)); 449 ASSERT_EQ(1u, icon_mappings.size()); 450 EXPECT_EQ(FAVICON, icon_mappings[0].icon_type); 451 EXPECT_EQ(page_url2, icon_mappings[0].page_url); 452 EXPECT_EQ(2, icon_mappings[0].icon_id); 453 ASSERT_TRUE(db.GetFavicon( 454 icon_mappings[0].icon_id, &time, &out_data, &out_icon_url)); 455 EXPECT_EQ(icon2, out_icon_url); 456 457 // Test a page without icon 458 GURL page_url4 = GURL("http://www.google.com/blank.html"); 459 EXPECT_FALSE(db.GetIconMappingsForPageURL(page_url4, NULL)); 460 } 461 462 } // namespace history 463