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