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