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