1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <algorithm> 6 #include <set> 7 #include <vector> 8 9 #include "base/basictypes.h" 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/command_line.h" 13 #include "base/file_util.h" 14 #include "base/files/file_path.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/path_service.h" 18 #include "base/platform_file.h" 19 #include "base/strings/string16.h" 20 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "chrome/browser/bookmarks/bookmark_model.h" 23 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 24 #include "chrome/browser/bookmarks/bookmark_utils.h" 25 #include "chrome/browser/history/history_backend.h" 26 #include "chrome/browser/history/history_notifications.h" 27 #include "chrome/browser/history/history_service.h" 28 #include "chrome/browser/history/history_service_factory.h" 29 #include "chrome/browser/history/in_memory_database.h" 30 #include "chrome/browser/history/in_memory_history_backend.h" 31 #include "chrome/browser/history/visit_filter.h" 32 #include "chrome/common/chrome_constants.h" 33 #include "chrome/common/chrome_paths.h" 34 #include "chrome/common/chrome_switches.h" 35 #include "chrome/common/importer/imported_favicon_usage.h" 36 #include "chrome/common/thumbnail_score.h" 37 #include "chrome/test/base/testing_profile.h" 38 #include "chrome/test/base/ui_test_utils.h" 39 #include "chrome/tools/profiles/thumbnail-inl.h" 40 #include "content/public/browser/notification_details.h" 41 #include "content/public/browser/notification_source.h" 42 #include "content/public/test/test_browser_thread.h" 43 #include "testing/gtest/include/gtest/gtest.h" 44 #include "third_party/skia/include/core/SkBitmap.h" 45 #include "ui/gfx/codec/jpeg_codec.h" 46 #include "ui/gfx/image/image.h" 47 #include "url/gurl.h" 48 49 using base::Time; 50 using base::TimeDelta; 51 52 // This file only tests functionality where it is most convenient to call the 53 // backend directly. Most of the history backend functions are tested by the 54 // history unit test. Because of the elaborate callbacks involved, this is no 55 // harder than calling it directly for many things. 56 57 namespace { 58 59 // data we'll put into the thumbnail database 60 static const unsigned char blob1[] = 61 "12346102356120394751634516591348710478123649165419234519234512349134"; 62 63 static const gfx::Size kTinySize = gfx::Size(10, 10); 64 static const gfx::Size kSmallSize = gfx::Size(16, 16); 65 static const gfx::Size kLargeSize = gfx::Size(32, 32); 66 67 // Comparison functions as to make it easier to check results of 68 // GetFaviconBitmaps() and GetIconMappingsForPageURL(). 69 bool IconMappingLessThan(const history::IconMapping& a, 70 const history::IconMapping& b) { 71 return a.icon_url < b.icon_url; 72 } 73 74 bool FaviconBitmapLessThan(const history::FaviconBitmap& a, 75 const history::FaviconBitmap& b) { 76 return a.pixel_size.GetArea() < b.pixel_size.GetArea(); 77 } 78 79 } // namespace 80 81 namespace history { 82 83 class HistoryBackendTest; 84 85 // This must be a separate object since HistoryBackend manages its lifetime. 86 // This just forwards the messages we're interested in to the test object. 87 class HistoryBackendTestDelegate : public HistoryBackend::Delegate { 88 public: 89 explicit HistoryBackendTestDelegate(HistoryBackendTest* test) : test_(test) {} 90 91 virtual void NotifyProfileError(int backend_id, 92 sql::InitStatus init_status) OVERRIDE {} 93 virtual void SetInMemoryBackend(int backend_id, 94 InMemoryHistoryBackend* backend) OVERRIDE; 95 virtual void BroadcastNotifications(int type, 96 HistoryDetails* details) OVERRIDE; 97 virtual void DBLoaded(int backend_id) OVERRIDE; 98 virtual void StartTopSitesMigration(int backend_id) OVERRIDE; 99 virtual void NotifyVisitDBObserversOnAddVisit( 100 const BriefVisitInfo& info) OVERRIDE {} 101 102 private: 103 // Not owned by us. 104 HistoryBackendTest* test_; 105 106 DISALLOW_COPY_AND_ASSIGN(HistoryBackendTestDelegate); 107 }; 108 109 class HistoryBackendCancelableRequest 110 : public CancelableRequestProvider, 111 public CancelableRequestConsumerTSimple<int> { 112 public: 113 HistoryBackendCancelableRequest() {} 114 115 template<class RequestType> 116 CancelableRequestProvider::Handle MockScheduleOfRequest( 117 RequestType* request) { 118 AddRequest(request, this); 119 return request->handle(); 120 } 121 }; 122 123 class HistoryBackendTest : public testing::Test { 124 public: 125 HistoryBackendTest() 126 : bookmark_model_(NULL), 127 loaded_(false), 128 num_broadcasted_notifications_(0), 129 ui_thread_(content::BrowserThread::UI, &message_loop_) { 130 } 131 132 virtual ~HistoryBackendTest() { 133 } 134 135 // Callback for QueryMostVisited. 136 void OnQueryMostVisited(CancelableRequestProvider::Handle handle, 137 history::MostVisitedURLList data) { 138 most_visited_list_.swap(data); 139 } 140 141 // Callback for QueryFiltered. 142 void OnQueryFiltered(CancelableRequestProvider::Handle handle, 143 const history::FilteredURLList& data) { 144 filtered_list_ = data; 145 } 146 147 const history::MostVisitedURLList& get_most_visited_list() const { 148 return most_visited_list_; 149 } 150 151 const history::FilteredURLList& get_filtered_list() const { 152 return filtered_list_; 153 } 154 155 int num_broadcasted_notifications() const { 156 return num_broadcasted_notifications_; 157 } 158 159 protected: 160 scoped_refptr<HistoryBackend> backend_; // Will be NULL on init failure. 161 scoped_ptr<InMemoryHistoryBackend> mem_backend_; 162 163 void AddRedirectChain(const char* sequence[], int page_id) { 164 AddRedirectChainWithTransitionAndTime(sequence, page_id, 165 content::PAGE_TRANSITION_LINK, 166 Time::Now()); 167 } 168 169 void AddRedirectChainWithTransitionAndTime( 170 const char* sequence[], 171 int page_id, 172 content::PageTransition transition, 173 base::Time time) { 174 history::RedirectList redirects; 175 for (int i = 0; sequence[i] != NULL; ++i) 176 redirects.push_back(GURL(sequence[i])); 177 178 int int_scope = 1; 179 void* scope = 0; 180 memcpy(&scope, &int_scope, sizeof(int_scope)); 181 history::HistoryAddPageArgs request( 182 redirects.back(), time, scope, page_id, GURL(), 183 redirects, transition, history::SOURCE_BROWSED, 184 true); 185 backend_->AddPage(request); 186 } 187 188 // Adds CLIENT_REDIRECT page transition. 189 // |url1| is the source URL and |url2| is the destination. 190 // |did_replace| is true if the transition is non-user initiated and the 191 // navigation entry for |url2| has replaced that for |url1|. The possibly 192 // updated transition code of the visit records for |url1| and |url2| is 193 // returned by filling in |*transition1| and |*transition2|, respectively. 194 // |time| is a time of the redirect. 195 void AddClientRedirect(const GURL& url1, const GURL& url2, bool did_replace, 196 base::Time time, 197 int* transition1, int* transition2) { 198 void* const dummy_scope = reinterpret_cast<void*>(0x87654321); 199 history::RedirectList redirects; 200 if (url1.is_valid()) 201 redirects.push_back(url1); 202 if (url2.is_valid()) 203 redirects.push_back(url2); 204 HistoryAddPageArgs request( 205 url2, time, dummy_scope, 0, url1, 206 redirects, content::PAGE_TRANSITION_CLIENT_REDIRECT, 207 history::SOURCE_BROWSED, did_replace); 208 backend_->AddPage(request); 209 210 *transition1 = getTransition(url1); 211 *transition2 = getTransition(url2); 212 } 213 214 int getTransition(const GURL& url) { 215 if (!url.is_valid()) 216 return 0; 217 URLRow row; 218 URLID id = backend_->db()->GetRowForURL(url, &row); 219 VisitVector visits; 220 EXPECT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 221 return visits[0].transition; 222 } 223 224 base::FilePath getTestDir() { 225 return test_dir_; 226 } 227 228 // Returns a gfx::Size vector with small size. 229 const std::vector<gfx::Size> GetSizesSmall() { 230 std::vector<gfx::Size> sizes_small; 231 sizes_small.push_back(kSmallSize); 232 return sizes_small; 233 } 234 235 // Returns a gfx::Size vector with large size. 236 const std::vector<gfx::Size> GetSizesLarge() { 237 std::vector<gfx::Size> sizes_large; 238 sizes_large.push_back(kLargeSize); 239 return sizes_large; 240 } 241 242 // Returns a gfx::Size vector with small and large sizes. 243 const std::vector<gfx::Size> GetSizesSmallAndLarge() { 244 std::vector<gfx::Size> sizes_small_and_large; 245 sizes_small_and_large.push_back(kSmallSize); 246 sizes_small_and_large.push_back(kLargeSize); 247 return sizes_small_and_large; 248 } 249 250 // Returns a gfx::Size vector with tiny, small and large sizes. 251 const std::vector<gfx::Size> GetSizesTinySmallAndLarge() { 252 std::vector<gfx::Size> sizes_tiny_small_and_large; 253 sizes_tiny_small_and_large.push_back(kTinySize); 254 sizes_tiny_small_and_large.push_back(kSmallSize); 255 sizes_tiny_small_and_large.push_back(kLargeSize); 256 return sizes_tiny_small_and_large; 257 } 258 259 // Returns 1x and 2x scale factors. 260 const std::vector<ui::ScaleFactor> GetScaleFactors1x2x() { 261 std::vector<ui::ScaleFactor> scale_factors_1x_2x; 262 scale_factors_1x_2x.push_back(ui::SCALE_FACTOR_100P); 263 scale_factors_1x_2x.push_back(ui::SCALE_FACTOR_200P); 264 return scale_factors_1x_2x; 265 } 266 267 // Returns the number of icon mappings of |icon_type| to |page_url|. 268 size_t NumIconMappingsForPageURL(const GURL& page_url, 269 chrome::IconType icon_type) { 270 std::vector<IconMapping> icon_mappings; 271 backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, 272 &icon_mappings); 273 return icon_mappings.size(); 274 } 275 276 // Returns the icon mappings for |page_url| sorted alphabetically by icon 277 // URL in ascending order. Returns true if there is at least one icon 278 // mapping. 279 bool GetSortedIconMappingsForPageURL( 280 const GURL& page_url, 281 std::vector<IconMapping>* icon_mappings) { 282 if (!backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 283 icon_mappings)) { 284 return false; 285 } 286 std::sort(icon_mappings->begin(), icon_mappings->end(), 287 IconMappingLessThan); 288 return true; 289 } 290 291 // Returns the favicon bitmaps for |icon_id| sorted by pixel size in 292 // ascending order. Returns true if there is at least one favicon bitmap. 293 bool GetSortedFaviconBitmaps(chrome::FaviconID icon_id, 294 std::vector<FaviconBitmap>* favicon_bitmaps) { 295 if (!backend_->thumbnail_db_->GetFaviconBitmaps(icon_id, favicon_bitmaps)) 296 return false; 297 std::sort(favicon_bitmaps->begin(), favicon_bitmaps->end(), 298 FaviconBitmapLessThan); 299 return true; 300 } 301 302 // Returns true if there is exactly one favicon bitmap associated to 303 // |favicon_id|. If true, returns favicon bitmap in output parameter. 304 bool GetOnlyFaviconBitmap(const chrome::FaviconID icon_id, 305 FaviconBitmap* favicon_bitmap) { 306 std::vector<FaviconBitmap> favicon_bitmaps; 307 if (!backend_->thumbnail_db_->GetFaviconBitmaps(icon_id, &favicon_bitmaps)) 308 return false; 309 if (favicon_bitmaps.size() != 1) 310 return false; 311 *favicon_bitmap = favicon_bitmaps[0]; 312 return true; 313 } 314 315 // Generates |favicon_bitmap_data| with entries for the icon_urls and sizes 316 // specified. The bitmap_data for entries are lowercase letters of the 317 // alphabet starting at 'a' for the entry at index 0. 318 void GenerateFaviconBitmapData( 319 const GURL& icon_url1, 320 const std::vector<gfx::Size>& icon_url1_sizes, 321 std::vector<chrome::FaviconBitmapData>* favicon_bitmap_data) { 322 GenerateFaviconBitmapData(icon_url1, icon_url1_sizes, GURL(), 323 std::vector<gfx::Size>(), favicon_bitmap_data); 324 } 325 326 void GenerateFaviconBitmapData( 327 const GURL& icon_url1, 328 const std::vector<gfx::Size>& icon_url1_sizes, 329 const GURL& icon_url2, 330 const std::vector<gfx::Size>& icon_url2_sizes, 331 std::vector<chrome::FaviconBitmapData>* favicon_bitmap_data) { 332 favicon_bitmap_data->clear(); 333 334 char bitmap_char = 'a'; 335 for (size_t i = 0; i < icon_url1_sizes.size(); ++i) { 336 std::vector<unsigned char> data; 337 data.push_back(bitmap_char); 338 chrome::FaviconBitmapData bitmap_data_element; 339 bitmap_data_element.bitmap_data = 340 base::RefCountedBytes::TakeVector(&data); 341 bitmap_data_element.pixel_size = icon_url1_sizes[i]; 342 bitmap_data_element.icon_url = icon_url1; 343 favicon_bitmap_data->push_back(bitmap_data_element); 344 345 ++bitmap_char; 346 } 347 348 for (size_t i = 0; i < icon_url2_sizes.size(); ++i) { 349 std::vector<unsigned char> data; 350 data.push_back(bitmap_char); 351 chrome::FaviconBitmapData bitmap_data_element; 352 bitmap_data_element.bitmap_data = 353 base::RefCountedBytes::TakeVector(&data); 354 bitmap_data_element.pixel_size = icon_url2_sizes[i]; 355 bitmap_data_element.icon_url = icon_url2; 356 favicon_bitmap_data->push_back(bitmap_data_element); 357 358 ++bitmap_char; 359 } 360 } 361 362 // Returns true if |bitmap_data| is equal to |expected_data|. 363 bool BitmapDataEqual(char expected_data, 364 scoped_refptr<base::RefCountedMemory> bitmap_data) { 365 return bitmap_data.get() && 366 bitmap_data->size() == 1u && 367 *bitmap_data->front() == expected_data; 368 } 369 370 BookmarkModel bookmark_model_; 371 372 protected: 373 // testing::Test 374 virtual void SetUp() { 375 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("BackendTest"), 376 &test_dir_)) 377 return; 378 backend_ = new HistoryBackend(test_dir_, 379 0, 380 new HistoryBackendTestDelegate(this), 381 &bookmark_model_); 382 backend_->Init(std::string(), false); 383 } 384 385 bool loaded_; 386 387 private: 388 friend class HistoryBackendTestDelegate; 389 390 virtual void TearDown() { 391 if (backend_.get()) 392 backend_->Closing(); 393 backend_ = NULL; 394 mem_backend_.reset(); 395 base::DeleteFile(test_dir_, true); 396 base::RunLoop().RunUntilIdle(); 397 } 398 399 void SetInMemoryBackend(int backend_id, InMemoryHistoryBackend* backend) { 400 mem_backend_.reset(backend); 401 } 402 403 void BroadcastNotifications(int type, 404 HistoryDetails* details) { 405 ++num_broadcasted_notifications_; 406 407 // Send the notifications directly to the in-memory database. 408 content::Details<HistoryDetails> det(details); 409 mem_backend_->Observe(type, content::Source<HistoryBackendTest>(NULL), det); 410 411 // The backend passes ownership of the details pointer to us. 412 delete details; 413 } 414 415 // The number of notifications which were broadcasted. 416 int num_broadcasted_notifications_; 417 418 base::MessageLoop message_loop_; 419 base::FilePath test_dir_; 420 history::MostVisitedURLList most_visited_list_; 421 history::FilteredURLList filtered_list_; 422 content::TestBrowserThread ui_thread_; 423 }; 424 425 void HistoryBackendTestDelegate::SetInMemoryBackend(int backend_id, 426 InMemoryHistoryBackend* backend) { 427 test_->SetInMemoryBackend(backend_id, backend); 428 } 429 430 void HistoryBackendTestDelegate::BroadcastNotifications( 431 int type, 432 HistoryDetails* details) { 433 test_->BroadcastNotifications(type, details); 434 } 435 436 void HistoryBackendTestDelegate::DBLoaded(int backend_id) { 437 test_->loaded_ = true; 438 } 439 440 void HistoryBackendTestDelegate::StartTopSitesMigration(int backend_id) { 441 test_->backend_->MigrateThumbnailsDatabase(); 442 } 443 444 // http://crbug.com/114287 445 #if defined(OS_WIN) 446 #define MAYBE_Loaded DISABLED_Loaded 447 #else 448 #define MAYBE_Loaded Loaded 449 #endif // defined(OS_WIN) 450 TEST_F(HistoryBackendTest, MAYBE_Loaded) { 451 ASSERT_TRUE(backend_.get()); 452 ASSERT_TRUE(loaded_); 453 } 454 455 TEST_F(HistoryBackendTest, DeleteAll) { 456 ASSERT_TRUE(backend_.get()); 457 458 // Add two favicons, each with two bitmaps. Note that we add favicon2 before 459 // adding favicon1. This is so that favicon1 one gets ID 2 autoassigned to 460 // the database, which will change when the other one is deleted. This way 461 // we can test that updating works properly. 462 GURL favicon_url1("http://www.google.com/favicon.ico"); 463 GURL favicon_url2("http://news.google.com/favicon.ico"); 464 chrome::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon(favicon_url2, 465 chrome::FAVICON); 466 chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(favicon_url1, 467 chrome::FAVICON); 468 469 std::vector<unsigned char> data; 470 data.push_back('a'); 471 EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1, 472 new base::RefCountedBytes(data), Time::Now(), kSmallSize)); 473 data[0] = 'b'; 474 EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1, 475 new base::RefCountedBytes(data), Time::Now(), kLargeSize)); 476 477 data[0] = 'c'; 478 EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2, 479 new base::RefCountedBytes(data), Time::Now(), kSmallSize)); 480 data[0] = 'd'; 481 EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2, 482 new base::RefCountedBytes(data), Time::Now(), kLargeSize)); 483 484 // First visit two URLs. 485 URLRow row1(GURL("http://www.google.com/")); 486 row1.set_visit_count(2); 487 row1.set_typed_count(1); 488 row1.set_last_visit(Time::Now()); 489 backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1); 490 491 URLRow row2(GURL("http://news.google.com/")); 492 row2.set_visit_count(1); 493 row2.set_last_visit(Time::Now()); 494 backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2); 495 496 URLRows rows; 497 rows.push_back(row2); // Reversed order for the same reason as favicons. 498 rows.push_back(row1); 499 backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED); 500 501 URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL); 502 URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL); 503 504 // Get the two visits for the URLs we just added. 505 VisitVector visits; 506 backend_->db_->GetVisitsForURL(row1_id, &visits); 507 ASSERT_EQ(1U, visits.size()); 508 509 visits.clear(); 510 backend_->db_->GetVisitsForURL(row2_id, &visits); 511 ASSERT_EQ(1U, visits.size()); 512 513 // The in-memory backend should have been set and it should have gotten the 514 // typed URL. 515 ASSERT_TRUE(mem_backend_.get()); 516 URLRow outrow1; 517 EXPECT_TRUE(mem_backend_->db_->GetRowForURL(row1.url(), NULL)); 518 519 // Add thumbnails for each page. The |Images| take ownership of SkBitmap 520 // created from decoding the images. 521 ThumbnailScore score(0.25, true, true); 522 scoped_ptr<SkBitmap> google_bitmap( 523 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); 524 525 gfx::Image google_image = gfx::Image::CreateFrom1xBitmap(*google_bitmap); 526 527 Time time; 528 GURL gurl; 529 backend_->thumbnail_db_->SetPageThumbnail(gurl, row1_id, &google_image, 530 score, time); 531 scoped_ptr<SkBitmap> weewar_bitmap( 532 gfx::JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail))); 533 gfx::Image weewar_image = gfx::Image::CreateFrom1xBitmap(*weewar_bitmap); 534 backend_->thumbnail_db_->SetPageThumbnail(gurl, row2_id, &weewar_image, 535 score, time); 536 537 // Star row1. 538 bookmark_model_.AddURL( 539 bookmark_model_.bookmark_bar_node(), 0, string16(), row1.url()); 540 541 // Now finally clear all history. 542 backend_->DeleteAllHistory(); 543 544 // The first URL should be preserved but the time should be cleared. 545 EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1)); 546 EXPECT_EQ(row1.url(), outrow1.url()); 547 EXPECT_EQ(0, outrow1.visit_count()); 548 EXPECT_EQ(0, outrow1.typed_count()); 549 EXPECT_TRUE(Time() == outrow1.last_visit()); 550 551 // The second row should be deleted. 552 URLRow outrow2; 553 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &outrow2)); 554 555 // All visits should be deleted for both URLs. 556 VisitVector all_visits; 557 backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits); 558 ASSERT_EQ(0U, all_visits.size()); 559 560 // All thumbnails should be deleted. 561 std::vector<unsigned char> out_data; 562 EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(outrow1.id(), 563 &out_data)); 564 EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(row2_id, &out_data)); 565 566 // We should have a favicon and favicon bitmaps for the first URL only. We 567 // look them up by favicon URL since the IDs may have changed. 568 chrome::FaviconID out_favicon1 = backend_->thumbnail_db_-> 569 GetFaviconIDForFaviconURL(favicon_url1, chrome::FAVICON, NULL); 570 EXPECT_TRUE(out_favicon1); 571 572 std::vector<FaviconBitmap> favicon_bitmaps; 573 EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps( 574 out_favicon1, &favicon_bitmaps)); 575 ASSERT_EQ(2u, favicon_bitmaps.size()); 576 577 FaviconBitmap favicon_bitmap1 = favicon_bitmaps[0]; 578 FaviconBitmap favicon_bitmap2 = favicon_bitmaps[1]; 579 580 // Favicon bitmaps do not need to be in particular order. 581 if (favicon_bitmap1.pixel_size == kLargeSize) { 582 FaviconBitmap tmp_favicon_bitmap = favicon_bitmap1; 583 favicon_bitmap1 = favicon_bitmap2; 584 favicon_bitmap2 = tmp_favicon_bitmap; 585 } 586 587 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap1.bitmap_data)); 588 EXPECT_EQ(kSmallSize, favicon_bitmap1.pixel_size); 589 590 EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap2.bitmap_data)); 591 EXPECT_EQ(kLargeSize, favicon_bitmap2.pixel_size); 592 593 chrome::FaviconID out_favicon2 = backend_->thumbnail_db_-> 594 GetFaviconIDForFaviconURL(favicon_url2, chrome::FAVICON, NULL); 595 EXPECT_FALSE(out_favicon2) << "Favicon not deleted"; 596 597 // The remaining URL should still reference the same favicon, even if its 598 // ID has changed. 599 std::vector<IconMapping> mappings; 600 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 601 outrow1.url(), chrome::FAVICON, &mappings)); 602 EXPECT_EQ(1u, mappings.size()); 603 EXPECT_EQ(out_favicon1, mappings[0].icon_id); 604 605 // The first URL should still be bookmarked. 606 EXPECT_TRUE(bookmark_model_.IsBookmarked(row1.url())); 607 } 608 609 // Checks that adding a visit, then calling DeleteAll, and then trying to add 610 // data for the visited page works. This can happen when clearing the history 611 // immediately after visiting a page. 612 TEST_F(HistoryBackendTest, DeleteAllThenAddData) { 613 ASSERT_TRUE(backend_.get()); 614 615 Time visit_time = Time::Now(); 616 GURL url("http://www.google.com/"); 617 HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(), 618 history::RedirectList(), 619 content::PAGE_TRANSITION_KEYWORD_GENERATED, 620 history::SOURCE_BROWSED, false); 621 backend_->AddPage(request); 622 623 // Check that a row was added. 624 URLRow outrow; 625 EXPECT_TRUE(backend_->db_->GetRowForURL(url, &outrow)); 626 627 // Check that the visit was added. 628 VisitVector all_visits; 629 backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits); 630 ASSERT_EQ(1U, all_visits.size()); 631 632 // Clear all history. 633 backend_->DeleteAllHistory(); 634 635 // The row should be deleted. 636 EXPECT_FALSE(backend_->db_->GetRowForURL(url, &outrow)); 637 638 // The visit should be deleted. 639 backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits); 640 ASSERT_EQ(0U, all_visits.size()); 641 642 // Try and set the title. 643 backend_->SetPageTitle(url, UTF8ToUTF16("Title")); 644 645 // The row should still be deleted. 646 EXPECT_FALSE(backend_->db_->GetRowForURL(url, &outrow)); 647 648 // The visit should still be deleted. 649 backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits); 650 ASSERT_EQ(0U, all_visits.size()); 651 } 652 653 TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) { 654 GURL favicon_url1("http://www.google.com/favicon.ico"); 655 GURL favicon_url2("http://news.google.com/favicon.ico"); 656 657 std::vector<unsigned char> data; 658 data.push_back('1'); 659 chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon( 660 favicon_url1, 661 chrome::FAVICON, 662 new base::RefCountedBytes(data), 663 Time::Now(), 664 gfx::Size()); 665 666 data[0] = '2'; 667 chrome::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon( 668 favicon_url2, 669 chrome::FAVICON, 670 new base::RefCountedBytes(data), 671 Time::Now(), 672 gfx::Size()); 673 674 // First visit two URLs. 675 URLRow row1(GURL("http://www.google.com/")); 676 row1.set_visit_count(2); 677 row1.set_typed_count(1); 678 row1.set_last_visit(Time::Now()); 679 EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1)); 680 681 URLRow row2(GURL("http://news.google.com/")); 682 row2.set_visit_count(1); 683 row2.set_last_visit(Time::Now()); 684 EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2)); 685 686 URLRows rows; 687 rows.push_back(row2); // Reversed order for the same reason as favicons. 688 rows.push_back(row1); 689 backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED); 690 691 URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL); 692 URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL); 693 694 // Star the two URLs. 695 bookmark_utils::AddIfNotBookmarked(&bookmark_model_, row1.url(), string16()); 696 bookmark_utils::AddIfNotBookmarked(&bookmark_model_, row2.url(), string16()); 697 698 // Delete url 2. Because url 2 is starred this won't delete the URL, only 699 // the visits. 700 backend_->expirer_.DeleteURL(row2.url()); 701 702 // Make sure url 2 is still valid, but has no visits. 703 URLRow tmp_url_row; 704 EXPECT_EQ(row2_id, backend_->db_->GetRowForURL(row2.url(), NULL)); 705 VisitVector visits; 706 backend_->db_->GetVisitsForURL(row2_id, &visits); 707 EXPECT_EQ(0U, visits.size()); 708 // The favicon should still be valid. 709 EXPECT_EQ(favicon2, 710 backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url2, 711 chrome::FAVICON, 712 NULL)); 713 714 // Unstar row2. 715 bookmark_utils::RemoveAllBookmarks(&bookmark_model_, row2.url()); 716 717 // Tell the backend it was unstarred. We have to explicitly do this as 718 // BookmarkModel isn't wired up to the backend during testing. 719 std::set<GURL> unstarred_urls; 720 unstarred_urls.insert(row2.url()); 721 backend_->URLsNoLongerBookmarked(unstarred_urls); 722 723 // The URL should no longer exist. 724 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row)); 725 // And the favicon should be deleted. 726 EXPECT_EQ(0, 727 backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url2, 728 chrome::FAVICON, 729 NULL)); 730 731 // Unstar row 1. 732 bookmark_utils::RemoveAllBookmarks(&bookmark_model_, row1.url()); 733 // Tell the backend it was unstarred. We have to explicitly do this as 734 // BookmarkModel isn't wired up to the backend during testing. 735 unstarred_urls.clear(); 736 unstarred_urls.insert(row1.url()); 737 backend_->URLsNoLongerBookmarked(unstarred_urls); 738 739 // The URL should still exist (because there were visits). 740 EXPECT_EQ(row1_id, backend_->db_->GetRowForURL(row1.url(), NULL)); 741 742 // There should still be visits. 743 visits.clear(); 744 backend_->db_->GetVisitsForURL(row1_id, &visits); 745 EXPECT_EQ(1U, visits.size()); 746 747 // The favicon should still be valid. 748 EXPECT_EQ(favicon1, 749 backend_->thumbnail_db_->GetFaviconIDForFaviconURL(favicon_url1, 750 chrome::FAVICON, 751 NULL)); 752 } 753 754 // Tests a handful of assertions for a navigation with a type of 755 // KEYWORD_GENERATED. 756 TEST_F(HistoryBackendTest, KeywordGenerated) { 757 ASSERT_TRUE(backend_.get()); 758 759 GURL url("http://google.com"); 760 761 Time visit_time = Time::Now() - base::TimeDelta::FromDays(1); 762 HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(), 763 history::RedirectList(), 764 content::PAGE_TRANSITION_KEYWORD_GENERATED, 765 history::SOURCE_BROWSED, false); 766 backend_->AddPage(request); 767 768 // A row should have been added for the url. 769 URLRow row; 770 URLID url_id = backend_->db()->GetRowForURL(url, &row); 771 ASSERT_NE(0, url_id); 772 773 // The typed count should be 1. 774 ASSERT_EQ(1, row.typed_count()); 775 776 // KEYWORD_GENERATED urls should not be added to the segment db. 777 std::string segment_name = VisitSegmentDatabase::ComputeSegmentName(url); 778 EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment_name)); 779 780 // One visit should be added. 781 VisitVector visits; 782 EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits)); 783 EXPECT_EQ(1U, visits.size()); 784 785 // But no visible visits. 786 visits.clear(); 787 QueryOptions query_options; 788 query_options.max_count = 1; 789 backend_->db()->GetVisibleVisitsInRange(query_options, &visits); 790 EXPECT_TRUE(visits.empty()); 791 792 // Expire the visits. 793 std::set<GURL> restrict_urls; 794 backend_->expire_backend()->ExpireHistoryBetween(restrict_urls, 795 visit_time, Time::Now()); 796 797 // The visit should have been nuked. 798 visits.clear(); 799 EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits)); 800 EXPECT_TRUE(visits.empty()); 801 802 // As well as the url. 803 ASSERT_EQ(0, backend_->db()->GetRowForURL(url, &row)); 804 } 805 806 TEST_F(HistoryBackendTest, ClientRedirect) { 807 ASSERT_TRUE(backend_.get()); 808 809 int transition1; 810 int transition2; 811 812 // Initial transition to page A. 813 GURL url_a("http://google.com/a"); 814 AddClientRedirect(GURL(), url_a, false, base::Time(), 815 &transition1, &transition2); 816 EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END); 817 818 // User initiated redirect to page B. 819 GURL url_b("http://google.com/b"); 820 AddClientRedirect(url_a, url_b, false, base::Time(), 821 &transition1, &transition2); 822 EXPECT_TRUE(transition1 & content::PAGE_TRANSITION_CHAIN_END); 823 EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END); 824 825 // Non-user initiated redirect to page C. 826 GURL url_c("http://google.com/c"); 827 AddClientRedirect(url_b, url_c, true, base::Time(), 828 &transition1, &transition2); 829 EXPECT_FALSE(transition1 & content::PAGE_TRANSITION_CHAIN_END); 830 EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END); 831 } 832 833 TEST_F(HistoryBackendTest, ImportedFaviconsTest) { 834 // Setup test data - two Urls in the history, one with favicon assigned and 835 // one without. 836 GURL favicon_url1("http://www.google.com/favicon.ico"); 837 std::vector<unsigned char> data; 838 data.push_back('1'); 839 chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon( 840 favicon_url1, 841 chrome::FAVICON, 842 base::RefCountedBytes::TakeVector(&data), 843 Time::Now(), 844 gfx::Size()); 845 URLRow row1(GURL("http://www.google.com/")); 846 row1.set_visit_count(1); 847 row1.set_last_visit(Time::Now()); 848 EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1)); 849 850 URLRow row2(GURL("http://news.google.com/")); 851 row2.set_visit_count(1); 852 row2.set_last_visit(Time::Now()); 853 URLRows rows; 854 rows.push_back(row1); 855 rows.push_back(row2); 856 backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED); 857 URLRow url_row1, url_row2; 858 EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0); 859 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0); 860 EXPECT_EQ(1u, NumIconMappingsForPageURL(row1.url(), chrome::FAVICON)); 861 EXPECT_EQ(0u, NumIconMappingsForPageURL(row2.url(), chrome::FAVICON)); 862 863 // Now provide one imported favicon for both URLs already in the registry. 864 // The new favicon should only be used with the URL that doesn't already have 865 // a favicon. 866 std::vector<ImportedFaviconUsage> favicons; 867 ImportedFaviconUsage favicon; 868 favicon.favicon_url = GURL("http://news.google.com/favicon.ico"); 869 favicon.png_data.push_back('2'); 870 favicon.urls.insert(row1.url()); 871 favicon.urls.insert(row2.url()); 872 favicons.push_back(favicon); 873 backend_->SetImportedFavicons(favicons); 874 EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0); 875 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0); 876 877 std::vector<IconMapping> mappings; 878 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 879 row1.url(), chrome::FAVICON, &mappings)); 880 EXPECT_EQ(1u, mappings.size()); 881 EXPECT_EQ(favicon1, mappings[0].icon_id); 882 EXPECT_EQ(favicon_url1, mappings[0].icon_url); 883 884 mappings.clear(); 885 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 886 row2.url(), chrome::FAVICON, &mappings)); 887 EXPECT_EQ(1u, mappings.size()); 888 EXPECT_EQ(favicon.favicon_url, mappings[0].icon_url); 889 890 // A URL should not be added to history (to store favicon), if 891 // the URL is not bookmarked. 892 GURL url3("http://mail.google.com"); 893 favicons.clear(); 894 favicon.favicon_url = GURL("http://mail.google.com/favicon.ico"); 895 favicon.png_data.push_back('3'); 896 favicon.urls.insert(url3); 897 favicons.push_back(favicon); 898 backend_->SetImportedFavicons(favicons); 899 URLRow url_row3; 900 EXPECT_TRUE(backend_->db_->GetRowForURL(url3, &url_row3) == 0); 901 902 // If the URL is bookmarked, it should get added to history with 0 visits. 903 bookmark_model_.AddURL(bookmark_model_.bookmark_bar_node(), 0, string16(), 904 url3); 905 backend_->SetImportedFavicons(favicons); 906 EXPECT_FALSE(backend_->db_->GetRowForURL(url3, &url_row3) == 0); 907 EXPECT_TRUE(url_row3.visit_count() == 0); 908 } 909 910 TEST_F(HistoryBackendTest, StripUsernamePasswordTest) { 911 ASSERT_TRUE(backend_.get()); 912 913 GURL url("http://anyuser:anypass@www.google.com"); 914 GURL stripped_url("http://www.google.com"); 915 916 // Clear all history. 917 backend_->DeleteAllHistory(); 918 919 // Visit the url with username, password. 920 backend_->AddPageVisit(url, base::Time::Now(), 0, 921 content::PageTransitionFromInt( 922 content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)), 923 history::SOURCE_BROWSED); 924 925 // Fetch the row information about stripped url from history db. 926 VisitVector visits; 927 URLID row_id = backend_->db_->GetRowForURL(stripped_url, NULL); 928 backend_->db_->GetVisitsForURL(row_id, &visits); 929 930 // Check if stripped url is stored in database. 931 ASSERT_EQ(1U, visits.size()); 932 } 933 934 TEST_F(HistoryBackendTest, AddPageVisitSource) { 935 ASSERT_TRUE(backend_.get()); 936 937 GURL url("http://www.google.com"); 938 939 // Clear all history. 940 backend_->DeleteAllHistory(); 941 942 // Assume visiting the url from an externsion. 943 backend_->AddPageVisit( 944 url, base::Time::Now(), 0, content::PAGE_TRANSITION_TYPED, 945 history::SOURCE_EXTENSION); 946 // Assume the url is imported from Firefox. 947 backend_->AddPageVisit(url, base::Time::Now(), 0, 948 content::PAGE_TRANSITION_TYPED, 949 history::SOURCE_FIREFOX_IMPORTED); 950 // Assume this url is also synced. 951 backend_->AddPageVisit(url, base::Time::Now(), 0, 952 content::PAGE_TRANSITION_TYPED, 953 history::SOURCE_SYNCED); 954 955 // Fetch the row information about the url from history db. 956 VisitVector visits; 957 URLID row_id = backend_->db_->GetRowForURL(url, NULL); 958 backend_->db_->GetVisitsForURL(row_id, &visits); 959 960 // Check if all the visits to the url are stored in database. 961 ASSERT_EQ(3U, visits.size()); 962 VisitSourceMap visit_sources; 963 ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources)); 964 ASSERT_EQ(3U, visit_sources.size()); 965 int sources = 0; 966 for (int i = 0; i < 3; i++) { 967 switch (visit_sources[visits[i].visit_id]) { 968 case history::SOURCE_EXTENSION: 969 sources |= 0x1; 970 break; 971 case history::SOURCE_FIREFOX_IMPORTED: 972 sources |= 0x2; 973 break; 974 case history::SOURCE_SYNCED: 975 sources |= 0x4; 976 default: 977 break; 978 } 979 } 980 EXPECT_EQ(0x7, sources); 981 } 982 983 TEST_F(HistoryBackendTest, AddPageVisitNotLastVisit) { 984 ASSERT_TRUE(backend_.get()); 985 986 GURL url("http://www.google.com"); 987 988 // Clear all history. 989 backend_->DeleteAllHistory(); 990 991 // Create visit times 992 base::Time recent_time = base::Time::Now(); 993 base::TimeDelta visit_age = base::TimeDelta::FromDays(3); 994 base::Time older_time = recent_time - visit_age; 995 996 // Visit the url with recent time. 997 backend_->AddPageVisit(url, recent_time, 0, 998 content::PageTransitionFromInt( 999 content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)), 1000 history::SOURCE_BROWSED); 1001 1002 // Add to the url a visit with older time (could be syncing from another 1003 // client, etc.). 1004 backend_->AddPageVisit(url, older_time, 0, 1005 content::PageTransitionFromInt( 1006 content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)), 1007 history::SOURCE_SYNCED); 1008 1009 // Fetch the row information about url from history db. 1010 VisitVector visits; 1011 URLRow row; 1012 URLID row_id = backend_->db_->GetRowForURL(url, &row); 1013 backend_->db_->GetVisitsForURL(row_id, &visits); 1014 1015 // Last visit time should be the most recent time, not the most recently added 1016 // visit. 1017 ASSERT_EQ(2U, visits.size()); 1018 ASSERT_EQ(recent_time, row.last_visit()); 1019 } 1020 1021 TEST_F(HistoryBackendTest, AddPageArgsSource) { 1022 ASSERT_TRUE(backend_.get()); 1023 1024 GURL url("http://testpageargs.com"); 1025 1026 // Assume this page is browsed by user. 1027 HistoryAddPageArgs request1(url, base::Time::Now(), NULL, 0, GURL(), 1028 history::RedirectList(), 1029 content::PAGE_TRANSITION_KEYWORD_GENERATED, 1030 history::SOURCE_BROWSED, false); 1031 backend_->AddPage(request1); 1032 // Assume this page is synced. 1033 HistoryAddPageArgs request2(url, base::Time::Now(), NULL, 0, GURL(), 1034 history::RedirectList(), 1035 content::PAGE_TRANSITION_LINK, 1036 history::SOURCE_SYNCED, false); 1037 backend_->AddPage(request2); 1038 // Assume this page is browsed again. 1039 HistoryAddPageArgs request3(url, base::Time::Now(), NULL, 0, GURL(), 1040 history::RedirectList(), 1041 content::PAGE_TRANSITION_TYPED, 1042 history::SOURCE_BROWSED, false); 1043 backend_->AddPage(request3); 1044 1045 // Three visits should be added with proper sources. 1046 VisitVector visits; 1047 URLRow row; 1048 URLID id = backend_->db()->GetRowForURL(url, &row); 1049 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1050 ASSERT_EQ(3U, visits.size()); 1051 VisitSourceMap visit_sources; 1052 ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources)); 1053 ASSERT_EQ(1U, visit_sources.size()); 1054 EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second); 1055 } 1056 1057 TEST_F(HistoryBackendTest, AddVisitsSource) { 1058 ASSERT_TRUE(backend_.get()); 1059 1060 GURL url1("http://www.cnn.com"); 1061 std::vector<VisitInfo> visits1, visits2; 1062 visits1.push_back(VisitInfo( 1063 Time::Now() - base::TimeDelta::FromDays(5), 1064 content::PAGE_TRANSITION_LINK)); 1065 visits1.push_back(VisitInfo( 1066 Time::Now() - base::TimeDelta::FromDays(1), 1067 content::PAGE_TRANSITION_LINK)); 1068 visits1.push_back(VisitInfo( 1069 Time::Now(), content::PAGE_TRANSITION_LINK)); 1070 1071 GURL url2("http://www.example.com"); 1072 visits2.push_back(VisitInfo( 1073 Time::Now() - base::TimeDelta::FromDays(10), 1074 content::PAGE_TRANSITION_LINK)); 1075 visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK)); 1076 1077 // Clear all history. 1078 backend_->DeleteAllHistory(); 1079 1080 // Add the visits. 1081 backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED); 1082 backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED); 1083 1084 // Verify the visits were added with their sources. 1085 VisitVector visits; 1086 URLRow row; 1087 URLID id = backend_->db()->GetRowForURL(url1, &row); 1088 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1089 ASSERT_EQ(3U, visits.size()); 1090 VisitSourceMap visit_sources; 1091 ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources)); 1092 ASSERT_EQ(3U, visit_sources.size()); 1093 for (int i = 0; i < 3; i++) 1094 EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]); 1095 id = backend_->db()->GetRowForURL(url2, &row); 1096 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1097 ASSERT_EQ(2U, visits.size()); 1098 ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources)); 1099 ASSERT_EQ(2U, visit_sources.size()); 1100 for (int i = 0; i < 2; i++) 1101 EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]); 1102 } 1103 1104 TEST_F(HistoryBackendTest, GetMostRecentVisits) { 1105 ASSERT_TRUE(backend_.get()); 1106 1107 GURL url1("http://www.cnn.com"); 1108 std::vector<VisitInfo> visits1; 1109 visits1.push_back(VisitInfo( 1110 Time::Now() - base::TimeDelta::FromDays(5), 1111 content::PAGE_TRANSITION_LINK)); 1112 visits1.push_back(VisitInfo( 1113 Time::Now() - base::TimeDelta::FromDays(1), 1114 content::PAGE_TRANSITION_LINK)); 1115 visits1.push_back(VisitInfo( 1116 Time::Now(), content::PAGE_TRANSITION_LINK)); 1117 1118 // Clear all history. 1119 backend_->DeleteAllHistory(); 1120 1121 // Add the visits. 1122 backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED); 1123 1124 // Verify the visits were added with their sources. 1125 VisitVector visits; 1126 URLRow row; 1127 URLID id = backend_->db()->GetRowForURL(url1, &row); 1128 ASSERT_TRUE(backend_->db()->GetMostRecentVisitsForURL(id, 1, &visits)); 1129 ASSERT_EQ(1U, visits.size()); 1130 EXPECT_EQ(visits1[2].first, visits[0].visit_time); 1131 } 1132 1133 TEST_F(HistoryBackendTest, RemoveVisitsTransitions) { 1134 ASSERT_TRUE(backend_.get()); 1135 1136 // Clear all history. 1137 backend_->DeleteAllHistory(); 1138 1139 GURL url1("http://www.cnn.com"); 1140 VisitInfo typed_visit( 1141 Time::Now() - base::TimeDelta::FromDays(6), 1142 content::PAGE_TRANSITION_TYPED); 1143 VisitInfo reload_visit( 1144 Time::Now() - base::TimeDelta::FromDays(5), 1145 content::PAGE_TRANSITION_RELOAD); 1146 VisitInfo link_visit( 1147 Time::Now() - base::TimeDelta::FromDays(4), 1148 content::PAGE_TRANSITION_LINK); 1149 std::vector<VisitInfo> visits_to_add; 1150 visits_to_add.push_back(typed_visit); 1151 visits_to_add.push_back(reload_visit); 1152 visits_to_add.push_back(link_visit); 1153 1154 // Add the visits. 1155 backend_->AddVisits(url1, visits_to_add, history::SOURCE_SYNCED); 1156 1157 // Verify that the various counts are what we expect. 1158 VisitVector visits; 1159 URLRow row; 1160 URLID id = backend_->db()->GetRowForURL(url1, &row); 1161 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1162 ASSERT_EQ(3U, visits.size()); 1163 ASSERT_EQ(1, row.typed_count()); 1164 ASSERT_EQ(2, row.visit_count()); 1165 1166 // Now, delete the typed visit and verify that typed_count is updated. 1167 ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0]))); 1168 id = backend_->db()->GetRowForURL(url1, &row); 1169 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1170 ASSERT_EQ(2U, visits.size()); 1171 ASSERT_EQ(0, row.typed_count()); 1172 ASSERT_EQ(1, row.visit_count()); 1173 1174 // Delete the reload visit now and verify that none of the counts have 1175 // changed. 1176 ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0]))); 1177 id = backend_->db()->GetRowForURL(url1, &row); 1178 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1179 ASSERT_EQ(1U, visits.size()); 1180 ASSERT_EQ(0, row.typed_count()); 1181 ASSERT_EQ(1, row.visit_count()); 1182 1183 // Delete the last visit and verify that we delete the URL. 1184 ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0]))); 1185 ASSERT_EQ(0, backend_->db()->GetRowForURL(url1, &row)); 1186 } 1187 1188 TEST_F(HistoryBackendTest, RemoveVisitsSource) { 1189 ASSERT_TRUE(backend_.get()); 1190 1191 GURL url1("http://www.cnn.com"); 1192 std::vector<VisitInfo> visits1, visits2; 1193 visits1.push_back(VisitInfo( 1194 Time::Now() - base::TimeDelta::FromDays(5), 1195 content::PAGE_TRANSITION_LINK)); 1196 visits1.push_back(VisitInfo(Time::Now(), 1197 content::PAGE_TRANSITION_LINK)); 1198 1199 GURL url2("http://www.example.com"); 1200 visits2.push_back(VisitInfo( 1201 Time::Now() - base::TimeDelta::FromDays(10), 1202 content::PAGE_TRANSITION_LINK)); 1203 visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK)); 1204 1205 // Clear all history. 1206 backend_->DeleteAllHistory(); 1207 1208 // Add the visits. 1209 backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED); 1210 backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED); 1211 1212 // Verify the visits of url1 were added. 1213 VisitVector visits; 1214 URLRow row; 1215 URLID id = backend_->db()->GetRowForURL(url1, &row); 1216 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1217 ASSERT_EQ(2U, visits.size()); 1218 // Remove these visits. 1219 ASSERT_TRUE(backend_->RemoveVisits(visits)); 1220 1221 // Now check only url2's source in visit_source table. 1222 VisitSourceMap visit_sources; 1223 ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources)); 1224 ASSERT_EQ(0U, visit_sources.size()); 1225 id = backend_->db()->GetRowForURL(url2, &row); 1226 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 1227 ASSERT_EQ(2U, visits.size()); 1228 ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources)); 1229 ASSERT_EQ(2U, visit_sources.size()); 1230 for (int i = 0; i < 2; i++) 1231 EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]); 1232 } 1233 1234 // Test for migration of adding visit_source table. 1235 TEST_F(HistoryBackendTest, MigrationVisitSource) { 1236 ASSERT_TRUE(backend_.get()); 1237 backend_->Closing(); 1238 backend_ = NULL; 1239 1240 base::FilePath old_history_path; 1241 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path)); 1242 old_history_path = old_history_path.AppendASCII("History"); 1243 old_history_path = old_history_path.AppendASCII("HistoryNoSource"); 1244 1245 // Copy history database file to current directory so that it will be deleted 1246 // in Teardown. 1247 base::FilePath new_history_path(getTestDir()); 1248 base::DeleteFile(new_history_path, true); 1249 file_util::CreateDirectory(new_history_path); 1250 base::FilePath new_history_file = 1251 new_history_path.Append(chrome::kHistoryFilename); 1252 ASSERT_TRUE(base::CopyFile(old_history_path, new_history_file)); 1253 1254 backend_ = new HistoryBackend(new_history_path, 1255 0, 1256 new HistoryBackendTestDelegate(this), 1257 &bookmark_model_); 1258 backend_->Init(std::string(), false); 1259 backend_->Closing(); 1260 backend_ = NULL; 1261 1262 // Now the database should already be migrated. 1263 // Check version first. 1264 int cur_version = HistoryDatabase::GetCurrentVersion(); 1265 sql::Connection db; 1266 ASSERT_TRUE(db.Open(new_history_file)); 1267 sql::Statement s(db.GetUniqueStatement( 1268 "SELECT value FROM meta WHERE key = 'version'")); 1269 ASSERT_TRUE(s.Step()); 1270 int file_version = s.ColumnInt(0); 1271 EXPECT_EQ(cur_version, file_version); 1272 1273 // Check visit_source table is created and empty. 1274 s.Assign(db.GetUniqueStatement( 1275 "SELECT name FROM sqlite_master WHERE name=\"visit_source\"")); 1276 ASSERT_TRUE(s.Step()); 1277 s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10")); 1278 EXPECT_FALSE(s.Step()); 1279 } 1280 1281 // Test that SetFaviconMappingsForPageAndRedirects correctly updates icon 1282 // mappings based on redirects, icon URLs and icon types. 1283 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirects) { 1284 // Init recent_redirects_ 1285 const GURL url1("http://www.google.com"); 1286 const GURL url2("http://www.google.com/m"); 1287 URLRow url_info1(url1); 1288 url_info1.set_visit_count(0); 1289 url_info1.set_typed_count(0); 1290 url_info1.set_last_visit(base::Time()); 1291 url_info1.set_hidden(false); 1292 backend_->db_->AddURL(url_info1); 1293 1294 URLRow url_info2(url2); 1295 url_info2.set_visit_count(0); 1296 url_info2.set_typed_count(0); 1297 url_info2.set_last_visit(base::Time()); 1298 url_info2.set_hidden(false); 1299 backend_->db_->AddURL(url_info2); 1300 1301 history::RedirectList redirects; 1302 redirects.push_back(url2); 1303 redirects.push_back(url1); 1304 backend_->recent_redirects_.Put(url1, redirects); 1305 1306 const GURL icon_url1("http://www.google.com/icon"); 1307 const GURL icon_url2("http://www.google.com/icon2"); 1308 1309 // Generate bitmap data for a page with two favicons. 1310 std::vector<chrome::FaviconBitmapData> two_favicon_bitmap_data; 1311 GenerateFaviconBitmapData(icon_url1, GetSizesSmallAndLarge(), 1312 icon_url2, GetSizesSmallAndLarge(), &two_favicon_bitmap_data); 1313 1314 // Generate bitmap data for a page with a single favicon. 1315 std::vector<chrome::FaviconBitmapData> one_favicon_bitmap_data; 1316 GenerateFaviconBitmapData(icon_url1, GetSizesSmallAndLarge(), 1317 &one_favicon_bitmap_data); 1318 1319 // Add two favicons 1320 backend_->SetFavicons(url1, chrome::FAVICON, two_favicon_bitmap_data); 1321 EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON)); 1322 EXPECT_EQ(2u, NumIconMappingsForPageURL(url2, chrome::FAVICON)); 1323 1324 // Add one touch_icon 1325 backend_->SetFavicons(url1, chrome::TOUCH_ICON, one_favicon_bitmap_data); 1326 EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON)); 1327 EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, chrome::TOUCH_ICON)); 1328 EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON)); 1329 1330 // Add one TOUCH_PRECOMPOSED_ICON 1331 backend_->SetFavicons( 1332 url1, chrome::TOUCH_PRECOMPOSED_ICON, one_favicon_bitmap_data); 1333 // The touch_icon was replaced. 1334 EXPECT_EQ(0u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON)); 1335 EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON)); 1336 EXPECT_EQ(1u, 1337 NumIconMappingsForPageURL(url1, chrome::TOUCH_PRECOMPOSED_ICON)); 1338 EXPECT_EQ(1u, 1339 NumIconMappingsForPageURL(url2, chrome::TOUCH_PRECOMPOSED_ICON)); 1340 1341 // Add a touch_icon. 1342 backend_->SetFavicons(url1, chrome::TOUCH_ICON, one_favicon_bitmap_data); 1343 EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON)); 1344 EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON)); 1345 // The TOUCH_PRECOMPOSED_ICON was replaced. 1346 EXPECT_EQ(0u, 1347 NumIconMappingsForPageURL(url1, chrome::TOUCH_PRECOMPOSED_ICON)); 1348 1349 // Add a single favicon. 1350 backend_->SetFavicons(url1, chrome::FAVICON, one_favicon_bitmap_data); 1351 EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON)); 1352 EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::FAVICON)); 1353 EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, chrome::FAVICON)); 1354 1355 // Add two favicons. 1356 backend_->SetFavicons(url1, chrome::FAVICON, two_favicon_bitmap_data); 1357 EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, chrome::TOUCH_ICON)); 1358 EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, chrome::FAVICON)); 1359 } 1360 1361 // Test that there is no churn in icon mappings from calling 1362 // SetFavicons() twice with the same |favicon_bitmap_data| parameter. 1363 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageDuplicates) { 1364 const GURL url("http://www.google.com/"); 1365 const GURL icon_url("http://www.google.com/icon"); 1366 1367 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1368 GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(), 1369 &favicon_bitmap_data); 1370 1371 backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data); 1372 1373 std::vector<IconMapping> icon_mappings; 1374 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 1375 url, chrome::FAVICON, &icon_mappings)); 1376 EXPECT_EQ(1u, icon_mappings.size()); 1377 IconMappingID mapping_id = icon_mappings[0].mapping_id; 1378 1379 backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data); 1380 1381 icon_mappings.clear(); 1382 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 1383 url, chrome::FAVICON, &icon_mappings)); 1384 EXPECT_EQ(1u, icon_mappings.size()); 1385 1386 // The same row in the icon_mapping table should be used for the mapping as 1387 // before. 1388 EXPECT_EQ(mapping_id, icon_mappings[0].mapping_id); 1389 } 1390 1391 // Test that calling SetFavicons() with FaviconBitmapData of different pixel 1392 // sizes than the initially passed in FaviconBitmapData deletes the no longer 1393 // used favicon bitmaps. 1394 TEST_F(HistoryBackendTest, SetFaviconsDeleteBitmaps) { 1395 const GURL page_url("http://www.google.com/"); 1396 const GURL icon_url("http://www.google.com/icon"); 1397 1398 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1399 GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(), 1400 &favicon_bitmap_data); 1401 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1402 1403 // Test initial state. 1404 std::vector<IconMapping> icon_mappings; 1405 EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url, &icon_mappings)); 1406 EXPECT_EQ(1u, icon_mappings.size()); 1407 EXPECT_EQ(icon_url, icon_mappings[0].icon_url); 1408 EXPECT_EQ(chrome::FAVICON, icon_mappings[0].icon_type); 1409 chrome::FaviconID favicon_id = icon_mappings[0].icon_id; 1410 1411 std::vector<FaviconBitmap> favicon_bitmaps; 1412 EXPECT_TRUE(GetSortedFaviconBitmaps(favicon_id, &favicon_bitmaps)); 1413 EXPECT_EQ(2u, favicon_bitmaps.size()); 1414 FaviconBitmapID small_bitmap_id = favicon_bitmaps[0].bitmap_id; 1415 EXPECT_NE(0, small_bitmap_id); 1416 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmaps[0].bitmap_data)); 1417 EXPECT_EQ(kSmallSize, favicon_bitmaps[0].pixel_size); 1418 FaviconBitmapID large_bitmap_id = favicon_bitmaps[1].bitmap_id; 1419 EXPECT_NE(0, large_bitmap_id); 1420 EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data)); 1421 EXPECT_EQ(kLargeSize, favicon_bitmaps[1].pixel_size); 1422 1423 // Call SetFavicons() with bitmap data for only the large bitmap. Check that 1424 // the small bitmap is in fact deleted. 1425 GenerateFaviconBitmapData(icon_url, GetSizesLarge(), &favicon_bitmap_data); 1426 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1427 1428 scoped_refptr<base::RefCountedMemory> bitmap_data_out; 1429 gfx::Size pixel_size_out; 1430 EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(small_bitmap_id, 1431 NULL, &bitmap_data_out, &pixel_size_out)); 1432 EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id, 1433 NULL, &bitmap_data_out, &pixel_size_out)); 1434 EXPECT_TRUE(BitmapDataEqual('a', bitmap_data_out)); 1435 EXPECT_EQ(kLargeSize, pixel_size_out); 1436 1437 icon_mappings.clear(); 1438 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1439 &icon_mappings)); 1440 EXPECT_EQ(1u, icon_mappings.size()); 1441 EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); 1442 1443 // Call SetFavicons() with no bitmap data. Check that the bitmaps and icon 1444 // mappings are deleted. 1445 favicon_bitmap_data.clear(); 1446 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1447 1448 EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id, NULL, 1449 NULL, NULL)); 1450 icon_mappings.clear(); 1451 EXPECT_FALSE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1452 &icon_mappings)); 1453 1454 // Notifications should have been broadcast for each call to SetFavicons(). 1455 EXPECT_EQ(3, num_broadcasted_notifications()); 1456 } 1457 1458 // Test updating a single favicon bitmap's data via SetFavicons. 1459 TEST_F(HistoryBackendTest, SetFaviconsReplaceBitmapData) { 1460 const GURL page_url("http://www.google.com/"); 1461 const GURL icon_url("http://www.google.com/icon"); 1462 1463 std::vector<unsigned char> data_initial; 1464 data_initial.push_back('a'); 1465 1466 chrome::FaviconBitmapData bitmap_data_element; 1467 bitmap_data_element.bitmap_data = 1468 base::RefCountedBytes::TakeVector(&data_initial); 1469 bitmap_data_element.pixel_size = kSmallSize; 1470 bitmap_data_element.icon_url = icon_url; 1471 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1472 favicon_bitmap_data.push_back(bitmap_data_element); 1473 1474 // Add bitmap to the database. 1475 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1476 1477 chrome::FaviconID original_favicon_id = 1478 backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1479 icon_url, chrome::FAVICON, NULL); 1480 EXPECT_NE(0, original_favicon_id); 1481 FaviconBitmap original_favicon_bitmap; 1482 EXPECT_TRUE( 1483 GetOnlyFaviconBitmap(original_favicon_id, &original_favicon_bitmap)); 1484 EXPECT_TRUE(BitmapDataEqual('a', original_favicon_bitmap.bitmap_data)); 1485 1486 EXPECT_EQ(1, num_broadcasted_notifications()); 1487 1488 // Call SetFavicons() with completely identical data. 1489 std::vector<unsigned char> updated_data; 1490 updated_data.push_back('a'); 1491 favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data); 1492 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1493 1494 chrome::FaviconID updated_favicon_id = 1495 backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1496 icon_url, chrome::FAVICON, NULL); 1497 EXPECT_NE(0, updated_favicon_id); 1498 FaviconBitmap updated_favicon_bitmap; 1499 EXPECT_TRUE( 1500 GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap)); 1501 EXPECT_TRUE(BitmapDataEqual('a', updated_favicon_bitmap.bitmap_data)); 1502 1503 // Because the bitmap data is byte equivalent, no notifications should have 1504 // been broadcasted. 1505 EXPECT_EQ(1, num_broadcasted_notifications()); 1506 1507 // Call SetFavicons() with identical data but a different bitmap. 1508 updated_data[0] = 'b'; 1509 favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data); 1510 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1511 1512 updated_favicon_id = 1513 backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1514 icon_url, chrome::FAVICON, NULL); 1515 EXPECT_NE(0, updated_favicon_id); 1516 EXPECT_TRUE( 1517 GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap)); 1518 EXPECT_TRUE(BitmapDataEqual('b', updated_favicon_bitmap.bitmap_data)); 1519 1520 // There should be no churn in FaviconIDs or FaviconBitmapIds even though 1521 // the bitmap data changed. 1522 EXPECT_EQ(original_favicon_bitmap.icon_id, updated_favicon_bitmap.icon_id); 1523 EXPECT_EQ(original_favicon_bitmap.bitmap_id, 1524 updated_favicon_bitmap.bitmap_id); 1525 1526 // A notification should have been broadcasted as the favicon bitmap data has 1527 // changed. 1528 EXPECT_EQ(2, num_broadcasted_notifications()); 1529 } 1530 1531 // Test that if two pages share the same FaviconID, changing the favicon for 1532 // one page does not affect the other. 1533 TEST_F(HistoryBackendTest, SetFaviconsSameFaviconURLForTwoPages) { 1534 GURL icon_url("http://www.google.com/favicon.ico"); 1535 GURL icon_url_new("http://www.google.com/favicon2.ico"); 1536 GURL page_url1("http://www.google.com"); 1537 GURL page_url2("http://www.google.ca"); 1538 1539 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1540 GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(), 1541 &favicon_bitmap_data); 1542 1543 backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data); 1544 1545 std::vector<GURL> icon_urls; 1546 icon_urls.push_back(icon_url); 1547 1548 std::vector<chrome::FaviconBitmapResult> bitmap_results; 1549 backend_->UpdateFaviconMappingsAndFetch( 1550 page_url2, icon_urls, chrome::FAVICON, kSmallSize.width(), 1551 GetScaleFactors1x2x(), &bitmap_results); 1552 1553 // Check that the same FaviconID is mapped to both page URLs. 1554 std::vector<IconMapping> icon_mappings; 1555 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 1556 page_url1, &icon_mappings)); 1557 EXPECT_EQ(1u, icon_mappings.size()); 1558 chrome::FaviconID favicon_id = icon_mappings[0].icon_id; 1559 EXPECT_NE(0, favicon_id); 1560 1561 icon_mappings.clear(); 1562 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 1563 page_url2, &icon_mappings)); 1564 EXPECT_EQ(1u, icon_mappings.size()); 1565 EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); 1566 1567 // Change the icon URL that |page_url1| is mapped to. 1568 GenerateFaviconBitmapData(icon_url_new, GetSizesSmall(), 1569 &favicon_bitmap_data); 1570 backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data); 1571 1572 // |page_url1| should map to a new FaviconID and have valid bitmap data. 1573 icon_mappings.clear(); 1574 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 1575 page_url1, &icon_mappings)); 1576 EXPECT_EQ(1u, icon_mappings.size()); 1577 EXPECT_EQ(icon_url_new, icon_mappings[0].icon_url); 1578 EXPECT_NE(favicon_id, icon_mappings[0].icon_id); 1579 1580 std::vector<FaviconBitmap> favicon_bitmaps; 1581 EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps( 1582 icon_mappings[0].icon_id, &favicon_bitmaps)); 1583 EXPECT_EQ(1u, favicon_bitmaps.size()); 1584 1585 // |page_url2| should still map to the same FaviconID and have valid bitmap 1586 // data. 1587 icon_mappings.clear(); 1588 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 1589 page_url2, &icon_mappings)); 1590 EXPECT_EQ(1u, icon_mappings.size()); 1591 EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); 1592 1593 favicon_bitmaps.clear(); 1594 EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(favicon_id, 1595 &favicon_bitmaps)); 1596 EXPECT_EQ(2u, favicon_bitmaps.size()); 1597 1598 // A notification should have been broadcast for each call to SetFavicons() 1599 // and each call to UpdateFaviconMappingsAndFetch(). 1600 EXPECT_EQ(3, num_broadcasted_notifications()); 1601 } 1602 1603 // Test that no notifications are broadcast as a result of calling 1604 // UpdateFaviconMappingsAndFetch() for an icon URL which is already 1605 // mapped to the passed in page URL. 1606 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoChange) { 1607 GURL page_url("http://www.google.com"); 1608 GURL icon_url("http://www.google.com/favicon.ico"); 1609 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1610 GenerateFaviconBitmapData(icon_url, GetSizesSmall(), &favicon_bitmap_data); 1611 1612 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1613 1614 chrome::FaviconID icon_id = 1615 backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1616 icon_url, chrome::FAVICON, NULL); 1617 EXPECT_NE(0, icon_id); 1618 EXPECT_EQ(1, num_broadcasted_notifications()); 1619 1620 std::vector<GURL> icon_urls; 1621 icon_urls.push_back(icon_url); 1622 1623 std::vector<chrome::FaviconBitmapResult> bitmap_results; 1624 backend_->UpdateFaviconMappingsAndFetch( 1625 page_url, icon_urls, chrome::FAVICON, kSmallSize.width(), 1626 GetScaleFactors1x2x(), &bitmap_results); 1627 1628 EXPECT_EQ(icon_id, backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1629 icon_url, chrome::FAVICON, NULL)); 1630 1631 // No notification should have been broadcast as no icon mapping, favicon, 1632 // or favicon bitmap was updated, added or removed. 1633 EXPECT_EQ(1, num_broadcasted_notifications()); 1634 } 1635 1636 // Test repeatedly calling MergeFavicon(). |page_url| is initially not known 1637 // to the database. 1638 TEST_F(HistoryBackendTest, MergeFaviconPageURLNotInDB) { 1639 GURL page_url("http://www.google.com"); 1640 GURL icon_url("http:/www.google.com/favicon.ico"); 1641 1642 std::vector<unsigned char> data; 1643 data.push_back('a'); 1644 scoped_refptr<base::RefCountedBytes> bitmap_data( 1645 new base::RefCountedBytes(data)); 1646 1647 backend_->MergeFavicon( 1648 page_url, icon_url, chrome::FAVICON, bitmap_data, kSmallSize); 1649 1650 // |page_url| should now be mapped to |icon_url| and the favicon bitmap should 1651 // not be expired. 1652 std::vector<IconMapping> icon_mappings; 1653 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1654 &icon_mappings)); 1655 EXPECT_EQ(1u, icon_mappings.size()); 1656 EXPECT_EQ(icon_url, icon_mappings[0].icon_url); 1657 1658 FaviconBitmap favicon_bitmap; 1659 EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); 1660 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1661 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data)); 1662 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1663 1664 data[0] = 'b'; 1665 bitmap_data = new base::RefCountedBytes(data); 1666 backend_->MergeFavicon( 1667 page_url, icon_url, chrome::FAVICON, bitmap_data, kSmallSize); 1668 1669 // |page_url| should still have a single favicon bitmap. The bitmap data 1670 // should be updated. 1671 icon_mappings.clear(); 1672 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1673 &icon_mappings)); 1674 EXPECT_EQ(1u, icon_mappings.size()); 1675 EXPECT_EQ(icon_url, icon_mappings[0].icon_url); 1676 1677 EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); 1678 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1679 EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data)); 1680 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1681 } 1682 1683 // Test calling MergeFavicon() when |page_url| is known to the database. 1684 TEST_F(HistoryBackendTest, MergeFaviconPageURLInDB) { 1685 GURL page_url("http://www.google.com"); 1686 GURL icon_url1("http:/www.google.com/favicon.ico"); 1687 GURL icon_url2("http://www.google.com/favicon2.ico"); 1688 1689 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1690 GenerateFaviconBitmapData(icon_url1, GetSizesSmall(), 1691 &favicon_bitmap_data); 1692 1693 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1694 1695 // Test initial state. 1696 std::vector<IconMapping> icon_mappings; 1697 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1698 &icon_mappings)); 1699 EXPECT_EQ(1u, icon_mappings.size()); 1700 EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); 1701 1702 FaviconBitmap favicon_bitmap; 1703 EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); 1704 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1705 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data)); 1706 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1707 1708 EXPECT_EQ(1, num_broadcasted_notifications()); 1709 1710 // 1) Merge identical favicon bitmap. 1711 std::vector<unsigned char> data; 1712 data.push_back('a'); 1713 scoped_refptr<base::RefCountedBytes> bitmap_data( 1714 new base::RefCountedBytes(data)); 1715 backend_->MergeFavicon( 1716 page_url, icon_url1, chrome::FAVICON, bitmap_data, kSmallSize); 1717 1718 // All the data should stay the same and no notifications should have been 1719 // sent. 1720 icon_mappings.clear(); 1721 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1722 &icon_mappings)); 1723 EXPECT_EQ(1u, icon_mappings.size()); 1724 EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); 1725 1726 EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); 1727 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1728 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data)); 1729 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1730 1731 EXPECT_EQ(1, num_broadcasted_notifications()); 1732 1733 // 2) Merge favicon bitmap of the same size. 1734 data[0] = 'b'; 1735 bitmap_data = new base::RefCountedBytes(data); 1736 backend_->MergeFavicon( 1737 page_url, icon_url1, chrome::FAVICON, bitmap_data, kSmallSize); 1738 1739 // The small favicon bitmap at |icon_url1| should be overwritten. 1740 icon_mappings.clear(); 1741 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1742 &icon_mappings)); 1743 EXPECT_EQ(1u, icon_mappings.size()); 1744 EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); 1745 1746 EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); 1747 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1748 EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data)); 1749 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1750 1751 // 3) Merge favicon for the same icon URL, but a pixel size for which there is 1752 // no favicon bitmap. 1753 data[0] = 'c'; 1754 bitmap_data = new base::RefCountedBytes(data); 1755 backend_->MergeFavicon( 1756 page_url, icon_url1, chrome::FAVICON, bitmap_data, kTinySize); 1757 1758 // A new favicon bitmap should be created and the preexisting favicon bitmap 1759 // ('b') should be expired. 1760 icon_mappings.clear(); 1761 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1762 &icon_mappings)); 1763 EXPECT_EQ(1u, icon_mappings.size()); 1764 EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); 1765 1766 std::vector<FaviconBitmap> favicon_bitmaps; 1767 EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id, 1768 &favicon_bitmaps)); 1769 EXPECT_NE(base::Time(), favicon_bitmaps[0].last_updated); 1770 EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data)); 1771 EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size); 1772 EXPECT_EQ(base::Time(), favicon_bitmaps[1].last_updated); 1773 EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data)); 1774 EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size); 1775 1776 // 4) Merge favicon for an icon URL different from the icon URLs already 1777 // mapped to page URL. 1778 data[0] = 'd'; 1779 bitmap_data = new base::RefCountedBytes(data); 1780 backend_->MergeFavicon( 1781 page_url, icon_url2, chrome::FAVICON, bitmap_data, kSmallSize); 1782 1783 // The existing favicon bitmaps should be copied over to the newly created 1784 // favicon at |icon_url2|. |page_url| should solely be mapped to |icon_url2|. 1785 icon_mappings.clear(); 1786 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1787 &icon_mappings)); 1788 EXPECT_EQ(1u, icon_mappings.size()); 1789 EXPECT_EQ(icon_url2, icon_mappings[0].icon_url); 1790 1791 favicon_bitmaps.clear(); 1792 EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id, 1793 &favicon_bitmaps)); 1794 EXPECT_EQ(base::Time(), favicon_bitmaps[0].last_updated); 1795 EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data)); 1796 EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size); 1797 // The favicon being merged should take precedence over the preexisting 1798 // favicon bitmaps. 1799 EXPECT_NE(base::Time(), favicon_bitmaps[1].last_updated); 1800 EXPECT_TRUE(BitmapDataEqual('d', favicon_bitmaps[1].bitmap_data)); 1801 EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size); 1802 1803 // A notification should have been broadcast for each call to SetFavicons() 1804 // and MergeFavicon(). 1805 EXPECT_EQ(4, num_broadcasted_notifications()); 1806 } 1807 1808 // Test calling MergeFavicon() when |icon_url| is known to the database but not 1809 // mapped to |page_url|. 1810 TEST_F(HistoryBackendTest, MergeFaviconIconURLMappedToDifferentPageURL) { 1811 GURL page_url1("http://www.google.com"); 1812 GURL page_url2("http://news.google.com"); 1813 GURL page_url3("http://maps.google.com"); 1814 GURL icon_url("http:/www.google.com/favicon.ico"); 1815 1816 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1817 GenerateFaviconBitmapData(icon_url, GetSizesSmall(), 1818 &favicon_bitmap_data); 1819 1820 backend_->SetFavicons(page_url1, chrome::FAVICON, favicon_bitmap_data); 1821 1822 // Test initial state. 1823 std::vector<IconMapping> icon_mappings; 1824 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1, 1825 &icon_mappings)); 1826 EXPECT_EQ(1u, icon_mappings.size()); 1827 EXPECT_EQ(icon_url, icon_mappings[0].icon_url); 1828 1829 FaviconBitmap favicon_bitmap; 1830 EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); 1831 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1832 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data)); 1833 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1834 1835 // 1) Merge in an identical favicon bitmap data but for a different page URL. 1836 std::vector<unsigned char> data; 1837 data.push_back('a'); 1838 scoped_refptr<base::RefCountedBytes> bitmap_data( 1839 new base::RefCountedBytes(data)); 1840 1841 backend_->MergeFavicon( 1842 page_url2, icon_url, chrome::FAVICON, bitmap_data, kSmallSize); 1843 1844 chrome::FaviconID favicon_id = 1845 backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1846 icon_url, chrome::FAVICON, NULL); 1847 EXPECT_NE(0, favicon_id); 1848 1849 EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap)); 1850 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1851 EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data)); 1852 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1853 1854 // 2) Merging a favicon bitmap with different bitmap data for the same icon 1855 // URL should overwrite the small favicon bitmap at |icon_url|. 1856 bitmap_data->data()[0] = 'b'; 1857 backend_->MergeFavicon( 1858 page_url3, icon_url, chrome::FAVICON, bitmap_data, kSmallSize); 1859 1860 favicon_id = backend_->thumbnail_db_->GetFaviconIDForFaviconURL( 1861 icon_url, chrome::FAVICON, NULL); 1862 EXPECT_NE(0, favicon_id); 1863 1864 EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap)); 1865 EXPECT_NE(base::Time(), favicon_bitmap.last_updated); 1866 EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data)); 1867 EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); 1868 1869 // |icon_url| should be mapped to all three page URLs. 1870 icon_mappings.clear(); 1871 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1, 1872 &icon_mappings)); 1873 EXPECT_EQ(1u, icon_mappings.size()); 1874 EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); 1875 1876 icon_mappings.clear(); 1877 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url2, 1878 &icon_mappings)); 1879 EXPECT_EQ(1u, icon_mappings.size()); 1880 EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); 1881 1882 icon_mappings.clear(); 1883 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url3, 1884 &icon_mappings)); 1885 EXPECT_EQ(1u, icon_mappings.size()); 1886 EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); 1887 1888 // A notification should have been broadcast for each call to SetFavicons() 1889 // and MergeFavicon(). 1890 EXPECT_EQ(3, num_broadcasted_notifications()); 1891 } 1892 1893 // Test that MergeFavicon() does not add more than 1894 // |kMaxFaviconBitmapsPerIconURL| to a favicon. 1895 TEST_F(HistoryBackendTest, MergeFaviconMaxFaviconBitmapsPerIconURL) { 1896 GURL page_url("http://www.google.com"); 1897 std::string icon_url_string("http://www.google.com/favicon.ico"); 1898 size_t replace_index = icon_url_string.size() - 1; 1899 1900 std::vector<unsigned char> data; 1901 data.push_back('a'); 1902 scoped_refptr<base::RefCountedMemory> bitmap_data = 1903 base::RefCountedBytes::TakeVector(&data); 1904 1905 int pixel_size = 1; 1906 for (size_t i = 0; i < kMaxFaviconBitmapsPerIconURL + 1; ++i) { 1907 icon_url_string[replace_index] = '0' + i; 1908 GURL icon_url(icon_url_string); 1909 1910 backend_->MergeFavicon(page_url, icon_url, chrome::FAVICON, bitmap_data, 1911 gfx::Size(pixel_size, pixel_size)); 1912 ++pixel_size; 1913 } 1914 1915 // There should be a single favicon mapped to |page_url| with exactly 1916 // kMaxFaviconBitmapsPerIconURL favicon bitmaps. 1917 std::vector<IconMapping> icon_mappings; 1918 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, 1919 &icon_mappings)); 1920 EXPECT_EQ(1u, icon_mappings.size()); 1921 std::vector<FaviconBitmap> favicon_bitmaps; 1922 EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps( 1923 icon_mappings[0].icon_id, &favicon_bitmaps)); 1924 EXPECT_EQ(kMaxFaviconBitmapsPerIconURL, favicon_bitmaps.size()); 1925 } 1926 1927 // Tests that the favicon set by MergeFavicon() shows up in the result of 1928 // GetFaviconsForURL(). 1929 TEST_F(HistoryBackendTest, MergeFaviconShowsUpInGetFaviconsForURLResult) { 1930 GURL page_url("http://www.google.com"); 1931 GURL icon_url("http://www.google.com/favicon.ico"); 1932 GURL merged_icon_url("http://wwww.google.com/favicon2.ico"); 1933 1934 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1935 GenerateFaviconBitmapData(icon_url, GetSizesSmallAndLarge(), 1936 &favicon_bitmap_data); 1937 1938 // Set some preexisting favicons for |page_url|. 1939 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 1940 1941 // Merge small favicon. 1942 std::vector<unsigned char> data; 1943 data.push_back('c'); 1944 scoped_refptr<base::RefCountedBytes> bitmap_data( 1945 new base::RefCountedBytes(data)); 1946 backend_->MergeFavicon( 1947 page_url, merged_icon_url, chrome::FAVICON, bitmap_data, kSmallSize); 1948 1949 // Request favicon bitmaps for both 1x and 2x to simulate request done by 1950 // BookmarkModel::GetFavicon(). 1951 std::vector<chrome::FaviconBitmapResult> bitmap_results; 1952 backend_->GetFaviconsForURL(page_url, chrome::FAVICON, kSmallSize.width(), 1953 GetScaleFactors1x2x(), &bitmap_results); 1954 1955 EXPECT_EQ(2u, bitmap_results.size()); 1956 const chrome::FaviconBitmapResult& first_result = bitmap_results[0]; 1957 const chrome::FaviconBitmapResult& result = 1958 (first_result.pixel_size == kSmallSize) ? first_result 1959 : bitmap_results[1]; 1960 EXPECT_TRUE(BitmapDataEqual('c', result.bitmap_data)); 1961 } 1962 1963 // Test UpdateFaviconMapingsAndFetch() when multiple icon types are passed in. 1964 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchMultipleIconTypes) { 1965 GURL page_url1("http://www.google.com"); 1966 GURL page_url2("http://news.google.com"); 1967 GURL page_url3("http://mail.google.com"); 1968 GURL icon_urla("http://www.google.com/favicon1.ico"); 1969 GURL icon_urlb("http://www.google.com/favicon2.ico"); 1970 GURL icon_urlc("http://www.google.com/favicon3.ico"); 1971 1972 // |page_url1| is mapped to |icon_urla| which if of type TOUCH_ICON. 1973 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1974 GenerateFaviconBitmapData(icon_urla, GetSizesSmall(), &favicon_bitmap_data); 1975 backend_->SetFavicons(page_url1, chrome::TOUCH_ICON, favicon_bitmap_data); 1976 1977 // |page_url2| is mapped to |icon_urlb| and |icon_urlc| which are of type 1978 // TOUCH_PRECOMPOSED_ICON. 1979 GenerateFaviconBitmapData(icon_urlb, GetSizesSmall(), icon_urlc, 1980 GetSizesSmall(), &favicon_bitmap_data); 1981 backend_->SetFavicons( 1982 page_url2, chrome::TOUCH_PRECOMPOSED_ICON, favicon_bitmap_data); 1983 1984 std::vector<GURL> icon_urls; 1985 icon_urls.push_back(icon_urla); 1986 icon_urls.push_back(icon_urlb); 1987 icon_urls.push_back(icon_urlc); 1988 1989 std::vector<chrome::FaviconBitmapResult> bitmap_results; 1990 backend_->UpdateFaviconMappingsAndFetch( 1991 page_url3, 1992 icon_urls, 1993 (chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON), 1994 kSmallSize.width(), 1995 GetScaleFactors1x2x(), 1996 &bitmap_results); 1997 1998 // |page_url1| and |page_url2| should still be mapped to the same icon URLs. 1999 std::vector<IconMapping> icon_mappings; 2000 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1, 2001 &icon_mappings)); 2002 EXPECT_EQ(1u, icon_mappings.size()); 2003 EXPECT_EQ(icon_urla, icon_mappings[0].icon_url); 2004 EXPECT_EQ(chrome::TOUCH_ICON, icon_mappings[0].icon_type); 2005 2006 icon_mappings.clear(); 2007 EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url2, &icon_mappings)); 2008 EXPECT_EQ(2u, icon_mappings.size()); 2009 EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url); 2010 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type); 2011 EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url); 2012 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type); 2013 2014 // |page_url3| should be mapped only to |icon_urlb| and |icon_urlc| as 2015 // TOUCH_PRECOMPOSED_ICON is the largest IconType. 2016 icon_mappings.clear(); 2017 EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url3, &icon_mappings)); 2018 EXPECT_EQ(2u, icon_mappings.size()); 2019 EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url); 2020 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type); 2021 EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url); 2022 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type); 2023 } 2024 2025 // Test the results of GetFaviconsFromDB() when there are no found 2026 // favicons. 2027 TEST_F(HistoryBackendTest, GetFaviconsFromDBEmpty) { 2028 const GURL page_url("http://www.google.com/"); 2029 2030 std::vector<chrome::FaviconBitmapResult> bitmap_results; 2031 EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON, 2032 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results)); 2033 EXPECT_TRUE(bitmap_results.empty()); 2034 } 2035 2036 // Test the results of GetFaviconsFromDB() when there are matching favicons 2037 // but there are no associated favicon bitmaps. 2038 TEST_F(HistoryBackendTest, GetFaviconsFromDBNoFaviconBitmaps) { 2039 const GURL page_url("http://www.google.com/"); 2040 const GURL icon_url("http://www.google.com/icon1"); 2041 2042 chrome::FaviconID icon_id = backend_->thumbnail_db_->AddFavicon( 2043 icon_url, chrome::FAVICON); 2044 EXPECT_NE(0, icon_id); 2045 EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id)); 2046 2047 std::vector<chrome::FaviconBitmapResult> bitmap_results_out; 2048 EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON, 2049 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2050 EXPECT_TRUE(bitmap_results_out.empty()); 2051 } 2052 2053 // Test that GetFaviconsFromDB() returns results for the bitmaps which most 2054 // closely match the passed in desired size and scale factors. 2055 TEST_F(HistoryBackendTest, GetFaviconsFromDBSelectClosestMatch) { 2056 const GURL page_url("http://www.google.com/"); 2057 const GURL icon_url("http://www.google.com/icon1"); 2058 2059 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 2060 GenerateFaviconBitmapData(icon_url, GetSizesTinySmallAndLarge(), 2061 &favicon_bitmap_data); 2062 2063 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 2064 2065 std::vector<chrome::FaviconBitmapResult> bitmap_results_out; 2066 EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, 2067 chrome::FAVICON, 2068 kSmallSize.width(), 2069 GetScaleFactors1x2x(), 2070 &bitmap_results_out)); 2071 2072 // The bitmap data for the small and large bitmaps should be returned as their 2073 // sizes match exactly. 2074 EXPECT_EQ(2u, bitmap_results_out.size()); 2075 // No required order for results. 2076 if (bitmap_results_out[0].pixel_size == kLargeSize) { 2077 chrome::FaviconBitmapResult tmp_result = bitmap_results_out[0]; 2078 bitmap_results_out[0] = bitmap_results_out[1]; 2079 bitmap_results_out[1] = tmp_result; 2080 } 2081 2082 EXPECT_FALSE(bitmap_results_out[0].expired); 2083 EXPECT_TRUE(BitmapDataEqual('b', bitmap_results_out[0].bitmap_data)); 2084 EXPECT_EQ(kSmallSize, bitmap_results_out[0].pixel_size); 2085 EXPECT_EQ(icon_url, bitmap_results_out[0].icon_url); 2086 EXPECT_EQ(chrome::FAVICON, bitmap_results_out[0].icon_type); 2087 2088 EXPECT_FALSE(bitmap_results_out[1].expired); 2089 EXPECT_TRUE(BitmapDataEqual('c', bitmap_results_out[1].bitmap_data)); 2090 EXPECT_EQ(kLargeSize, bitmap_results_out[1].pixel_size); 2091 EXPECT_EQ(icon_url, bitmap_results_out[1].icon_url); 2092 EXPECT_EQ(chrome::FAVICON, bitmap_results_out[1].icon_type); 2093 } 2094 2095 // Test that GetFaviconsFromDB() returns results from the icon URL whose 2096 // bitmaps most closely match the passed in desired size and scale factors. 2097 TEST_F(HistoryBackendTest, GetFaviconsFromDBSingleIconURL) { 2098 const GURL page_url("http://www.google.com/"); 2099 2100 const GURL icon_url1("http://www.google.com/icon1"); 2101 const GURL icon_url2("http://www.google.com/icon2"); 2102 2103 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 2104 GenerateFaviconBitmapData(icon_url1, GetSizesSmall(), icon_url2, 2105 GetSizesLarge(), &favicon_bitmap_data); 2106 2107 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 2108 2109 std::vector<chrome::FaviconBitmapResult> bitmap_results_out; 2110 EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, 2111 chrome::FAVICON, 2112 kSmallSize.width(), 2113 GetScaleFactors1x2x(), 2114 &bitmap_results_out)); 2115 2116 // The results should have results for the icon URL with the large bitmap as 2117 // downscaling is preferred to upscaling. 2118 EXPECT_EQ(1u, bitmap_results_out.size()); 2119 EXPECT_EQ(kLargeSize, bitmap_results_out[0].pixel_size); 2120 EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url); 2121 } 2122 2123 // Test the results of GetFaviconsFromDB() when called with different 2124 // |icon_types|. 2125 TEST_F(HistoryBackendTest, GetFaviconsFromDBIconType) { 2126 const GURL page_url("http://www.google.com/"); 2127 const GURL icon_url1("http://www.google.com/icon1.png"); 2128 const GURL icon_url2("http://www.google.com/icon2.png"); 2129 2130 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 2131 GenerateFaviconBitmapData(icon_url1, GetSizesSmall(), &favicon_bitmap_data); 2132 backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data); 2133 2134 GenerateFaviconBitmapData(icon_url2, GetSizesSmall(), &favicon_bitmap_data); 2135 backend_->SetFavicons(page_url, chrome::TOUCH_ICON, favicon_bitmap_data); 2136 2137 std::vector<chrome::FaviconBitmapResult> bitmap_results_out; 2138 EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON, 2139 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2140 2141 EXPECT_EQ(1u, bitmap_results_out.size()); 2142 EXPECT_EQ(chrome::FAVICON, bitmap_results_out[0].icon_type); 2143 EXPECT_EQ(icon_url1, bitmap_results_out[0].icon_url); 2144 2145 bitmap_results_out.clear(); 2146 EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::TOUCH_ICON, 2147 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2148 2149 EXPECT_EQ(1u, bitmap_results_out.size()); 2150 EXPECT_EQ(chrome::TOUCH_ICON, bitmap_results_out[0].icon_type); 2151 EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url); 2152 } 2153 2154 // Test that GetFaviconsFromDB() correctly sets the expired flag for bitmap 2155 // reults. 2156 TEST_F(HistoryBackendTest, GetFaviconsFromDBExpired) { 2157 const GURL page_url("http://www.google.com/"); 2158 const GURL icon_url("http://www.google.com/icon.png"); 2159 2160 std::vector<unsigned char> data; 2161 data.push_back('a'); 2162 scoped_refptr<base::RefCountedBytes> bitmap_data( 2163 base::RefCountedBytes::TakeVector(&data)); 2164 base::Time last_updated = base::Time::FromTimeT(0); 2165 chrome::FaviconID icon_id = 2166 backend_->thumbnail_db_->AddFavicon(icon_url, 2167 chrome::FAVICON, 2168 bitmap_data, 2169 last_updated, 2170 kSmallSize); 2171 EXPECT_NE(0, icon_id); 2172 EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id)); 2173 2174 std::vector<chrome::FaviconBitmapResult> bitmap_results_out; 2175 EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url, chrome::FAVICON, 2176 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2177 2178 EXPECT_EQ(1u, bitmap_results_out.size()); 2179 EXPECT_TRUE(bitmap_results_out[0].expired); 2180 } 2181 2182 // Check that UpdateFaviconMappingsAndFetch() call back to the UI when there is 2183 // no valid thumbnail database. 2184 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoDB) { 2185 // Make the thumbnail database invalid. 2186 backend_->thumbnail_db_.reset(); 2187 2188 std::vector<chrome::FaviconBitmapResult> bitmap_results; 2189 2190 backend_->UpdateFaviconMappingsAndFetch( 2191 GURL(), std::vector<GURL>(), chrome::FAVICON, kSmallSize.width(), 2192 GetScaleFactors1x2x(), &bitmap_results); 2193 2194 EXPECT_TRUE(bitmap_results.empty()); 2195 } 2196 2197 TEST_F(HistoryBackendTest, CloneFaviconIsRestrictedToSameDomain) { 2198 const GURL url("http://www.google.com/"); 2199 const GURL same_domain_url("http://www.google.com/subdir/index.html"); 2200 const GURL foreign_domain_url("http://www.not-google.com/"); 2201 const GURL icon_url("http://www.google.com/icon.png"); 2202 2203 // Add a favicon 2204 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 2205 GenerateFaviconBitmapData(icon_url, GetSizesSmall(), &favicon_bitmap_data); 2206 backend_->SetFavicons(url, chrome::FAVICON, favicon_bitmap_data); 2207 EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL( 2208 url, chrome::FAVICON, NULL)); 2209 2210 // Validate starting state. 2211 std::vector<chrome::FaviconBitmapResult> bitmap_results_out; 2212 EXPECT_TRUE(backend_->GetFaviconsFromDB(url, chrome::FAVICON, 2213 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2214 EXPECT_FALSE(backend_->GetFaviconsFromDB(same_domain_url, chrome::FAVICON, 2215 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2216 EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url, chrome::FAVICON, 2217 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2218 2219 // Same-domain cloning should work. 2220 backend_->CloneFavicons(url, same_domain_url); 2221 EXPECT_TRUE(backend_->GetFaviconsFromDB(same_domain_url, chrome::FAVICON, 2222 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2223 2224 // Foreign-domain cloning is forbidden. 2225 backend_->CloneFavicons(url, foreign_domain_url); 2226 EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url, chrome::FAVICON, 2227 kSmallSize.width(), GetScaleFactors1x2x(), &bitmap_results_out)); 2228 } 2229 2230 TEST_F(HistoryBackendTest, QueryFilteredURLs) { 2231 const char* google = "http://www.google.com/"; 2232 const char* yahoo = "http://www.yahoo.com/"; 2233 const char* yahoo_sports = "http://sports.yahoo.com/"; 2234 const char* yahoo_sports_with_article1 = 2235 "http://sports.yahoo.com/article1.htm"; 2236 const char* yahoo_sports_with_article2 = 2237 "http://sports.yahoo.com/article2.htm"; 2238 const char* yahoo_sports_soccer = "http://sports.yahoo.com/soccer"; 2239 const char* apple = "http://www.apple.com/"; 2240 2241 // Clear all history. 2242 backend_->DeleteAllHistory(); 2243 2244 Time tested_time = Time::Now().LocalMidnight() + 2245 base::TimeDelta::FromHours(4); 2246 base::TimeDelta half_an_hour = base::TimeDelta::FromMinutes(30); 2247 base::TimeDelta one_hour = base::TimeDelta::FromHours(1); 2248 base::TimeDelta one_day = base::TimeDelta::FromDays(1); 2249 2250 const content::PageTransition kTypedTransition = 2251 content::PAGE_TRANSITION_TYPED; 2252 const content::PageTransition kKeywordGeneratedTransition = 2253 content::PAGE_TRANSITION_KEYWORD_GENERATED; 2254 2255 const char* redirect_sequence[2]; 2256 redirect_sequence[1] = NULL; 2257 2258 redirect_sequence[0] = google; 2259 AddRedirectChainWithTransitionAndTime( 2260 redirect_sequence, 0, kTypedTransition, 2261 tested_time - one_day - half_an_hour * 2); 2262 AddRedirectChainWithTransitionAndTime( 2263 redirect_sequence, 0, 2264 kTypedTransition, tested_time - one_day); 2265 AddRedirectChainWithTransitionAndTime( 2266 redirect_sequence, 0, 2267 kTypedTransition, tested_time - half_an_hour / 2); 2268 AddRedirectChainWithTransitionAndTime( 2269 redirect_sequence, 0, 2270 kTypedTransition, tested_time); 2271 2272 // Add a visit with a transition that will make sure that no segment gets 2273 // created for this page (so the subsequent entries will have different URLIDs 2274 // and SegmentIDs). 2275 redirect_sequence[0] = apple; 2276 AddRedirectChainWithTransitionAndTime( 2277 redirect_sequence, 0, kKeywordGeneratedTransition, 2278 tested_time - one_day + one_hour * 6); 2279 2280 redirect_sequence[0] = yahoo; 2281 AddRedirectChainWithTransitionAndTime( 2282 redirect_sequence, 0, kTypedTransition, 2283 tested_time - one_day + half_an_hour); 2284 AddRedirectChainWithTransitionAndTime( 2285 redirect_sequence, 0, kTypedTransition, 2286 tested_time - one_day + half_an_hour * 2); 2287 2288 redirect_sequence[0] = yahoo_sports; 2289 AddRedirectChainWithTransitionAndTime( 2290 redirect_sequence, 0, kTypedTransition, 2291 tested_time - one_day - half_an_hour * 2); 2292 AddRedirectChainWithTransitionAndTime( 2293 redirect_sequence, 0, kTypedTransition, 2294 tested_time - one_day); 2295 int transition1, transition2; 2296 AddClientRedirect(GURL(yahoo_sports), GURL(yahoo_sports_with_article1), false, 2297 tested_time - one_day + half_an_hour, 2298 &transition1, &transition2); 2299 AddClientRedirect(GURL(yahoo_sports_with_article1), 2300 GURL(yahoo_sports_with_article2), 2301 false, 2302 tested_time - one_day + half_an_hour * 2, 2303 &transition1, &transition2); 2304 2305 redirect_sequence[0] = yahoo_sports_soccer; 2306 AddRedirectChainWithTransitionAndTime(redirect_sequence, 0, 2307 kTypedTransition, 2308 tested_time - half_an_hour); 2309 backend_->Commit(); 2310 2311 scoped_refptr<QueryFilteredURLsRequest> request1 = 2312 new history::QueryFilteredURLsRequest( 2313 base::Bind(&HistoryBackendTest::OnQueryFiltered, 2314 base::Unretained(static_cast<HistoryBackendTest*>(this)))); 2315 HistoryBackendCancelableRequest cancellable_request; 2316 cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( 2317 request1.get()); 2318 2319 VisitFilter filter; 2320 // Time limit is |tested_time| +/- 45 min. 2321 base::TimeDelta three_quarters_of_an_hour = base::TimeDelta::FromMinutes(45); 2322 filter.SetFilterTime(tested_time); 2323 filter.SetFilterWidth(three_quarters_of_an_hour); 2324 backend_->QueryFilteredURLs(request1, 100, filter, false); 2325 2326 ASSERT_EQ(4U, get_filtered_list().size()); 2327 EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); 2328 EXPECT_EQ(std::string(yahoo_sports_soccer), 2329 get_filtered_list()[1].url.spec()); 2330 EXPECT_EQ(std::string(yahoo), get_filtered_list()[2].url.spec()); 2331 EXPECT_EQ(std::string(yahoo_sports), 2332 get_filtered_list()[3].url.spec()); 2333 2334 // Time limit is between |tested_time| and |tested_time| + 2 hours. 2335 scoped_refptr<QueryFilteredURLsRequest> request2 = 2336 new history::QueryFilteredURLsRequest( 2337 base::Bind(&HistoryBackendTest::OnQueryFiltered, 2338 base::Unretained(static_cast<HistoryBackendTest*>(this)))); 2339 cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( 2340 request2.get()); 2341 filter.SetFilterTime(tested_time + one_hour); 2342 filter.SetFilterWidth(one_hour); 2343 backend_->QueryFilteredURLs(request2, 100, filter, false); 2344 2345 ASSERT_EQ(3U, get_filtered_list().size()); 2346 EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); 2347 EXPECT_EQ(std::string(yahoo), get_filtered_list()[1].url.spec()); 2348 EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec()); 2349 2350 // Time limit is between |tested_time| - 2 hours and |tested_time|. 2351 scoped_refptr<QueryFilteredURLsRequest> request3 = 2352 new history::QueryFilteredURLsRequest( 2353 base::Bind(&HistoryBackendTest::OnQueryFiltered, 2354 base::Unretained(static_cast<HistoryBackendTest*>(this)))); 2355 cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( 2356 request3.get()); 2357 filter.SetFilterTime(tested_time - one_hour); 2358 filter.SetFilterWidth(one_hour); 2359 backend_->QueryFilteredURLs(request3, 100, filter, false); 2360 2361 ASSERT_EQ(3U, get_filtered_list().size()); 2362 EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); 2363 EXPECT_EQ(std::string(yahoo_sports_soccer), 2364 get_filtered_list()[1].url.spec()); 2365 EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec()); 2366 2367 filter.ClearFilters(); 2368 base::Time::Exploded exploded_time; 2369 tested_time.LocalExplode(&exploded_time); 2370 2371 // Today. 2372 scoped_refptr<QueryFilteredURLsRequest> request4 = 2373 new history::QueryFilteredURLsRequest( 2374 base::Bind(&HistoryBackendTest::OnQueryFiltered, 2375 base::Unretained(static_cast<HistoryBackendTest*>(this)))); 2376 cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( 2377 request4.get()); 2378 filter.SetFilterTime(tested_time); 2379 filter.SetDayOfTheWeekFilter(static_cast<int>(exploded_time.day_of_week)); 2380 backend_->QueryFilteredURLs(request4, 100, filter, false); 2381 2382 ASSERT_EQ(2U, get_filtered_list().size()); 2383 EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); 2384 EXPECT_EQ(std::string(yahoo_sports_soccer), 2385 get_filtered_list()[1].url.spec()); 2386 2387 // Today + time limit - only yahoo_sports_soccer should fit. 2388 scoped_refptr<QueryFilteredURLsRequest> request5 = 2389 new history::QueryFilteredURLsRequest( 2390 base::Bind(&HistoryBackendTest::OnQueryFiltered, 2391 base::Unretained(static_cast<HistoryBackendTest*>(this)))); 2392 cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( 2393 request5.get()); 2394 filter.SetFilterTime(tested_time - base::TimeDelta::FromMinutes(40)); 2395 filter.SetFilterWidth(base::TimeDelta::FromMinutes(20)); 2396 backend_->QueryFilteredURLs(request5, 100, filter, false); 2397 2398 ASSERT_EQ(1U, get_filtered_list().size()); 2399 EXPECT_EQ(std::string(yahoo_sports_soccer), 2400 get_filtered_list()[0].url.spec()); 2401 2402 // Make sure we get debug data if we request it. 2403 scoped_refptr<QueryFilteredURLsRequest> request6 = 2404 new history::QueryFilteredURLsRequest( 2405 base::Bind(&HistoryBackendTest::OnQueryFiltered, 2406 base::Unretained(static_cast<HistoryBackendTest*>(this)))); 2407 cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( 2408 request6.get()); 2409 filter.SetFilterTime(tested_time); 2410 filter.SetFilterWidth(one_hour * 2); 2411 backend_->QueryFilteredURLs(request6, 100, filter, true); 2412 2413 // If the SegmentID is used by QueryFilteredURLs when generating the debug 2414 // data instead of the URLID, the |total_visits| for the |yahoo_sports_soccer| 2415 // entry will be zero instead of 1. 2416 ASSERT_GE(get_filtered_list().size(), 2U); 2417 EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); 2418 EXPECT_EQ(std::string(yahoo_sports_soccer), 2419 get_filtered_list()[1].url.spec()); 2420 EXPECT_EQ(4U, get_filtered_list()[0].extended_info.total_visits); 2421 EXPECT_EQ(1U, get_filtered_list()[1].extended_info.total_visits); 2422 } 2423 2424 TEST_F(HistoryBackendTest, UpdateVisitDuration) { 2425 // This unit test will test adding and deleting visit details information. 2426 ASSERT_TRUE(backend_.get()); 2427 2428 GURL url1("http://www.cnn.com"); 2429 std::vector<VisitInfo> visit_info1, visit_info2; 2430 Time start_ts = Time::Now() - base::TimeDelta::FromDays(5); 2431 Time end_ts = start_ts + base::TimeDelta::FromDays(2); 2432 visit_info1.push_back(VisitInfo(start_ts, content::PAGE_TRANSITION_LINK)); 2433 2434 GURL url2("http://www.example.com"); 2435 visit_info2.push_back(VisitInfo(Time::Now() - base::TimeDelta::FromDays(10), 2436 content::PAGE_TRANSITION_LINK)); 2437 2438 // Clear all history. 2439 backend_->DeleteAllHistory(); 2440 2441 // Add the visits. 2442 backend_->AddVisits(url1, visit_info1, history::SOURCE_BROWSED); 2443 backend_->AddVisits(url2, visit_info2, history::SOURCE_BROWSED); 2444 2445 // Verify the entries for both visits were added in visit_details. 2446 VisitVector visits1, visits2; 2447 URLRow row; 2448 URLID url_id1 = backend_->db()->GetRowForURL(url1, &row); 2449 ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1)); 2450 ASSERT_EQ(1U, visits1.size()); 2451 EXPECT_EQ(0, visits1[0].visit_duration.ToInternalValue()); 2452 2453 URLID url_id2 = backend_->db()->GetRowForURL(url2, &row); 2454 ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id2, &visits2)); 2455 ASSERT_EQ(1U, visits2.size()); 2456 EXPECT_EQ(0, visits2[0].visit_duration.ToInternalValue()); 2457 2458 // Update the visit to cnn.com. 2459 backend_->UpdateVisitDuration(visits1[0].visit_id, end_ts); 2460 2461 // Check the duration for visiting cnn.com was correctly updated. 2462 ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1)); 2463 ASSERT_EQ(1U, visits1.size()); 2464 base::TimeDelta expected_duration = end_ts - start_ts; 2465 EXPECT_EQ(expected_duration.ToInternalValue(), 2466 visits1[0].visit_duration.ToInternalValue()); 2467 2468 // Remove the visit to cnn.com. 2469 ASSERT_TRUE(backend_->RemoveVisits(visits1)); 2470 } 2471 2472 // Test for migration of adding visit_duration column. 2473 TEST_F(HistoryBackendTest, MigrationVisitDuration) { 2474 ASSERT_TRUE(backend_.get()); 2475 backend_->Closing(); 2476 backend_ = NULL; 2477 2478 base::FilePath old_history_path, old_history, old_archived; 2479 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path)); 2480 old_history_path = old_history_path.AppendASCII("History"); 2481 old_history = old_history_path.AppendASCII("HistoryNoDuration"); 2482 old_archived = old_history_path.AppendASCII("ArchivedNoDuration"); 2483 2484 // Copy history database file to current directory so that it will be deleted 2485 // in Teardown. 2486 base::FilePath new_history_path(getTestDir()); 2487 base::DeleteFile(new_history_path, true); 2488 file_util::CreateDirectory(new_history_path); 2489 base::FilePath new_history_file = 2490 new_history_path.Append(chrome::kHistoryFilename); 2491 base::FilePath new_archived_file = 2492 new_history_path.Append(chrome::kArchivedHistoryFilename); 2493 ASSERT_TRUE(base::CopyFile(old_history, new_history_file)); 2494 ASSERT_TRUE(base::CopyFile(old_archived, new_archived_file)); 2495 2496 backend_ = new HistoryBackend(new_history_path, 2497 0, 2498 new HistoryBackendTestDelegate(this), 2499 &bookmark_model_); 2500 backend_->Init(std::string(), false); 2501 backend_->Closing(); 2502 backend_ = NULL; 2503 2504 // Now both history and archived_history databases should already be migrated. 2505 2506 // Check version in history database first. 2507 int cur_version = HistoryDatabase::GetCurrentVersion(); 2508 sql::Connection db; 2509 ASSERT_TRUE(db.Open(new_history_file)); 2510 sql::Statement s(db.GetUniqueStatement( 2511 "SELECT value FROM meta WHERE key = 'version'")); 2512 ASSERT_TRUE(s.Step()); 2513 int file_version = s.ColumnInt(0); 2514 EXPECT_EQ(cur_version, file_version); 2515 2516 // Check visit_duration column in visits table is created and set to 0. 2517 s.Assign(db.GetUniqueStatement( 2518 "SELECT visit_duration FROM visits LIMIT 1")); 2519 ASSERT_TRUE(s.Step()); 2520 EXPECT_EQ(0, s.ColumnInt(0)); 2521 2522 // Repeat version and visit_duration checks in archived history database 2523 // also. 2524 cur_version = ArchivedDatabase::GetCurrentVersion(); 2525 sql::Connection archived_db; 2526 ASSERT_TRUE(archived_db.Open(new_archived_file)); 2527 sql::Statement s1(archived_db.GetUniqueStatement( 2528 "SELECT value FROM meta WHERE key = 'version'")); 2529 ASSERT_TRUE(s1.Step()); 2530 file_version = s1.ColumnInt(0); 2531 EXPECT_EQ(cur_version, file_version); 2532 2533 // Check visit_duration column in visits table is created and set to 0. 2534 s1.Assign(archived_db.GetUniqueStatement( 2535 "SELECT visit_duration FROM visits LIMIT 1")); 2536 ASSERT_TRUE(s1.Step()); 2537 EXPECT_EQ(0, s1.ColumnInt(0)); 2538 } 2539 2540 TEST_F(HistoryBackendTest, AddPageNoVisitForBookmark) { 2541 ASSERT_TRUE(backend_.get()); 2542 2543 GURL url("http://www.google.com"); 2544 string16 title(UTF8ToUTF16("Bookmark title")); 2545 backend_->AddPageNoVisitForBookmark(url, title); 2546 2547 URLRow row; 2548 backend_->GetURL(url, &row); 2549 EXPECT_EQ(url, row.url()); 2550 EXPECT_EQ(title, row.title()); 2551 EXPECT_EQ(0, row.visit_count()); 2552 2553 backend_->DeleteURL(url); 2554 backend_->AddPageNoVisitForBookmark(url, string16()); 2555 backend_->GetURL(url, &row); 2556 EXPECT_EQ(url, row.url()); 2557 EXPECT_EQ(UTF8ToUTF16(url.spec()), row.title()); 2558 EXPECT_EQ(0, row.visit_count()); 2559 } 2560 2561 TEST_F(HistoryBackendTest, ExpireHistoryForTimes) { 2562 ASSERT_TRUE(backend_.get()); 2563 2564 HistoryAddPageArgs args[10]; 2565 for (size_t i = 0; i < arraysize(args); ++i) { 2566 args[i].url = GURL("http://example" + 2567 std::string((i % 2 == 0 ? ".com" : ".net"))); 2568 args[i].time = base::Time::FromInternalValue(i); 2569 backend_->AddPage(args[i]); 2570 } 2571 EXPECT_EQ(base::Time(), backend_->GetFirstRecordedTimeForTest()); 2572 2573 URLRow row; 2574 for (size_t i = 0; i < arraysize(args); ++i) { 2575 EXPECT_TRUE(backend_->GetURL(args[i].url, &row)); 2576 } 2577 2578 std::set<base::Time> times; 2579 times.insert(args[5].time); 2580 backend_->ExpireHistoryForTimes(times, 2581 base::Time::FromInternalValue(2), 2582 base::Time::FromInternalValue(8)); 2583 2584 EXPECT_EQ(base::Time::FromInternalValue(0), 2585 backend_->GetFirstRecordedTimeForTest()); 2586 2587 // Visits to http://example.com are untouched. 2588 VisitVector visit_vector; 2589 EXPECT_TRUE(backend_->GetVisitsForURL( 2590 backend_->db_->GetRowForURL(GURL("http://example.com"), NULL), 2591 &visit_vector)); 2592 ASSERT_EQ(5u, visit_vector.size()); 2593 EXPECT_EQ(base::Time::FromInternalValue(0), visit_vector[0].visit_time); 2594 EXPECT_EQ(base::Time::FromInternalValue(2), visit_vector[1].visit_time); 2595 EXPECT_EQ(base::Time::FromInternalValue(4), visit_vector[2].visit_time); 2596 EXPECT_EQ(base::Time::FromInternalValue(6), visit_vector[3].visit_time); 2597 EXPECT_EQ(base::Time::FromInternalValue(8), visit_vector[4].visit_time); 2598 2599 // Visits to http://example.net between [2,8] are removed. 2600 visit_vector.clear(); 2601 EXPECT_TRUE(backend_->GetVisitsForURL( 2602 backend_->db_->GetRowForURL(GURL("http://example.net"), NULL), 2603 &visit_vector)); 2604 ASSERT_EQ(2u, visit_vector.size()); 2605 EXPECT_EQ(base::Time::FromInternalValue(1), visit_vector[0].visit_time); 2606 EXPECT_EQ(base::Time::FromInternalValue(9), visit_vector[1].visit_time); 2607 2608 EXPECT_EQ(base::Time::FromInternalValue(0), 2609 backend_->GetFirstRecordedTimeForTest()); 2610 } 2611 2612 TEST_F(HistoryBackendTest, ExpireHistory) { 2613 ASSERT_TRUE(backend_.get()); 2614 // Since history operations are dependent on the local timezone, make all 2615 // entries relative to a fixed, local reference time. 2616 base::Time reference_time = base::Time::UnixEpoch().LocalMidnight() + 2617 base::TimeDelta::FromHours(12); 2618 2619 // Insert 4 entries into the database. 2620 HistoryAddPageArgs args[4]; 2621 for (size_t i = 0; i < arraysize(args); ++i) { 2622 args[i].url = GURL("http://example" + base::IntToString(i) + ".com"); 2623 args[i].time = reference_time + base::TimeDelta::FromDays(i); 2624 backend_->AddPage(args[i]); 2625 } 2626 2627 URLRow url_rows[4]; 2628 for (unsigned int i = 0; i < arraysize(args); ++i) 2629 ASSERT_TRUE(backend_->GetURL(args[i].url, &url_rows[i])); 2630 2631 std::vector<ExpireHistoryArgs> expire_list; 2632 VisitVector visits; 2633 2634 // Passing an empty map should be a no-op. 2635 backend_->ExpireHistory(expire_list); 2636 backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits); 2637 EXPECT_EQ(4U, visits.size()); 2638 2639 // Trying to delete an unknown URL with the time of the first visit should 2640 // also be a no-op. 2641 expire_list.resize(expire_list.size() + 1); 2642 expire_list[0].SetTimeRangeForOneDay(args[0].time); 2643 expire_list[0].urls.insert(GURL("http://google.does-not-exist")); 2644 backend_->ExpireHistory(expire_list); 2645 backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits); 2646 EXPECT_EQ(4U, visits.size()); 2647 2648 // Now add the first URL with the same time -- it should get deleted. 2649 expire_list.back().urls.insert(url_rows[0].url()); 2650 backend_->ExpireHistory(expire_list); 2651 2652 backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits); 2653 ASSERT_EQ(3U, visits.size()); 2654 EXPECT_EQ(visits[0].url_id, url_rows[1].id()); 2655 EXPECT_EQ(visits[1].url_id, url_rows[2].id()); 2656 EXPECT_EQ(visits[2].url_id, url_rows[3].id()); 2657 2658 // The first recorded time should also get updated. 2659 EXPECT_EQ(backend_->GetFirstRecordedTimeForTest(), args[1].time); 2660 2661 // Now delete the rest of the visits in one call. 2662 for (unsigned int i = 1; i < arraysize(args); ++i) { 2663 expire_list.resize(expire_list.size() + 1); 2664 expire_list[i].SetTimeRangeForOneDay(args[i].time); 2665 expire_list[i].urls.insert(args[i].url); 2666 } 2667 backend_->ExpireHistory(expire_list); 2668 2669 backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits); 2670 ASSERT_EQ(0U, visits.size()); 2671 } 2672 2673 class HistoryBackendSegmentDurationTest : public HistoryBackendTest { 2674 public: 2675 HistoryBackendSegmentDurationTest() {} 2676 2677 virtual void SetUp() { 2678 CommandLine::ForCurrentProcess()->AppendSwitch( 2679 switches::kTrackActiveVisitTime); 2680 HistoryBackendTest::SetUp(); 2681 } 2682 2683 private: 2684 DISALLOW_COPY_AND_ASSIGN(HistoryBackendSegmentDurationTest); 2685 }; 2686 2687 // Assertions around segment durations. 2688 TEST_F(HistoryBackendSegmentDurationTest, SegmentDuration) { 2689 const GURL url1("http://www.google.com"); 2690 const GURL url2("http://www.foo.com/m"); 2691 const std::string segment1(VisitSegmentDatabase::ComputeSegmentName(url1)); 2692 const std::string segment2(VisitSegmentDatabase::ComputeSegmentName(url2)); 2693 2694 Time segment_time(VisitSegmentDatabase::SegmentTime(Time::Now())); 2695 URLRow url_info1(url1); 2696 url_info1.set_visit_count(0); 2697 url_info1.set_typed_count(0); 2698 url_info1.set_last_visit(segment_time); 2699 url_info1.set_hidden(false); 2700 const URLID url1_id = backend_->db()->AddURL(url_info1); 2701 EXPECT_NE(0, url1_id); 2702 2703 URLRow url_info2(url2); 2704 url_info2.set_visit_count(0); 2705 url_info2.set_typed_count(0); 2706 url_info2.set_last_visit(Time()); 2707 url_info2.set_hidden(false); 2708 const URLID url2_id = backend_->db()->AddURL(url_info2); 2709 EXPECT_NE(0, url2_id); 2710 EXPECT_NE(url1_id, url2_id); 2711 2712 // Should not have any segments for the urls. 2713 EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment1)); 2714 EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment2)); 2715 2716 // Update the duration, which should implicitly create the segments. 2717 const TimeDelta segment1_time_delta(TimeDelta::FromHours(1)); 2718 const TimeDelta segment2_time_delta(TimeDelta::FromHours(2)); 2719 backend_->IncreaseSegmentDuration(url1, segment_time, segment1_time_delta); 2720 backend_->IncreaseSegmentDuration(url2, segment_time, segment2_time_delta); 2721 2722 // Get the ids of the segments that were created. 2723 const SegmentID segment1_id = backend_->db()->GetSegmentNamed(segment1); 2724 EXPECT_NE(0, segment1_id); 2725 const SegmentID segment2_id = backend_->db()->GetSegmentNamed(segment2); 2726 EXPECT_NE(0, segment2_id); 2727 EXPECT_NE(segment1_id, segment2_id); 2728 2729 // Make sure the values made it to the db. 2730 SegmentDurationID segment1_duration_id; 2731 TimeDelta fetched_delta; 2732 EXPECT_TRUE(backend_->db()->GetSegmentDuration( 2733 segment1_id, segment_time, &segment1_duration_id, 2734 &fetched_delta)); 2735 EXPECT_NE(0, segment1_duration_id); 2736 EXPECT_EQ(segment1_time_delta.InHours(), fetched_delta.InHours()); 2737 2738 SegmentDurationID segment2_duration_id; 2739 EXPECT_TRUE(backend_->db()->GetSegmentDuration( 2740 segment2_id, segment_time, &segment2_duration_id, 2741 &fetched_delta)); 2742 EXPECT_NE(0, segment2_duration_id); 2743 EXPECT_NE(segment1_duration_id, segment2_duration_id); 2744 EXPECT_EQ(segment2_time_delta.InHours(), fetched_delta.InHours()); 2745 2746 // Query by duration. |url2| should be first as it has a longer view time. 2747 ScopedVector<PageUsageData> data; 2748 backend_->db()->QuerySegmentDuration(segment_time, 10, &data.get()); 2749 ASSERT_EQ(2u, data.size()); 2750 EXPECT_EQ(url2.spec(), data[0]->GetURL().spec()); 2751 EXPECT_EQ(url2_id, data[0]->GetID()); 2752 EXPECT_EQ(segment2_time_delta.InHours(), data[0]->duration().InHours()); 2753 2754 EXPECT_EQ(url1.spec(), data[1]->GetURL().spec()); 2755 EXPECT_EQ(url1_id, data[1]->GetID()); 2756 EXPECT_EQ(segment1_time_delta.InHours(), data[1]->duration().InHours()); 2757 } 2758 2759 // Simple test that removes a bookmark. This test exercises the code paths in 2760 // History that block till bookmark bar model is loaded. 2761 TEST_F(HistoryBackendTest, RemoveNotification) { 2762 scoped_ptr<TestingProfile> profile(new TestingProfile()); 2763 2764 ASSERT_TRUE(profile->CreateHistoryService(false, false)); 2765 profile->CreateBookmarkModel(true); 2766 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile.get()); 2767 ui_test_utils::WaitForBookmarkModelToLoad(model); 2768 2769 // Add a URL. 2770 GURL url("http://www.google.com"); 2771 bookmark_utils::AddIfNotBookmarked(model, url, base::string16()); 2772 2773 HistoryService* service = HistoryServiceFactory::GetForProfile( 2774 profile.get(), Profile::EXPLICIT_ACCESS); 2775 2776 service->AddPage( 2777 url, base::Time::Now(), NULL, 1, GURL(), RedirectList(), 2778 content::PAGE_TRANSITION_TYPED, SOURCE_BROWSED, false); 2779 2780 // This won't actually delete the URL, rather it'll empty out the visits. 2781 // This triggers blocking on the BookmarkModel. 2782 service->DeleteURL(url); 2783 } 2784 2785 // Test DeleteFTSIndexDatabases deletes expected files. 2786 TEST_F(HistoryBackendTest, DeleteFTSIndexDatabases) { 2787 ASSERT_TRUE(backend_.get()); 2788 2789 base::FilePath history_path(getTestDir()); 2790 base::FilePath db1(history_path.AppendASCII("History Index 2013-05")); 2791 base::FilePath db1_journal(db1.InsertBeforeExtensionASCII("-journal")); 2792 base::FilePath db1_wal(db1.InsertBeforeExtensionASCII("-wal")); 2793 base::FilePath db2_symlink(history_path.AppendASCII("History Index 2013-06")); 2794 base::FilePath db2_actual(history_path.AppendASCII("Underlying DB")); 2795 2796 // Setup dummy index database files. 2797 const char* data = "Dummy"; 2798 const size_t data_len = 5; 2799 ASSERT_TRUE(file_util::WriteFile(db1, data, data_len)); 2800 ASSERT_TRUE(file_util::WriteFile(db1_journal, data, data_len)); 2801 ASSERT_TRUE(file_util::WriteFile(db1_wal, data, data_len)); 2802 ASSERT_TRUE(file_util::WriteFile(db2_actual, data, data_len)); 2803 #if defined(OS_POSIX) 2804 EXPECT_TRUE(file_util::CreateSymbolicLink(db2_actual, db2_symlink)); 2805 #endif 2806 2807 // Delete all DTS index databases. 2808 backend_->DeleteFTSIndexDatabases(); 2809 EXPECT_FALSE(base::PathExists(db1)); 2810 EXPECT_FALSE(base::PathExists(db1_wal)); 2811 EXPECT_FALSE(base::PathExists(db1_journal)); 2812 EXPECT_FALSE(base::PathExists(db2_symlink)); 2813 EXPECT_TRUE(base::PathExists(db2_actual)); // Symlinks shouldn't be followed. 2814 } 2815 2816 } // namespace history 2817