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