history_backend_unittest.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 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 "base/file_path.h" 6#include "base/file_util.h" 7#include "base/command_line.h" 8#include "base/path_service.h" 9#include "base/ref_counted.h" 10#include "base/scoped_ptr.h" 11#include "base/string16.h" 12#include "base/utf_string_conversions.h" 13#include "chrome/browser/bookmarks/bookmark_model.h" 14#include "chrome/browser/history/history_backend.h" 15#include "chrome/browser/history/history_notifications.h" 16#include "chrome/browser/history/in_memory_history_backend.h" 17#include "chrome/browser/history/in_memory_database.h" 18#include "chrome/browser/history/top_sites.h" 19#include "chrome/common/chrome_constants.h" 20#include "chrome/common/chrome_paths.h" 21#include "chrome/common/chrome_switches.h" 22#include "chrome/common/notification_service.h" 23#include "chrome/common/thumbnail_score.h" 24#include "chrome/tools/profiles/thumbnail-inl.h" 25#include "gfx/codec/jpeg_codec.h" 26#include "googleurl/src/gurl.h" 27#include "testing/gtest/include/gtest/gtest.h" 28 29using base::Time; 30 31// This file only tests functionality where it is most convenient to call the 32// backend directly. Most of the history backend functions are tested by the 33// history unit test. Because of the elaborate callbacks involved, this is no 34// harder than calling it directly for many things. 35 36namespace history { 37 38class HistoryBackendTest; 39 40// This must be a separate object since HistoryBackend manages its lifetime. 41// This just forwards the messages we're interested in to the test object. 42class HistoryBackendTestDelegate : public HistoryBackend::Delegate { 43 public: 44 explicit HistoryBackendTestDelegate(HistoryBackendTest* test) : test_(test) {} 45 46 virtual void NotifyProfileError(int message_id) {} 47 virtual void SetInMemoryBackend(InMemoryHistoryBackend* backend); 48 virtual void BroadcastNotifications(NotificationType type, 49 HistoryDetails* details); 50 virtual void DBLoaded(); 51 virtual void StartTopSitesMigration(); 52 53 private: 54 // Not owned by us. 55 HistoryBackendTest* test_; 56 57 DISALLOW_COPY_AND_ASSIGN(HistoryBackendTestDelegate); 58}; 59 60class HistoryBackendTest : public testing::Test { 61 public: 62 HistoryBackendTest() : bookmark_model_(NULL), loaded_(false) {} 63 virtual ~HistoryBackendTest() { 64 } 65 66 protected: 67 scoped_refptr<HistoryBackend> backend_; // Will be NULL on init failure. 68 scoped_ptr<InMemoryHistoryBackend> mem_backend_; 69 70 void AddRedirectChain(const char* sequence[], int page_id) { 71 history::RedirectList redirects; 72 for (int i = 0; sequence[i] != NULL; ++i) 73 redirects.push_back(GURL(sequence[i])); 74 75 int int_scope = 1; 76 void* scope = 0; 77 memcpy(&scope, &int_scope, sizeof(int_scope)); 78 scoped_refptr<history::HistoryAddPageArgs> request( 79 new history::HistoryAddPageArgs( 80 redirects.back(), Time::Now(), scope, page_id, GURL(), 81 redirects, PageTransition::LINK, history::SOURCE_BROWSED, true)); 82 backend_->AddPage(request); 83 } 84 85 // Adds CLIENT_REDIRECT page transition. 86 // |url1| is the source URL and |url2| is the destination. 87 // |did_replace| is true if the transition is non-user initiated and the 88 // navigation entry for |url2| has replaced that for |url1|. The possibly 89 // updated transition code of the visit records for |url1| and |url2| is 90 // returned by filling in |*transition1| and |*transition2|, respectively. 91 void AddClientRedirect(const GURL& url1, const GURL& url2, bool did_replace, 92 int* transition1, int* transition2) { 93 void* const dummy_scope = reinterpret_cast<void*>(0x87654321); 94 history::RedirectList redirects; 95 if (url1.is_valid()) 96 redirects.push_back(url1); 97 if (url2.is_valid()) 98 redirects.push_back(url2); 99 scoped_refptr<HistoryAddPageArgs> request( 100 new HistoryAddPageArgs(url2, base::Time(), dummy_scope, 0, url1, 101 redirects, PageTransition::CLIENT_REDIRECT, 102 history::SOURCE_BROWSED, did_replace)); 103 backend_->AddPage(request); 104 105 *transition1 = getTransition(url1); 106 *transition2 = getTransition(url2); 107 } 108 109 int getTransition(const GURL& url) { 110 if (!url.is_valid()) 111 return 0; 112 URLRow row; 113 URLID id = backend_->db()->GetRowForURL(url, &row); 114 VisitVector visits; 115 EXPECT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 116 return visits[0].transition; 117 } 118 119 FilePath getTestDir() { 120 return test_dir_; 121 } 122 123 BookmarkModel bookmark_model_; 124 125 protected: 126 bool loaded_; 127 128 private: 129 friend class HistoryBackendTestDelegate; 130 131 // testing::Test 132 virtual void SetUp() { 133 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("BackendTest"), 134 &test_dir_)) 135 return; 136 backend_ = new HistoryBackend(test_dir_, 137 new HistoryBackendTestDelegate(this), 138 &bookmark_model_); 139 backend_->Init(std::string(), false); 140 } 141 virtual void TearDown() { 142 if (backend_.get()) 143 backend_->Closing(); 144 backend_ = NULL; 145 mem_backend_.reset(); 146 file_util::Delete(test_dir_, true); 147 } 148 149 void SetInMemoryBackend(InMemoryHistoryBackend* backend) { 150 mem_backend_.reset(backend); 151 } 152 153 void BroadcastNotifications(NotificationType type, 154 HistoryDetails* details) { 155 // Send the notifications directly to the in-memory database. 156 Details<HistoryDetails> det(details); 157 mem_backend_->Observe(type, Source<HistoryBackendTest>(NULL), det); 158 159 // The backend passes ownership of the details pointer to us. 160 delete details; 161 } 162 163 MessageLoop message_loop_; 164 FilePath test_dir_; 165}; 166 167void HistoryBackendTestDelegate::SetInMemoryBackend( 168 InMemoryHistoryBackend* backend) { 169 test_->SetInMemoryBackend(backend); 170} 171 172void HistoryBackendTestDelegate::BroadcastNotifications( 173 NotificationType type, 174 HistoryDetails* details) { 175 test_->BroadcastNotifications(type, details); 176} 177 178void HistoryBackendTestDelegate::DBLoaded() { 179 test_->loaded_ = true; 180} 181 182void HistoryBackendTestDelegate::StartTopSitesMigration() { 183 test_->backend_->MigrateThumbnailsDatabase(); 184} 185 186TEST_F(HistoryBackendTest, Loaded) { 187 ASSERT_TRUE(backend_.get()); 188 ASSERT_TRUE(loaded_); 189} 190 191TEST_F(HistoryBackendTest, DeleteAll) { 192 ASSERT_TRUE(backend_.get()); 193 194 // Add two favicons, use the characters '1' and '2' for the image data. Note 195 // that we do these in the opposite order. This is so the first one gets ID 196 // 2 autoassigned to the database, which will change when the other one is 197 // deleted. This way we can test that updating works properly. 198 GURL favicon_url1("http://www.google.com/favicon.ico"); 199 GURL favicon_url2("http://news.google.com/favicon.ico"); 200 FavIconID favicon2 = backend_->thumbnail_db_->AddFavIcon(favicon_url2); 201 FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1); 202 203 std::vector<unsigned char> data; 204 data.push_back('1'); 205 EXPECT_TRUE(backend_->thumbnail_db_->SetFavIcon(favicon1, 206 new RefCountedBytes(data), Time::Now())); 207 208 data[0] = '2'; 209 EXPECT_TRUE(backend_->thumbnail_db_->SetFavIcon( 210 favicon2, new RefCountedBytes(data), Time::Now())); 211 212 // First visit two URLs. 213 URLRow row1(GURL("http://www.google.com/")); 214 row1.set_visit_count(2); 215 row1.set_typed_count(1); 216 row1.set_last_visit(Time::Now()); 217 row1.set_favicon_id(favicon1); 218 219 URLRow row2(GURL("http://news.google.com/")); 220 row2.set_visit_count(1); 221 row2.set_last_visit(Time::Now()); 222 row2.set_favicon_id(favicon2); 223 224 std::vector<URLRow> rows; 225 rows.push_back(row2); // Reversed order for the same reason as favicons. 226 rows.push_back(row1); 227 backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED); 228 229 URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL); 230 URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL); 231 232 // Get the two visits for the URLs we just added. 233 VisitVector visits; 234 backend_->db_->GetVisitsForURL(row1_id, &visits); 235 ASSERT_EQ(1U, visits.size()); 236 VisitID visit1_id = visits[0].visit_id; 237 238 visits.clear(); 239 backend_->db_->GetVisitsForURL(row2_id, &visits); 240 ASSERT_EQ(1U, visits.size()); 241 VisitID visit2_id = visits[0].visit_id; 242 243 // The in-memory backend should have been set and it should have gotten the 244 // typed URL. 245 ASSERT_TRUE(mem_backend_.get()); 246 URLRow outrow1; 247 EXPECT_TRUE(mem_backend_->db_->GetRowForURL(row1.url(), NULL)); 248 249 // Add thumbnails for each page. 250 ThumbnailScore score(0.25, true, true); 251 scoped_ptr<SkBitmap> google_bitmap( 252 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); 253 254 Time time; 255 GURL gurl; 256 backend_->thumbnail_db_->SetPageThumbnail(gurl, row1_id, *google_bitmap, 257 score, time); 258 scoped_ptr<SkBitmap> weewar_bitmap( 259 gfx::JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail))); 260 backend_->thumbnail_db_->SetPageThumbnail(gurl, row2_id, *weewar_bitmap, 261 score, time); 262 263 // Star row1. 264 bookmark_model_.AddURL( 265 bookmark_model_.GetBookmarkBarNode(), 0, string16(), row1.url()); 266 267 // Set full text index for each one. 268 backend_->text_database_->AddPageData(row1.url(), row1_id, visit1_id, 269 row1.last_visit(), 270 UTF8ToUTF16("Title 1"), 271 UTF8ToUTF16("Body 1")); 272 backend_->text_database_->AddPageData(row2.url(), row2_id, visit2_id, 273 row2.last_visit(), 274 UTF8ToUTF16("Title 2"), 275 UTF8ToUTF16("Body 2")); 276 277 // Now finally clear all history. 278 backend_->DeleteAllHistory(); 279 280 // The first URL should be preserved but the time should be cleared. 281 EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1)); 282 EXPECT_EQ(0, outrow1.visit_count()); 283 EXPECT_EQ(0, outrow1.typed_count()); 284 EXPECT_TRUE(Time() == outrow1.last_visit()); 285 286 // The second row should be deleted. 287 URLRow outrow2; 288 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &outrow2)); 289 290 // All visits should be deleted for both URLs. 291 VisitVector all_visits; 292 backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits); 293 ASSERT_EQ(0U, all_visits.size()); 294 295 // All thumbnails should be deleted. 296 std::vector<unsigned char> out_data; 297 EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(outrow1.id(), 298 &out_data)); 299 EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(row2_id, &out_data)); 300 301 // We should have a favicon for the first URL only. We look them up by favicon 302 // URL since the IDs may hav changed. 303 FavIconID out_favicon1 = backend_->thumbnail_db_-> 304 GetFavIconIDForFavIconURL(favicon_url1); 305 EXPECT_TRUE(out_favicon1); 306 FavIconID out_favicon2 = backend_->thumbnail_db_-> 307 GetFavIconIDForFavIconURL(favicon_url2); 308 EXPECT_FALSE(out_favicon2) << "Favicon not deleted"; 309 310 // The remaining URL should still reference the same favicon, even if its 311 // ID has changed. 312 EXPECT_EQ(out_favicon1, outrow1.favicon_id()); 313 314 // The first URL should still be bookmarked. 315 EXPECT_TRUE(bookmark_model_.IsBookmarked(row1.url())); 316 317 // The full text database should have no data. 318 std::vector<TextDatabase::Match> text_matches; 319 Time first_time_searched; 320 backend_->text_database_->GetTextMatches(UTF8ToUTF16("Body"), 321 QueryOptions(), 322 &text_matches, 323 &first_time_searched); 324 EXPECT_EQ(0U, text_matches.size()); 325} 326 327TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) { 328 GURL favicon_url1("http://www.google.com/favicon.ico"); 329 GURL favicon_url2("http://news.google.com/favicon.ico"); 330 FavIconID favicon2 = backend_->thumbnail_db_->AddFavIcon(favicon_url2); 331 FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1); 332 333 std::vector<unsigned char> data; 334 data.push_back('1'); 335 EXPECT_TRUE(backend_->thumbnail_db_->SetFavIcon( 336 favicon1, new RefCountedBytes(data), Time::Now())); 337 338 data[0] = '2'; 339 EXPECT_TRUE(backend_->thumbnail_db_->SetFavIcon( 340 favicon2, new RefCountedBytes(data), Time::Now())); 341 342 // First visit two URLs. 343 URLRow row1(GURL("http://www.google.com/")); 344 row1.set_visit_count(2); 345 row1.set_typed_count(1); 346 row1.set_last_visit(Time::Now()); 347 row1.set_favicon_id(favicon1); 348 349 URLRow row2(GURL("http://news.google.com/")); 350 row2.set_visit_count(1); 351 row2.set_last_visit(Time::Now()); 352 row2.set_favicon_id(favicon2); 353 354 std::vector<URLRow> rows; 355 rows.push_back(row2); // Reversed order for the same reason as favicons. 356 rows.push_back(row1); 357 backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED); 358 359 URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL); 360 URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL); 361 362 // Star the two URLs. 363 bookmark_model_.SetURLStarred(row1.url(), string16(), true); 364 bookmark_model_.SetURLStarred(row2.url(), string16(), true); 365 366 // Delete url 2. Because url 2 is starred this won't delete the URL, only 367 // the visits. 368 backend_->expirer_.DeleteURL(row2.url()); 369 370 // Make sure url 2 is still valid, but has no visits. 371 URLRow tmp_url_row; 372 EXPECT_EQ(row2_id, backend_->db_->GetRowForURL(row2.url(), NULL)); 373 VisitVector visits; 374 backend_->db_->GetVisitsForURL(row2_id, &visits); 375 EXPECT_EQ(0U, visits.size()); 376 // The favicon should still be valid. 377 EXPECT_EQ(favicon2, 378 backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2)); 379 380 // Unstar row2. 381 bookmark_model_.SetURLStarred(row2.url(), string16(), false); 382 // Tell the backend it was unstarred. We have to explicitly do this as 383 // BookmarkModel isn't wired up to the backend during testing. 384 std::set<GURL> unstarred_urls; 385 unstarred_urls.insert(row2.url()); 386 backend_->URLsNoLongerBookmarked(unstarred_urls); 387 388 // The URL should no longer exist. 389 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row)); 390 // And the favicon should be deleted. 391 EXPECT_EQ(0, 392 backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2)); 393 394 // Unstar row 1. 395 bookmark_model_.SetURLStarred(row1.url(), string16(), false); 396 // Tell the backend it was unstarred. We have to explicitly do this as 397 // BookmarkModel isn't wired up to the backend during testing. 398 unstarred_urls.clear(); 399 unstarred_urls.insert(row1.url()); 400 backend_->URLsNoLongerBookmarked(unstarred_urls); 401 402 // The URL should still exist (because there were visits). 403 EXPECT_EQ(row1_id, backend_->db_->GetRowForURL(row1.url(), NULL)); 404 405 // There should still be visits. 406 visits.clear(); 407 backend_->db_->GetVisitsForURL(row1_id, &visits); 408 EXPECT_EQ(1U, visits.size()); 409 410 // The favicon should still be valid. 411 EXPECT_EQ(favicon1, 412 backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url1)); 413} 414 415TEST_F(HistoryBackendTest, GetPageThumbnailAfterRedirects) { 416 ASSERT_TRUE(backend_.get()); 417 if (history::TopSites::IsEnabled()) 418 return; 419 420 const char* base_url = "http://mail"; 421 const char* thumbnail_url = "http://mail.google.com"; 422 const char* first_chain[] = { 423 base_url, 424 thumbnail_url, 425 NULL 426 }; 427 AddRedirectChain(first_chain, 0); 428 429 // Add a thumbnail for the end of that redirect chain. 430 scoped_ptr<SkBitmap> thumbnail( 431 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); 432 backend_->SetPageThumbnail(GURL(thumbnail_url), *thumbnail, 433 ThumbnailScore(0.25, true, true)); 434 435 // Write a second URL chain so that if you were to simply check what 436 // "http://mail" redirects to, you wouldn't see the URL that has 437 // contains the thumbnail. 438 const char* second_chain[] = { 439 base_url, 440 "http://mail.google.com/somewhere/else", 441 NULL 442 }; 443 AddRedirectChain(second_chain, 1); 444 445 // Now try to get the thumbnail for the base url. It shouldn't be 446 // distracted by the second chain and should return the thumbnail 447 // attached to thumbnail_url_. 448 scoped_refptr<RefCountedBytes> data; 449 backend_->GetPageThumbnailDirectly(GURL(base_url), &data); 450 451 EXPECT_TRUE(data.get()); 452} 453 454// Tests a handful of assertions for a navigation with a type of 455// KEYWORD_GENERATED. 456TEST_F(HistoryBackendTest, KeywordGenerated) { 457 ASSERT_TRUE(backend_.get()); 458 459 GURL url("http://google.com"); 460 461 Time visit_time = Time::Now() - base::TimeDelta::FromDays(1); 462 scoped_refptr<HistoryAddPageArgs> request( 463 new HistoryAddPageArgs(url, visit_time, NULL, 0, GURL(), 464 history::RedirectList(), 465 PageTransition::KEYWORD_GENERATED, 466 history::SOURCE_BROWSED, false)); 467 backend_->AddPage(request); 468 469 // A row should have been added for the url. 470 URLRow row; 471 URLID url_id = backend_->db()->GetRowForURL(url, &row); 472 ASSERT_NE(0, url_id); 473 474 // The typed count should be 1. 475 ASSERT_EQ(1, row.typed_count()); 476 477 // KEYWORD_GENERATED urls should not be added to the segment db. 478 std::string segment_name = VisitSegmentDatabase::ComputeSegmentName(url); 479 EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment_name)); 480 481 // One visit should be added. 482 VisitVector visits; 483 EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits)); 484 EXPECT_EQ(1U, visits.size()); 485 486 // But no visible visits. 487 visits.clear(); 488 backend_->db()->GetVisibleVisitsInRange(base::Time(), base::Time(), 1, 489 &visits); 490 EXPECT_TRUE(visits.empty()); 491 492 // Expire the visits. 493 std::set<GURL> restrict_urls; 494 backend_->expire_backend()->ExpireHistoryBetween(restrict_urls, 495 visit_time, Time::Now()); 496 497 // The visit should have been nuked. 498 visits.clear(); 499 EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits)); 500 EXPECT_TRUE(visits.empty()); 501 502 // As well as the url. 503 ASSERT_EQ(0, backend_->db()->GetRowForURL(url, &row)); 504} 505 506TEST_F(HistoryBackendTest, ClientRedirect) { 507 ASSERT_TRUE(backend_.get()); 508 509 int transition1; 510 int transition2; 511 512 // Initial transition to page A. 513 GURL url_a("http://google.com/a"); 514 AddClientRedirect(GURL(), url_a, false, &transition1, &transition2); 515 EXPECT_TRUE(transition2 & PageTransition::CHAIN_END); 516 517 // User initiated redirect to page B. 518 GURL url_b("http://google.com/b"); 519 AddClientRedirect(url_a, url_b, false, &transition1, &transition2); 520 EXPECT_TRUE(transition1 & PageTransition::CHAIN_END); 521 EXPECT_TRUE(transition2 & PageTransition::CHAIN_END); 522 523 // Non-user initiated redirect to page C. 524 GURL url_c("http://google.com/c"); 525 AddClientRedirect(url_b, url_c, true, &transition1, &transition2); 526 EXPECT_FALSE(transition1 & PageTransition::CHAIN_END); 527 EXPECT_TRUE(transition2 & PageTransition::CHAIN_END); 528} 529 530TEST_F(HistoryBackendTest, ImportedFaviconsTest) { 531 // Setup test data - two Urls in the history, one with favicon assigned and 532 // one without. 533 GURL favicon_url1("http://www.google.com/favicon.ico"); 534 FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1); 535 std::vector<unsigned char> data; 536 data.push_back('1'); 537 EXPECT_TRUE(backend_->thumbnail_db_->SetFavIcon(favicon1, 538 RefCountedBytes::TakeVector(&data), Time::Now())); 539 URLRow row1(GURL("http://www.google.com/")); 540 row1.set_favicon_id(favicon1); 541 row1.set_visit_count(1); 542 row1.set_last_visit(Time::Now()); 543 URLRow row2(GURL("http://news.google.com/")); 544 row2.set_visit_count(1); 545 row2.set_last_visit(Time::Now()); 546 std::vector<URLRow> rows; 547 rows.push_back(row1); 548 rows.push_back(row2); 549 backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED); 550 URLRow url_row1, url_row2; 551 EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0); 552 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0); 553 EXPECT_FALSE(url_row1.favicon_id() == 0); 554 EXPECT_TRUE(url_row2.favicon_id() == 0); 555 556 // Now provide one imported favicon for both URLs already in the registry. 557 // The new favicon should only be used with the URL that doesn't already have 558 // a favicon. 559 std::vector<history::ImportedFavIconUsage> favicons; 560 history::ImportedFavIconUsage favicon; 561 favicon.favicon_url = GURL("http://news.google.com/favicon.ico"); 562 favicon.png_data.push_back('2'); 563 favicon.urls.insert(row1.url()); 564 favicon.urls.insert(row2.url()); 565 favicons.push_back(favicon); 566 backend_->SetImportedFavicons(favicons); 567 EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0); 568 EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0); 569 EXPECT_FALSE(url_row1.favicon_id() == 0); 570 EXPECT_FALSE(url_row2.favicon_id() == 0); 571 EXPECT_FALSE(url_row1.favicon_id() == url_row2.favicon_id()); 572 573 // A URL should not be added to history (to store favicon), if 574 // the URL is not bookmarked. 575 GURL url3("http://mail.google.com"); 576 favicons.clear(); 577 favicon.favicon_url = GURL("http://mail.google.com/favicon.ico"); 578 favicon.png_data.push_back('3'); 579 favicon.urls.insert(url3); 580 favicons.push_back(favicon); 581 backend_->SetImportedFavicons(favicons); 582 URLRow url_row3; 583 EXPECT_TRUE(backend_->db_->GetRowForURL(url3, &url_row3) == 0); 584 585 // If the URL is bookmarked, it should get added to history with 0 visits. 586 bookmark_model_.AddURL(bookmark_model_.GetBookmarkBarNode(), 0, string16(), 587 url3); 588 backend_->SetImportedFavicons(favicons); 589 EXPECT_FALSE(backend_->db_->GetRowForURL(url3, &url_row3) == 0); 590 EXPECT_TRUE(url_row3.visit_count() == 0); 591} 592 593TEST_F(HistoryBackendTest, StripUsernamePasswordTest) { 594 ASSERT_TRUE(backend_.get()); 595 596 GURL url("http://anyuser:anypass@www.google.com"); 597 GURL stripped_url("http://www.google.com"); 598 599 // Clear all history. 600 backend_->DeleteAllHistory(); 601 602 // Visit the url with username, password. 603 backend_->AddPageVisit(url, base::Time::Now(), 0, 604 PageTransition::GetQualifier(PageTransition::TYPED), 605 history::SOURCE_BROWSED); 606 607 // Fetch the row information about stripped url from history db. 608 VisitVector visits; 609 URLID row_id = backend_->db_->GetRowForURL(stripped_url, NULL); 610 backend_->db_->GetVisitsForURL(row_id, &visits); 611 612 // Check if stripped url is stored in database. 613 ASSERT_EQ(1U, visits.size()); 614} 615 616TEST_F(HistoryBackendTest, DeleteThumbnailsDatabaseTest) { 617 if (history::TopSites::IsEnabled()) 618 return; 619 620 EXPECT_TRUE(backend_->thumbnail_db_->NeedsMigrationToTopSites()); 621 backend_->delegate_->StartTopSitesMigration(); 622 EXPECT_FALSE(backend_->thumbnail_db_->NeedsMigrationToTopSites()); 623} 624 625TEST_F(HistoryBackendTest, AddPageVisitSource) { 626 ASSERT_TRUE(backend_.get()); 627 628 GURL url("http://www.google.com"); 629 630 // Clear all history. 631 backend_->DeleteAllHistory(); 632 633 // Assume visiting the url from an externsion. 634 backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED, 635 history::SOURCE_EXTENSION); 636 // Assume the url is imported from Firefox. 637 backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED, 638 history::SOURCE_FIREFOX_IMPORTED); 639 // Assume this url is also synced. 640 backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED, 641 history::SOURCE_SYNCED); 642 643 // Fetch the row information about the url from history db. 644 VisitVector visits; 645 URLID row_id = backend_->db_->GetRowForURL(url, NULL); 646 backend_->db_->GetVisitsForURL(row_id, &visits); 647 648 // Check if all the visits to the url are stored in database. 649 ASSERT_EQ(3U, visits.size()); 650 VisitSourceMap visit_sources; 651 backend_->db_->GetVisitsSource(visits, &visit_sources); 652 ASSERT_EQ(3U, visit_sources.size()); 653 int sources = 0; 654 for (int i = 0; i < 3; i++) { 655 switch (visit_sources[visits[i].visit_id]) { 656 case history::SOURCE_EXTENSION: 657 sources |= 0x1; 658 break; 659 case history::SOURCE_FIREFOX_IMPORTED: 660 sources |= 0x2; 661 break; 662 case history::SOURCE_SYNCED: 663 sources |= 0x4; 664 default: 665 break; 666 } 667 } 668 EXPECT_EQ(0x7, sources); 669} 670 671TEST_F(HistoryBackendTest, AddPageArgsSource) { 672 ASSERT_TRUE(backend_.get()); 673 674 GURL url("http://testpageargs.com"); 675 676 // Assume this page is browsed by user. 677 scoped_refptr<HistoryAddPageArgs> request1( 678 new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(), 679 history::RedirectList(), 680 PageTransition::KEYWORD_GENERATED, 681 history::SOURCE_BROWSED, false)); 682 backend_->AddPage(request1); 683 // Assume this page is synced. 684 scoped_refptr<HistoryAddPageArgs> request2( 685 new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(), 686 history::RedirectList(), 687 PageTransition::LINK, 688 history::SOURCE_SYNCED, false)); 689 backend_->AddPage(request2); 690 // Assume this page is browsed again. 691 scoped_refptr<HistoryAddPageArgs> request3( 692 new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(), 693 history::RedirectList(), 694 PageTransition::TYPED, 695 history::SOURCE_BROWSED, false)); 696 backend_->AddPage(request3); 697 698 // Three visits should be added with proper sources. 699 VisitVector visits; 700 URLRow row; 701 URLID id = backend_->db()->GetRowForURL(url, &row); 702 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 703 ASSERT_EQ(3U, visits.size()); 704 VisitSourceMap visit_sources; 705 backend_->db_->GetVisitsSource(visits, &visit_sources); 706 ASSERT_EQ(1U, visit_sources.size()); 707 EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second); 708} 709 710TEST_F(HistoryBackendTest, AddVisitsSource) { 711 ASSERT_TRUE(backend_.get()); 712 713 GURL url1("http://www.cnn.com"); 714 std::vector<base::Time> visits1; 715 visits1.push_back(Time::Now() - base::TimeDelta::FromDays(5)); 716 visits1.push_back(Time::Now() - base::TimeDelta::FromDays(1)); 717 visits1.push_back(Time::Now()); 718 719 GURL url2("http://www.example.com"); 720 std::vector<base::Time> visits2; 721 visits2.push_back(Time::Now() - base::TimeDelta::FromDays(10)); 722 visits2.push_back(Time::Now()); 723 724 // Clear all history. 725 backend_->DeleteAllHistory(); 726 727 // Add the visits. 728 backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED); 729 backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED); 730 731 // Verify the visits were added with their sources. 732 VisitVector visits; 733 URLRow row; 734 URLID id = backend_->db()->GetRowForURL(url1, &row); 735 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 736 ASSERT_EQ(3U, visits.size()); 737 VisitSourceMap visit_sources; 738 backend_->db_->GetVisitsSource(visits, &visit_sources); 739 ASSERT_EQ(3U, visit_sources.size()); 740 for (int i = 0; i < 3; i++) 741 EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]); 742 id = backend_->db()->GetRowForURL(url2, &row); 743 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 744 ASSERT_EQ(2U, visits.size()); 745 backend_->db_->GetVisitsSource(visits, &visit_sources); 746 ASSERT_EQ(2U, visit_sources.size()); 747 for (int i = 0; i < 2; i++) 748 EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]); 749} 750 751TEST_F(HistoryBackendTest, RemoveVisitsSource) { 752 ASSERT_TRUE(backend_.get()); 753 754 GURL url1("http://www.cnn.com"); 755 std::vector<base::Time> visits1; 756 visits1.push_back(Time::Now() - base::TimeDelta::FromDays(5)); 757 visits1.push_back(Time::Now()); 758 759 GURL url2("http://www.example.com"); 760 std::vector<base::Time> visits2; 761 visits2.push_back(Time::Now() - base::TimeDelta::FromDays(10)); 762 visits2.push_back(Time::Now()); 763 764 // Clear all history. 765 backend_->DeleteAllHistory(); 766 767 // Add the visits. 768 backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED); 769 backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED); 770 771 // Verify the visits of url1 were added. 772 VisitVector visits; 773 URLRow row; 774 URLID id = backend_->db()->GetRowForURL(url1, &row); 775 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 776 ASSERT_EQ(2U, visits.size()); 777 // Remove these visits. 778 ASSERT_TRUE(backend_->RemoveVisits(visits)); 779 780 // Now check only url2's source in visit_source table. 781 VisitSourceMap visit_sources; 782 backend_->db_->GetVisitsSource(visits, &visit_sources); 783 ASSERT_EQ(0U, visit_sources.size()); 784 id = backend_->db()->GetRowForURL(url2, &row); 785 ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits)); 786 ASSERT_EQ(2U, visits.size()); 787 backend_->db_->GetVisitsSource(visits, &visit_sources); 788 ASSERT_EQ(2U, visit_sources.size()); 789 for (int i = 0; i < 2; i++) 790 EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]); 791} 792 793// Test for migration of adding visit_source table. 794TEST_F(HistoryBackendTest, MigrationVisitSource) { 795 ASSERT_TRUE(backend_.get()); 796 backend_->Closing(); 797 backend_ = NULL; 798 799 FilePath old_history_path; 800 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path)); 801 old_history_path = old_history_path.AppendASCII("History"); 802 old_history_path = old_history_path.AppendASCII("HistoryNoSource"); 803 804 // Copy history database file to current directory so that it will be deleted 805 // in Teardown. 806 FilePath new_history_path(getTestDir()); 807 file_util::Delete(new_history_path, true); 808 file_util::CreateDirectory(new_history_path); 809 FilePath new_history_file = new_history_path.Append(chrome::kHistoryFilename); 810 ASSERT_TRUE(file_util::CopyFile(old_history_path, new_history_file)); 811 812 backend_ = new HistoryBackend(new_history_path, 813 new HistoryBackendTestDelegate(this), 814 &bookmark_model_); 815 backend_->Init(std::string(), false); 816 backend_->Closing(); 817 backend_ = NULL; 818 819 // Now the database should already be migrated. 820 // Check version first. 821 int cur_version = HistoryDatabase::GetCurrentVersion(); 822 sql::Connection db; 823 ASSERT_TRUE(db.Open(new_history_file)); 824 sql::Statement s(db.GetUniqueStatement( 825 "SELECT value FROM meta WHERE key = 'version'")); 826 ASSERT_TRUE(s.Step()); 827 int file_version = s.ColumnInt(0); 828 EXPECT_EQ(cur_version, file_version); 829 830 // Check visit_source table is created and empty. 831 s.Assign(db.GetUniqueStatement( 832 "SELECT name FROM sqlite_master WHERE name=\"visit_source\"")); 833 ASSERT_TRUE(s.Step()); 834 s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10")); 835 EXPECT_FALSE(s.Step()); 836} 837 838} // namespace history 839