1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/history/android/android_provider_backend.h" 6 7 #include <vector> 8 9 #include "base/file_util.h" 10 #include "base/files/file_path.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "chrome/browser/bookmarks/bookmark_model.h" 16 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 17 #include "chrome/browser/bookmarks/bookmark_service.h" 18 #include "chrome/browser/bookmarks/bookmark_test_helpers.h" 19 #include "chrome/browser/chrome_notification_types.h" 20 #include "chrome/browser/favicon/favicon_changed_details.h" 21 #include "chrome/browser/history/android/android_time.h" 22 #include "chrome/browser/history/history_backend.h" 23 #include "chrome/browser/profiles/profile_manager.h" 24 #include "chrome/common/chrome_constants.h" 25 #include "chrome/test/base/testing_browser_process.h" 26 #include "chrome/test/base/testing_profile.h" 27 #include "chrome/test/base/testing_profile_manager.h" 28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/test/test_browser_thread.h" 30 #include "content/public/test/test_utils.h" 31 #include "testing/gtest/include/gtest/gtest.h" 32 33 using base::Time; 34 using base::TimeDelta; 35 using content::BrowserThread; 36 37 namespace history { 38 39 namespace { 40 41 struct BookmarkCacheRow { 42 public: 43 BookmarkCacheRow() 44 : url_id_(0), 45 bookmark_(false), 46 favicon_id_(0) { 47 } 48 URLID url_id_; 49 Time create_time_; 50 Time last_visit_time_; 51 bool bookmark_; 52 chrome::FaviconID favicon_id_; 53 }; 54 55 } // namespace 56 57 class AndroidProviderBackendDelegate : public HistoryBackend::Delegate { 58 public: 59 AndroidProviderBackendDelegate() {} 60 61 virtual void NotifyProfileError(int backend_id, 62 sql::InitStatus init_status) OVERRIDE {} 63 virtual void SetInMemoryBackend(int backend_id, 64 InMemoryHistoryBackend* backend) OVERRIDE {} 65 virtual void BroadcastNotifications(int type, 66 HistoryDetails* details) OVERRIDE { 67 switch (type) { 68 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: 69 deleted_details_.reset(static_cast<URLsDeletedDetails*>(details)); 70 break; 71 case chrome::NOTIFICATION_FAVICON_CHANGED: 72 favicon_details_.reset(static_cast<FaviconChangedDetails*>(details)); 73 break; 74 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: 75 modified_details_.reset(static_cast<URLsModifiedDetails*>(details)); 76 break; 77 } 78 } 79 virtual void DBLoaded(int backend_id) OVERRIDE {} 80 virtual void NotifyVisitDBObserversOnAddVisit( 81 const history::BriefVisitInfo& info) OVERRIDE {} 82 83 URLsDeletedDetails* deleted_details() const { 84 return deleted_details_.get(); 85 } 86 87 URLsModifiedDetails* modified_details() const { 88 return modified_details_.get(); 89 } 90 91 FaviconChangedDetails* favicon_details() const { 92 return favicon_details_.get(); 93 } 94 95 void ResetDetails() { 96 deleted_details_.reset(); 97 modified_details_.reset(); 98 favicon_details_.reset(); 99 } 100 101 private: 102 scoped_ptr<URLsDeletedDetails> deleted_details_; 103 scoped_ptr<URLsModifiedDetails> modified_details_; 104 scoped_ptr<FaviconChangedDetails> favicon_details_; 105 106 DISALLOW_COPY_AND_ASSIGN(AndroidProviderBackendDelegate); 107 }; 108 109 class AndroidProviderBackendTest : public testing::Test { 110 public: 111 AndroidProviderBackendTest() 112 : profile_manager_( 113 TestingBrowserProcess::GetGlobal()), 114 bookmark_model_(NULL), 115 ui_thread_(BrowserThread::UI, &message_loop_), 116 file_thread_(BrowserThread::FILE, &message_loop_) { 117 } 118 virtual ~AndroidProviderBackendTest() {} 119 120 protected: 121 virtual void SetUp() OVERRIDE { 122 // Setup the testing profile, so the bookmark_model_sql_handler could 123 // get the bookmark model from it. 124 ASSERT_TRUE(profile_manager_.SetUp()); 125 // It seems that the name has to be chrome::kInitialProfile, so it 126 // could be found by ProfileManager::GetLastUsedProfile(). 127 TestingProfile* testing_profile = profile_manager_.CreateTestingProfile( 128 chrome::kInitialProfile); 129 testing_profile->CreateBookmarkModel(true); 130 bookmark_model_ = BookmarkModelFactory::GetForProfile(testing_profile); 131 test::WaitForBookmarkModelToLoad(bookmark_model_); 132 ASSERT_TRUE(bookmark_model_); 133 134 // Get the BookmarkModel from LastUsedProfile, this is the same way that 135 // how the BookmarkModelSQLHandler gets the BookmarkModel. 136 Profile* profile = ProfileManager::GetLastUsedProfile(); 137 ASSERT_TRUE(profile); 138 139 // Setup the database directory and files. 140 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 141 142 history_db_name_ = temp_dir_.path().AppendASCII(chrome::kHistoryFilename); 143 thumbnail_db_name_ = temp_dir_.path().AppendASCII( 144 chrome::kFaviconsFilename); 145 android_cache_db_name_ = temp_dir_.path().AppendASCII( 146 "TestAndroidCache.db"); 147 } 148 149 void AddBookmark(const GURL& url) { 150 const BookmarkNode* mobile_node = bookmark_model_->mobile_node(); 151 ASSERT_TRUE(mobile_node); 152 ASSERT_TRUE(bookmark_model_->AddURL(mobile_node, 0, base::string16(), url)); 153 } 154 155 bool GetAndroidURLsRows(std::vector<AndroidURLRow>* rows, 156 AndroidProviderBackend* backend) { 157 sql::Statement statement(backend->db_->GetCachedStatement(SQL_FROM_HERE, 158 "SELECT id, raw_url, url_id FROM android_urls ORDER BY url_id ASC")); 159 160 while (statement.Step()) { 161 AndroidURLRow row; 162 row.id = statement.ColumnInt64(0); 163 row.raw_url = statement.ColumnString(1); 164 row.url_id = statement.ColumnInt64(2); 165 rows->push_back(row); 166 } 167 return true; 168 } 169 170 bool GetBookmarkCacheRows(std::vector<BookmarkCacheRow>* rows, 171 AndroidProviderBackend* backend) { 172 sql::Statement statement(backend->db_->GetCachedStatement(SQL_FROM_HERE, 173 "SELECT created_time, last_visit_time, url_id, bookmark, favicon_id " 174 "FROM android_cache_db.bookmark_cache ORDER BY url_id ASC")); 175 176 while (statement.Step()) { 177 BookmarkCacheRow row; 178 row.create_time_ = FromDatabaseTime(statement.ColumnInt64(0)); 179 row.last_visit_time_ = FromDatabaseTime(statement.ColumnInt64(1)); 180 row.url_id_ = statement.ColumnInt64(2); 181 row.bookmark_ = statement.ColumnBool(3); 182 row.favicon_id_ = statement.ColumnInt64(4); 183 rows->push_back(row); 184 } 185 return true; 186 } 187 188 AndroidProviderBackendDelegate delegate_; 189 scoped_refptr<HistoryBackend> history_backend_; 190 HistoryDatabase history_db_; 191 ThumbnailDatabase thumbnail_db_; 192 base::ScopedTempDir temp_dir_; 193 base::FilePath android_cache_db_name_; 194 base::FilePath history_db_name_; 195 base::FilePath thumbnail_db_name_; 196 197 TestingProfileManager profile_manager_; 198 BookmarkModel* bookmark_model_; 199 base::MessageLoopForUI message_loop_; 200 content::TestBrowserThread ui_thread_; 201 content::TestBrowserThread file_thread_; 202 203 204 DISALLOW_COPY_AND_ASSIGN(AndroidProviderBackendTest); 205 }; 206 207 TEST_F(AndroidProviderBackendTest, UpdateTables) { 208 GURL url1("http://www.cnn.com"); 209 URLID url_id1 = 0; 210 std::vector<VisitInfo> visits1; 211 Time last_visited1 = Time::Now() - TimeDelta::FromDays(1); 212 Time created1 = last_visited1 - TimeDelta::FromDays(20); 213 visits1.push_back(VisitInfo(created1, content::PAGE_TRANSITION_LINK)); 214 visits1.push_back(VisitInfo(last_visited1 - TimeDelta::FromDays(1), 215 content::PAGE_TRANSITION_LINK)); 216 visits1.push_back(VisitInfo(last_visited1, content::PAGE_TRANSITION_LINK)); 217 218 GURL url2("http://www.example.com"); 219 URLID url_id2 = 0; 220 std::vector<VisitInfo> visits2; 221 Time last_visited2 = Time::Now(); 222 Time created2 = last_visited2 - TimeDelta::FromDays(10); 223 visits2.push_back(VisitInfo(created2, content::PAGE_TRANSITION_LINK)); 224 visits2.push_back(VisitInfo(last_visited2 - TimeDelta::FromDays(5), 225 content::PAGE_TRANSITION_LINK)); 226 visits2.push_back(VisitInfo(last_visited2, content::PAGE_TRANSITION_LINK)); 227 228 // Add a bookmark which is not in the history. 229 GURL url3("http://www.bookmark.com"); 230 base::string16 title3(UTF8ToUTF16("bookmark")); 231 ASSERT_TRUE(bookmark_model_->AddURL(bookmark_model_->bookmark_bar_node(), 0, 232 title3, url3)); 233 // Only use the HistoryBackend to generate the test data. 234 // HistoryBackend will shutdown after that. 235 { 236 scoped_refptr<HistoryBackend> history_backend; 237 history_backend = new HistoryBackend(temp_dir_.path(), 0, 238 new AndroidProviderBackendDelegate(), bookmark_model_); 239 history_backend->Init(std::string(), false); 240 history_backend->AddVisits(url1, visits1, history::SOURCE_SYNCED); 241 history_backend->AddVisits(url2, visits2, history::SOURCE_SYNCED); 242 URLRow url_row; 243 244 ASSERT_TRUE(history_backend->GetURL(url1, &url_row)); 245 url_id1 = url_row.id(); 246 ASSERT_TRUE(history_backend->GetURL(url2, &url_row)); 247 url_id2 = url_row.id(); 248 249 // Set favicon to url2. 250 std::vector<unsigned char> data; 251 data.push_back('1'); 252 chrome::FaviconBitmapData bitmap_data_element; 253 bitmap_data_element.bitmap_data = new base::RefCountedBytes(data); 254 bitmap_data_element.pixel_size = gfx::Size(); 255 bitmap_data_element.icon_url = GURL(); 256 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 257 favicon_bitmap_data.push_back(bitmap_data_element); 258 259 history_backend->SetFavicons(url2, chrome::FAVICON, favicon_bitmap_data); 260 history_backend->Closing(); 261 } 262 263 // The history_db_name and thumbnail_db_name files should be created by 264 // HistoryBackend. We need to open the same database files. 265 ASSERT_TRUE(base::PathExists(history_db_name_)); 266 ASSERT_TRUE(base::PathExists(thumbnail_db_name_)); 267 268 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 269 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 270 // Set url1 as bookmark. 271 AddBookmark(url1); 272 scoped_ptr<AndroidProviderBackend> backend( 273 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 274 &thumbnail_db_, bookmark_model_, &delegate_)); 275 276 ASSERT_TRUE(backend->EnsureInitializedAndUpdated()); 277 278 // First verify that the bookmark which was not in the history has been added 279 // to history database. 280 URLRow url_row; 281 ASSERT_TRUE(history_db_.GetRowForURL(url3, &url_row)); 282 URLID url_id3 = url_row.id(); 283 ASSERT_EQ(url3, url_row.url()); 284 ASSERT_EQ(title3, url_row.title()); 285 286 std::vector<AndroidURLRow> android_url_rows; 287 ASSERT_TRUE(GetAndroidURLsRows(&android_url_rows, backend.get())); 288 ASSERT_EQ(3u, android_url_rows.size()); 289 std::vector<AndroidURLRow>::iterator i = android_url_rows.begin(); 290 EXPECT_EQ(url_id1, i->url_id); 291 EXPECT_EQ(url1.spec(), i->raw_url); 292 i++; 293 EXPECT_EQ(url_id2, i->url_id); 294 EXPECT_EQ(url2.spec(), i->raw_url); 295 i++; 296 EXPECT_EQ(url_id3, i->url_id); 297 EXPECT_EQ(url3.spec(), i->raw_url); 298 299 std::vector<BookmarkCacheRow> bookmark_cache_rows; 300 ASSERT_TRUE(GetBookmarkCacheRows(&bookmark_cache_rows, backend.get())); 301 ASSERT_EQ(3u, bookmark_cache_rows.size()); 302 std::vector<BookmarkCacheRow>::const_iterator j = bookmark_cache_rows.begin(); 303 EXPECT_EQ(url_id1, j->url_id_); 304 EXPECT_EQ(ToDatabaseTime(last_visited1), ToDatabaseTime(j->last_visit_time_)); 305 EXPECT_EQ(ToDatabaseTime(created1), ToDatabaseTime(j->create_time_)); 306 EXPECT_EQ(0, j->favicon_id_); 307 EXPECT_TRUE(j->bookmark_); 308 j++; 309 EXPECT_EQ(url_id2, j->url_id_); 310 EXPECT_EQ(ToDatabaseTime(last_visited2), ToDatabaseTime(j->last_visit_time_)); 311 EXPECT_EQ(ToDatabaseTime(created2), ToDatabaseTime(j->create_time_)); 312 EXPECT_NE(0, j->favicon_id_); 313 EXPECT_FALSE(j->bookmark_); 314 315 // Delete url2 from database. 316 ASSERT_TRUE(history_db_.DeleteURLRow(url_id2)); 317 VisitVector visit_rows; 318 ASSERT_TRUE(history_db_.GetMostRecentVisitsForURL(url_id2, 10, 319 &visit_rows)); 320 ASSERT_EQ(3u, visit_rows.size()); 321 for (VisitVector::const_iterator v = visit_rows.begin(); 322 v != visit_rows.end(); v++) 323 history_db_.DeleteVisit(*v); 324 325 backend->UpdateTables(); 326 327 android_url_rows.clear(); 328 ASSERT_TRUE(GetAndroidURLsRows(&android_url_rows, backend.get())); 329 ASSERT_EQ(2u, android_url_rows.size()); 330 i = android_url_rows.begin(); 331 EXPECT_EQ(url_id1, i->url_id); 332 EXPECT_EQ(url1.spec(), i->raw_url); 333 ++i; 334 EXPECT_EQ(url_id3, i->url_id); 335 EXPECT_EQ(url3.spec(), i->raw_url); 336 337 bookmark_cache_rows.clear(); 338 ASSERT_TRUE(GetBookmarkCacheRows(&bookmark_cache_rows, backend.get())); 339 ASSERT_EQ(2u, bookmark_cache_rows.size()); 340 j = bookmark_cache_rows.begin(); 341 EXPECT_EQ(url_id1, j->url_id_); 342 EXPECT_EQ(ToDatabaseTime(last_visited1), ToDatabaseTime(j->last_visit_time_)); 343 EXPECT_EQ(ToDatabaseTime(created1), ToDatabaseTime(j->create_time_)); 344 EXPECT_EQ(0, j->favicon_id_); 345 EXPECT_TRUE(j->bookmark_); 346 ++j; 347 EXPECT_EQ(url_id3, j->url_id_); 348 EXPECT_EQ(base::Time::UnixEpoch(), j->last_visit_time_); 349 EXPECT_EQ(base::Time::UnixEpoch(), j->create_time_); 350 EXPECT_EQ(0, j->favicon_id_); 351 EXPECT_TRUE(j->bookmark_); 352 } 353 354 TEST_F(AndroidProviderBackendTest, QueryHistoryAndBookmarks) { 355 GURL url1("http://www.cnn.com"); 356 URLID url_id1 = 0; 357 const base::string16 title1(UTF8ToUTF16("cnn")); 358 std::vector<VisitInfo> visits1; 359 Time last_visited1 = Time::Now() - TimeDelta::FromDays(1); 360 Time created1 = last_visited1 - TimeDelta::FromDays(20); 361 visits1.push_back(VisitInfo(created1, content::PAGE_TRANSITION_LINK)); 362 visits1.push_back(VisitInfo(last_visited1 - TimeDelta::FromDays(1), 363 content::PAGE_TRANSITION_LINK)); 364 visits1.push_back(VisitInfo(last_visited1, content::PAGE_TRANSITION_LINK)); 365 366 GURL url2("http://www.example.com"); 367 URLID url_id2 = 0; 368 std::vector<VisitInfo> visits2; 369 const base::string16 title2(UTF8ToUTF16("example")); 370 Time last_visited2 = Time::Now(); 371 Time created2 = last_visited2 - TimeDelta::FromDays(10); 372 visits2.push_back(VisitInfo(created2, content::PAGE_TRANSITION_LINK)); 373 visits2.push_back(VisitInfo(last_visited2 - TimeDelta::FromDays(5), 374 content::PAGE_TRANSITION_LINK)); 375 visits2.push_back(VisitInfo(last_visited2, content::PAGE_TRANSITION_LINK)); 376 377 // Only use the HistoryBackend to generate the test data. 378 // HistoryBackend will shutdown after that. 379 { 380 scoped_refptr<HistoryBackend> history_backend; 381 history_backend = new HistoryBackend(temp_dir_.path(), 0, 382 new AndroidProviderBackendDelegate(), bookmark_model_); 383 history_backend->Init(std::string(), false); 384 history_backend->AddVisits(url1, visits1, history::SOURCE_SYNCED); 385 history_backend->AddVisits(url2, visits2, history::SOURCE_SYNCED); 386 URLRow url_row; 387 388 ASSERT_TRUE(history_backend->GetURL(url1, &url_row)); 389 url_id1 = url_row.id(); 390 url_row.set_title(title1); 391 ASSERT_TRUE(history_backend->UpdateURL(url_id1, url_row)); 392 393 ASSERT_TRUE(history_backend->GetURL(url2, &url_row)); 394 url_id2 = url_row.id(); 395 url_row.set_title(title2); 396 ASSERT_TRUE(history_backend->UpdateURL(url_id2, url_row)); 397 398 // Set favicon to url2. 399 std::vector<unsigned char> data; 400 data.push_back('1'); 401 chrome::FaviconBitmapData bitmap_data_element; 402 bitmap_data_element.bitmap_data = new base::RefCountedBytes(data); 403 bitmap_data_element.pixel_size = gfx::Size(); 404 bitmap_data_element.icon_url = GURL(); 405 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 406 favicon_bitmap_data.push_back(bitmap_data_element); 407 408 history_backend->SetFavicons(url2, chrome::FAVICON, favicon_bitmap_data); 409 history_backend->Closing(); 410 } 411 412 // The history_db_name and thumbnail_db_name files should be created by 413 // HistoryBackend. We need to open the same database files. 414 ASSERT_TRUE(base::PathExists(history_db_name_)); 415 ASSERT_TRUE(base::PathExists(thumbnail_db_name_)); 416 417 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 418 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 419 // Set url1 as bookmark. 420 AddBookmark(url1); 421 422 scoped_ptr<AndroidProviderBackend> backend( 423 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 424 &thumbnail_db_, bookmark_model_, &delegate_)); 425 426 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 427 428 projections.push_back(HistoryAndBookmarkRow::ID); 429 projections.push_back(HistoryAndBookmarkRow::URL); 430 projections.push_back(HistoryAndBookmarkRow::TITLE); 431 projections.push_back(HistoryAndBookmarkRow::CREATED); 432 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 433 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 434 projections.push_back(HistoryAndBookmarkRow::FAVICON); 435 projections.push_back(HistoryAndBookmarkRow::BOOKMARK); 436 437 scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks( 438 projections, std::string(), std::vector<base::string16>(), 439 std::string("url ASC"))); 440 ASSERT_TRUE(statement->statement()->Step()); 441 ASSERT_EQ(url1, GURL(statement->statement()->ColumnString(1))); 442 EXPECT_EQ(title1, statement->statement()->ColumnString16(2)); 443 EXPECT_EQ(ToDatabaseTime(created1), 444 statement->statement()->ColumnInt64(3)); 445 EXPECT_EQ(ToDatabaseTime(last_visited1), 446 statement->statement()->ColumnInt64(4)); 447 EXPECT_EQ(3, statement->statement()->ColumnInt(5)); 448 EXPECT_EQ(6, statement->favicon_index()); 449 // No favicon. 450 EXPECT_EQ(0, statement->statement()->ColumnByteLength(6)); 451 EXPECT_TRUE(statement->statement()->ColumnBool(7)); 452 453 ASSERT_TRUE(statement->statement()->Step()); 454 EXPECT_EQ(title2, statement->statement()->ColumnString16(2)); 455 ASSERT_EQ(url2, GURL(statement->statement()->ColumnString(1))); 456 EXPECT_EQ(ToDatabaseTime(created2), 457 statement->statement()->ColumnInt64(3)); 458 EXPECT_EQ(ToDatabaseTime(last_visited2), 459 statement->statement()->ColumnInt64(4)); 460 EXPECT_EQ(3, statement->statement()->ColumnInt(5)); 461 std::vector<unsigned char> favicon2; 462 EXPECT_EQ(6, statement->favicon_index()); 463 // Has favicon. 464 EXPECT_NE(0, statement->statement()->ColumnByteLength(6)); 465 EXPECT_FALSE(statement->statement()->ColumnBool(7)); 466 467 // No more row. 468 EXPECT_FALSE(statement->statement()->Step()); 469 470 // Query by bookmark 471 statement.reset(backend->QueryHistoryAndBookmarks(projections, "bookmark=1", 472 std::vector<base::string16>(), std::string("url ASC"))); 473 // Only URL1 is returned. 474 ASSERT_TRUE(statement->statement()->Step()); 475 ASSERT_EQ(url1, GURL(statement->statement()->ColumnString(1))); 476 EXPECT_FALSE(statement->statement()->Step()); 477 478 statement.reset(backend->QueryHistoryAndBookmarks(projections, "bookmark=0", 479 std::vector<base::string16>(), std::string("url ASC"))); 480 // Only URL2 is returned. 481 ASSERT_TRUE(statement->statement()->Step()); 482 ASSERT_EQ(url2, GURL(statement->statement()->ColumnString(1))); 483 EXPECT_FALSE(statement->statement()->Step()); 484 } 485 486 TEST_F(AndroidProviderBackendTest, InsertHistoryAndBookmark) { 487 HistoryAndBookmarkRow row1; 488 row1.set_raw_url("cnn.com"); 489 row1.set_url(GURL("http://cnn.com")); 490 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 491 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 492 row1.set_visit_count(10); 493 row1.set_is_bookmark(true); 494 row1.set_title(UTF8ToUTF16("cnn")); 495 496 HistoryAndBookmarkRow row2; 497 row2.set_raw_url("http://www.example.com"); 498 row2.set_url(GURL("http://www.example.com")); 499 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 500 row2.set_is_bookmark(false); 501 row2.set_title(UTF8ToUTF16("example")); 502 std::vector<unsigned char> data; 503 data.push_back('1'); 504 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 505 506 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 507 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 508 scoped_ptr<AndroidProviderBackend> backend( 509 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 510 &thumbnail_db_, bookmark_model_, &delegate_)); 511 512 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 513 EXPECT_FALSE(delegate_.deleted_details()); 514 ASSERT_TRUE(delegate_.modified_details()); 515 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 516 EXPECT_EQ(row1.url(), delegate_.modified_details()->changed_urls[0].url()); 517 EXPECT_EQ(row1.last_visit_time(), 518 delegate_.modified_details()->changed_urls[0].last_visit()); 519 EXPECT_EQ(row1.visit_count(), 520 delegate_.modified_details()->changed_urls[0].visit_count()); 521 EXPECT_EQ(row1.title(), 522 delegate_.modified_details()->changed_urls[0].title()); 523 EXPECT_FALSE(delegate_.favicon_details()); 524 content::RunAllPendingInMessageLoop(); 525 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 526 const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0); 527 ASSERT_TRUE(child); 528 EXPECT_EQ(row1.title(), child->GetTitle()); 529 EXPECT_EQ(row1.url(), child->url()); 530 531 delegate_.ResetDetails(); 532 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 533 EXPECT_FALSE(delegate_.deleted_details()); 534 ASSERT_TRUE(delegate_.modified_details()); 535 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 536 EXPECT_EQ(row2.url(), delegate_.modified_details()->changed_urls[0].url()); 537 EXPECT_EQ(row2.last_visit_time(), 538 delegate_.modified_details()->changed_urls[0].last_visit()); 539 EXPECT_EQ(row2.title(), 540 delegate_.modified_details()->changed_urls[0].title()); 541 ASSERT_TRUE(delegate_.favicon_details()); 542 ASSERT_EQ(1u, delegate_.favicon_details()->urls.size()); 543 ASSERT_TRUE(delegate_.favicon_details()->urls.end() != 544 delegate_.favicon_details()->urls.find(row2.url())); 545 546 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 547 projections.push_back(HistoryAndBookmarkRow::ID); 548 projections.push_back(HistoryAndBookmarkRow::URL); 549 projections.push_back(HistoryAndBookmarkRow::TITLE); 550 projections.push_back(HistoryAndBookmarkRow::CREATED); 551 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 552 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 553 projections.push_back(HistoryAndBookmarkRow::FAVICON); 554 projections.push_back(HistoryAndBookmarkRow::BOOKMARK); 555 556 scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks( 557 projections, std::string(), std::vector<base::string16>(), 558 std::string("url ASC"))); 559 ASSERT_TRUE(statement->statement()->Step()); 560 ASSERT_EQ(row1.raw_url(), statement->statement()->ColumnString(1)); 561 EXPECT_EQ(row1.title(), statement->statement()->ColumnString16(2)); 562 EXPECT_EQ(ToDatabaseTime(row1.created()), 563 statement->statement()->ColumnInt64(3)); 564 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 565 statement->statement()->ColumnInt64(4)); 566 EXPECT_EQ(row1.visit_count(), statement->statement()->ColumnInt(5)); 567 EXPECT_EQ(6, statement->favicon_index()); 568 // No favicon. 569 EXPECT_EQ(0, statement->statement()->ColumnByteLength(6)); 570 571 // TODO: Find a way to test the bookmark was added in BookmarkModel. 572 // The bookmark was added in UI thread, there is no good way to test it. 573 EXPECT_TRUE(statement->statement()->ColumnBool(7)); 574 575 ASSERT_TRUE(statement->statement()->Step()); 576 EXPECT_EQ(row2.title(), statement->statement()->ColumnString16(2)); 577 EXPECT_EQ(row2.url(), GURL(statement->statement()->ColumnString(1))); 578 EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()), 579 statement->statement()->ColumnInt64(3)); 580 EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()), 581 statement->statement()->ColumnInt64(4)); 582 EXPECT_EQ(1, statement->statement()->ColumnInt(5)); 583 EXPECT_EQ(6, statement->favicon_index()); 584 // Has favicon. 585 EXPECT_NE(0, statement->statement()->ColumnByteLength(6)); 586 // TODO: Find a way to test the bookmark was added in BookmarkModel. 587 // The bookmark was added in UI thread, there is no good way to test it. 588 EXPECT_FALSE(statement->statement()->ColumnBool(7)); 589 590 // No more row. 591 EXPECT_FALSE(statement->statement()->Step()); 592 } 593 594 TEST_F(AndroidProviderBackendTest, DeleteHistoryAndBookmarks) { 595 HistoryAndBookmarkRow row1; 596 row1.set_raw_url("cnn.com"); 597 row1.set_url(GURL("http://cnn.com")); 598 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 599 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 600 row1.set_visit_count(10); 601 row1.set_is_bookmark(true); 602 row1.set_title(UTF8ToUTF16("cnn")); 603 604 HistoryAndBookmarkRow row2; 605 row2.set_raw_url("http://www.example.com"); 606 row2.set_url(GURL("http://www.example.com")); 607 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 608 row2.set_is_bookmark(false); 609 row2.set_title(UTF8ToUTF16("example")); 610 std::vector<unsigned char> data; 611 data.push_back('1'); 612 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 613 614 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 615 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 616 617 scoped_ptr<AndroidProviderBackend> backend( 618 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 619 &thumbnail_db_, bookmark_model_, &delegate_)); 620 621 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 622 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 623 // Verify the row1 has been added in bookmark model. 624 content::RunAllPendingInMessageLoop(); 625 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 626 const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0); 627 ASSERT_TRUE(child); 628 EXPECT_EQ(row1.title(), child->GetTitle()); 629 EXPECT_EQ(row1.url(), child->url()); 630 631 // Delete the row1. 632 std::vector<base::string16> args; 633 int deleted_count = 0; 634 delegate_.ResetDetails(); 635 ASSERT_TRUE(backend->DeleteHistoryAndBookmarks("Favicon IS NULL", args, 636 &deleted_count)); 637 EXPECT_EQ(1, deleted_count); 638 // Verify the row1 was removed from bookmark model. 639 content::RunAllPendingInMessageLoop(); 640 ASSERT_EQ(0, bookmark_model_->mobile_node()->child_count()); 641 642 // Verify notifications 643 ASSERT_TRUE(delegate_.deleted_details()); 644 EXPECT_FALSE(delegate_.modified_details()); 645 EXPECT_EQ(1u, delegate_.deleted_details()->rows.size()); 646 EXPECT_EQ(row1.url(), delegate_.deleted_details()->rows[0].url()); 647 EXPECT_EQ(row1.last_visit_time(), 648 delegate_.deleted_details()->rows[0].last_visit()); 649 EXPECT_EQ(row1.title(), 650 delegate_.deleted_details()->rows[0].title()); 651 EXPECT_FALSE(delegate_.favicon_details()); 652 653 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 654 projections.push_back(HistoryAndBookmarkRow::ID); 655 projections.push_back(HistoryAndBookmarkRow::URL); 656 projections.push_back(HistoryAndBookmarkRow::TITLE); 657 projections.push_back(HistoryAndBookmarkRow::CREATED); 658 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 659 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 660 projections.push_back(HistoryAndBookmarkRow::FAVICON); 661 projections.push_back(HistoryAndBookmarkRow::BOOKMARK); 662 663 scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks( 664 projections, std::string(), std::vector<base::string16>(), 665 std::string("url ASC"))); 666 ASSERT_TRUE(statement->statement()->Step()); 667 668 EXPECT_EQ(row2.title(), statement->statement()->ColumnString16(2)); 669 EXPECT_EQ(row2.url(), GURL(statement->statement()->ColumnString(1))); 670 EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()), 671 statement->statement()->ColumnInt64(3)); 672 EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()), 673 statement->statement()->ColumnInt64(4)); 674 EXPECT_EQ(1, statement->statement()->ColumnInt(5)); 675 EXPECT_EQ(6, statement->favicon_index()); 676 // Has favicon. 677 EXPECT_NE(0, statement->statement()->ColumnByteLength(6)); 678 // TODO: Find a way to test the bookmark was added in BookmarkModel. 679 // The bookmark was added in UI thread, there is no good way to test it. 680 EXPECT_FALSE(statement->statement()->ColumnBool(7)); 681 // No more row. 682 EXPECT_FALSE(statement->statement()->Step()); 683 684 deleted_count = 0; 685 // Delete row2. 686 delegate_.ResetDetails(); 687 ASSERT_TRUE(backend->DeleteHistoryAndBookmarks("bookmark = 0", 688 std::vector<base::string16>(), &deleted_count)); 689 // Verify notifications 690 ASSERT_TRUE(delegate_.deleted_details()); 691 EXPECT_FALSE(delegate_.modified_details()); 692 EXPECT_EQ(1u, delegate_.deleted_details()->rows.size()); 693 EXPECT_EQ(row2.url(), delegate_.deleted_details()->rows[0].url()); 694 EXPECT_EQ(row2.last_visit_time(), 695 delegate_.deleted_details()->rows[0].last_visit()); 696 EXPECT_EQ(row2.title(), 697 delegate_.deleted_details()->rows[0].title()); 698 ASSERT_TRUE(delegate_.favicon_details()); 699 ASSERT_EQ(1u, delegate_.favicon_details()->urls.size()); 700 ASSERT_TRUE(delegate_.favicon_details()->urls.end() != 701 delegate_.favicon_details()->urls.find(row2.url())); 702 703 ASSERT_EQ(1, deleted_count); 704 scoped_ptr<AndroidStatement> statement1(backend->QueryHistoryAndBookmarks( 705 projections, std::string(), std::vector<base::string16>(), 706 std::string("url ASC"))); 707 ASSERT_FALSE(statement1->statement()->Step()); 708 } 709 710 TEST_F(AndroidProviderBackendTest, IsValidHistoryAndBookmarkRow) { 711 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 712 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 713 scoped_ptr<AndroidProviderBackend> backend( 714 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 715 &thumbnail_db_, bookmark_model_, &delegate_)); 716 717 // The created time and last visit time are too close to have required visit 718 // count. 719 HistoryAndBookmarkRow row1; 720 row1.set_raw_url("cnn.com"); 721 row1.set_url(GURL("http://cnn.com")); 722 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 723 row1.set_created(Time::FromInternalValue( 724 row1.last_visit_time().ToInternalValue() - 1)); 725 row1.set_visit_count(10); 726 row1.set_is_bookmark(true); 727 row1.set_title(UTF8ToUTF16("cnn")); 728 EXPECT_FALSE(backend->InsertHistoryAndBookmark(row1)); 729 730 // Have different created time and last visit time, but only have 1 visit 731 // count. 732 HistoryAndBookmarkRow row2; 733 row2.set_raw_url("http://www.example.com"); 734 row2.set_url(GURL("http://www.example.com")); 735 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 736 row2.set_created(Time::Now() - TimeDelta::FromDays(11)); 737 row2.set_visit_count(1); 738 EXPECT_FALSE(backend->InsertHistoryAndBookmark(row2)); 739 740 // Have created time in the future. 741 HistoryAndBookmarkRow row3; 742 row3.set_raw_url("http://www.example.com"); 743 row3.set_url(GURL("http://www.example.com")); 744 row3.set_created(Time::Now() + TimeDelta::FromDays(11)); 745 EXPECT_FALSE(backend->InsertHistoryAndBookmark(row3)); 746 747 // Have last vist time in the future. 748 HistoryAndBookmarkRow row4; 749 row4.set_raw_url("http://www.example.com"); 750 row4.set_url(GURL("http://www.example.com")); 751 row4.set_last_visit_time(Time::Now() + TimeDelta::FromDays(11)); 752 EXPECT_FALSE(backend->InsertHistoryAndBookmark(row4)); 753 754 // Created time is larger than last visit time. 755 HistoryAndBookmarkRow row5; 756 row5.set_raw_url("http://www.example.com"); 757 row5.set_url(GURL("http://www.example.com")); 758 row5.set_last_visit_time(Time::Now()); 759 row5.set_created(Time::Now() + TimeDelta::FromDays(11)); 760 EXPECT_FALSE(backend->InsertHistoryAndBookmark(row5)); 761 762 // Visit count is zero, and last visit time is not zero. 763 HistoryAndBookmarkRow row6; 764 row6.set_raw_url("http://www.example.com"); 765 row6.set_url(GURL("http://www.example.com")); 766 row6.set_visit_count(0); 767 row6.set_last_visit_time(Time::Now()); 768 row6.set_created(Time::Now() - TimeDelta::FromDays(1)); 769 EXPECT_FALSE(backend->InsertHistoryAndBookmark(row6)); 770 771 // Visit count is zero, and create time is not zero. 772 HistoryAndBookmarkRow row7; 773 row7.set_raw_url("http://www.example.com"); 774 row7.set_url(GURL("http://www.example.com")); 775 row7.set_visit_count(0); 776 row7.set_last_visit_time(Time::Now()); 777 row7.set_created(Time::UnixEpoch()); 778 EXPECT_TRUE(backend->InsertHistoryAndBookmark(row7)); 779 } 780 781 TEST_F(AndroidProviderBackendTest, UpdateURL) { 782 HistoryAndBookmarkRow row1; 783 row1.set_raw_url("cnn.com"); 784 row1.set_url(GURL("http://cnn.com")); 785 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 786 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 787 row1.set_visit_count(10); 788 row1.set_is_bookmark(true); 789 row1.set_title(UTF8ToUTF16("cnn")); 790 791 HistoryAndBookmarkRow row2; 792 row2.set_raw_url("http://www.example.com"); 793 row2.set_url(GURL("http://www.example.com")); 794 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 795 row2.set_is_bookmark(false); 796 row2.set_title(UTF8ToUTF16("example")); 797 std::vector<unsigned char> data; 798 data.push_back('1'); 799 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 800 801 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 802 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 803 scoped_ptr<AndroidProviderBackend> backend( 804 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 805 &thumbnail_db_, bookmark_model_, &delegate_)); 806 807 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 808 ASSERT_TRUE(id1); 809 AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2); 810 ASSERT_TRUE(id2); 811 812 // Verify the row1 has been added in bookmark model. 813 content::RunAllPendingInMessageLoop(); 814 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 815 const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0); 816 ASSERT_TRUE(child); 817 EXPECT_EQ(row1.title(), child->GetTitle()); 818 EXPECT_EQ(row1.url(), child->url()); 819 820 // Make sure the url has correctly insertted. 821 URLID url_id1 = history_db_.GetRowForURL(row1.url(), NULL); 822 ASSERT_TRUE(url_id1); 823 URLID url_id2 = history_db_.GetRowForURL(row2.url(), NULL); 824 ASSERT_TRUE(url_id2); 825 826 // Make sure we have the correct visit rows in visit table. 827 VisitVector visits; 828 ASSERT_TRUE(history_db_.GetVisitsForURL(url_id1, &visits)); 829 ASSERT_EQ(10u, visits.size()); 830 visits.clear(); 831 ASSERT_TRUE(history_db_.GetVisitsForURL(url_id2, &visits)); 832 ASSERT_EQ(1u, visits.size()); 833 834 int update_count; 835 std::vector<base::string16> update_args; 836 // Try to update the mutiple rows with the same URL, this should failed. 837 HistoryAndBookmarkRow update_row1; 838 update_row1.set_raw_url("newwebiste.com"); 839 update_row1.set_url(GURL("http://newwebsite.com")); 840 update_args.clear(); 841 ASSERT_FALSE(backend->UpdateHistoryAndBookmarks(update_row1, std::string(), 842 update_args, &update_count)); 843 844 // Only update one URL. 845 update_args.clear(); 846 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 847 delegate_.ResetDetails(); 848 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?", 849 update_args, &update_count)); 850 // Verify notifications, Update involves insert and delete URLS. 851 ASSERT_TRUE(delegate_.deleted_details()); 852 EXPECT_EQ(1u, delegate_.deleted_details()->rows.size()); 853 EXPECT_EQ(row1.url(), delegate_.deleted_details()->rows[0].url()); 854 EXPECT_EQ(row1.last_visit_time(), 855 delegate_.deleted_details()->rows[0].last_visit()); 856 EXPECT_EQ(row1.title(), 857 delegate_.deleted_details()->rows[0].title()); 858 ASSERT_TRUE(delegate_.modified_details()); 859 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 860 EXPECT_EQ(update_row1.url(), 861 delegate_.modified_details()->changed_urls[0].url()); 862 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 863 ToDatabaseTime( 864 delegate_.modified_details()->changed_urls[0].last_visit())); 865 EXPECT_EQ(row1.title(), 866 delegate_.modified_details()->changed_urls[0].title()); 867 EXPECT_FALSE(delegate_.favicon_details()); 868 869 EXPECT_EQ(1, update_count); 870 // We shouldn't find orignal url anymore. 871 EXPECT_FALSE(history_db_.GetRowForURL(row1.url(), NULL)); 872 visits.clear(); 873 EXPECT_TRUE(history_db_.GetVisitsForURL(url_id1, &visits)); 874 EXPECT_EQ(0u, visits.size()); 875 // Verify new URL. 876 URLRow new_row; 877 EXPECT_TRUE(history_db_.GetRowForURL(update_row1.url(), &new_row)); 878 EXPECT_EQ(10, new_row.visit_count()); 879 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 880 ToDatabaseTime(new_row.last_visit())); 881 visits.clear(); 882 EXPECT_TRUE(history_db_.GetVisitsForURL(new_row.id(), &visits)); 883 EXPECT_EQ(10u, visits.size()); 884 AndroidURLRow android_url_row1; 885 ASSERT_TRUE(history_db_.GetAndroidURLRow(new_row.id(), &android_url_row1)); 886 // Android URL ID shouldn't change. 887 EXPECT_EQ(id1, android_url_row1.id); 888 889 // Verify the bookmark model was updated. 890 content::RunAllPendingInMessageLoop(); 891 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 892 const BookmarkNode* child1 = bookmark_model_->mobile_node()->GetChild(0); 893 ASSERT_TRUE(child1); 894 EXPECT_EQ(row1.title(), child1->GetTitle()); 895 EXPECT_EQ(update_row1.url(), child1->url()); 896 897 // Update the URL with visit count, created time, and last visit time. 898 HistoryAndBookmarkRow update_row2; 899 update_row2.set_raw_url("somethingelse.com"); 900 update_row2.set_url(GURL("http://somethingelse.com")); 901 update_row2.set_last_visit_time(Time::Now()); 902 update_row2.set_created(Time::Now() - TimeDelta::FromDays(20)); 903 update_row2.set_visit_count(10); 904 905 update_args.clear(); 906 update_args.push_back(UTF8ToUTF16(row2.raw_url())); 907 delegate_.ResetDetails(); 908 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row2, "url = ?", 909 update_args, &update_count)); 910 // Verify notifications, Update involves insert and delete URLS. 911 ASSERT_TRUE(delegate_.deleted_details()); 912 EXPECT_EQ(1u, delegate_.deleted_details()->rows.size()); 913 EXPECT_EQ(row2.url(), delegate_.deleted_details()->rows[0].url()); 914 EXPECT_EQ(row2.last_visit_time(), 915 delegate_.deleted_details()->rows[0].last_visit()); 916 EXPECT_EQ(row2.title(), 917 delegate_.deleted_details()->rows[0].title()); 918 ASSERT_TRUE(delegate_.modified_details()); 919 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 920 EXPECT_EQ(update_row2.url(), 921 delegate_.modified_details()->changed_urls[0].url()); 922 EXPECT_EQ(ToDatabaseTime(update_row2.last_visit_time()), 923 ToDatabaseTime( 924 delegate_.modified_details()->changed_urls[0].last_visit())); 925 EXPECT_EQ(update_row2.visit_count(), 926 delegate_.modified_details()->changed_urls[0].visit_count()); 927 ASSERT_TRUE(delegate_.favicon_details()); 928 ASSERT_EQ(2u, delegate_.favicon_details()->urls.size()); 929 ASSERT_TRUE(delegate_.favicon_details()->urls.end() != 930 delegate_.favicon_details()->urls.find(row2.url())); 931 ASSERT_TRUE(delegate_.favicon_details()->urls.end() != 932 delegate_.favicon_details()->urls.find(update_row2.url())); 933 934 EXPECT_EQ(1, update_count); 935 // We shouldn't find orignal url anymore. 936 EXPECT_FALSE(history_db_.GetRowForURL(row2.url(), NULL)); 937 visits.clear(); 938 EXPECT_TRUE(history_db_.GetVisitsForURL(url_id2, &visits)); 939 EXPECT_EQ(0u, visits.size()); 940 941 // Verify new URL. 942 URLRow new_row2; 943 ASSERT_TRUE(history_db_.GetRowForURL(update_row2.url(), &new_row2)); 944 EXPECT_EQ(10, new_row2.visit_count()); 945 EXPECT_EQ(update_row2.last_visit_time(), new_row2.last_visit()); 946 visits.clear(); 947 EXPECT_TRUE(history_db_.GetVisitsForURL(new_row2.id(), &visits)); 948 EXPECT_EQ(10u, visits.size()); 949 AndroidURLRow android_url_row2; 950 ASSERT_TRUE(history_db_.GetAndroidURLRow(new_row2.id(), &android_url_row2)); 951 // Android URL ID shouldn't change. 952 EXPECT_EQ(id2, android_url_row2.id); 953 954 ASSERT_TRUE(history_db_.GetVisitsForURL(new_row2.id(), &visits)); 955 ASSERT_EQ(10u, visits.size()); 956 EXPECT_EQ(update_row2.created(), visits[0].visit_time); 957 EXPECT_EQ(update_row2.last_visit_time(), visits[9].visit_time); 958 } 959 960 TEST_F(AndroidProviderBackendTest, UpdateVisitCount) { 961 HistoryAndBookmarkRow row1; 962 row1.set_raw_url("cnn.com"); 963 row1.set_url(GURL("http://cnn.com")); 964 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 965 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 966 row1.set_visit_count(10); 967 row1.set_is_bookmark(true); 968 row1.set_title(UTF8ToUTF16("cnn")); 969 970 HistoryAndBookmarkRow row2; 971 row2.set_raw_url("http://www.example.com"); 972 row2.set_url(GURL("http://www.example.com")); 973 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 974 row2.set_is_bookmark(false); 975 row2.set_title(UTF8ToUTF16("example")); 976 std::vector<unsigned char> data; 977 data.push_back('1'); 978 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 979 980 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 981 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 982 scoped_ptr<AndroidProviderBackend> backend( 983 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 984 &thumbnail_db_, bookmark_model_, &delegate_)); 985 986 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 987 ASSERT_TRUE(id1); 988 AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2); 989 ASSERT_TRUE(id2); 990 991 int update_count; 992 std::vector<base::string16> update_args; 993 // Update the visit_count to a value less than current one. 994 HistoryAndBookmarkRow update_row1; 995 update_row1.set_visit_count(5); 996 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 997 delegate_.ResetDetails(); 998 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?", 999 update_args, &update_count)); 1000 // Verify notifications, Update involves modified URL. 1001 EXPECT_FALSE(delegate_.deleted_details()); 1002 ASSERT_TRUE(delegate_.modified_details()); 1003 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 1004 EXPECT_EQ(row1.url(), 1005 delegate_.modified_details()->changed_urls[0].url()); 1006 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 1007 ToDatabaseTime( 1008 delegate_.modified_details()->changed_urls[0].last_visit())); 1009 EXPECT_EQ(update_row1.visit_count(), 1010 delegate_.modified_details()->changed_urls[0].visit_count()); 1011 EXPECT_FALSE(delegate_.favicon_details()); 1012 1013 // All visits should be removed, and 5 new visit insertted. 1014 URLRow new_row1; 1015 ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), &new_row1)); 1016 EXPECT_EQ(5, new_row1.visit_count()); 1017 VisitVector visits; 1018 ASSERT_TRUE(history_db_.GetVisitsForURL(new_row1.id(), &visits)); 1019 ASSERT_EQ(5u, visits.size()); 1020 EXPECT_EQ(row1.last_visit_time(), visits[4].visit_time); 1021 EXPECT_GT(row1.last_visit_time(), visits[0].visit_time); 1022 1023 // Update the visit_count to a value equal to current one. 1024 HistoryAndBookmarkRow update_row2; 1025 update_row2.set_visit_count(1); 1026 update_args.clear(); 1027 update_args.push_back(UTF8ToUTF16(row2.raw_url())); 1028 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row2, "url = ?", 1029 update_args, &update_count)); 1030 // All shouldn't have any change. 1031 URLRow new_row2; 1032 ASSERT_TRUE(history_db_.GetRowForURL(row2.url(), &new_row2)); 1033 EXPECT_EQ(1, new_row2.visit_count()); 1034 1035 ASSERT_TRUE(history_db_.GetVisitsForURL(new_row2.id(), &visits)); 1036 ASSERT_EQ(1u, visits.size()); 1037 EXPECT_EQ(row2.last_visit_time(), visits[0].visit_time); 1038 } 1039 1040 TEST_F(AndroidProviderBackendTest, UpdateLastVisitTime) { 1041 HistoryAndBookmarkRow row1; 1042 row1.set_raw_url("cnn.com"); 1043 row1.set_url(GURL("http://cnn.com")); 1044 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1045 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1046 row1.set_visit_count(10); 1047 row1.set_is_bookmark(true); 1048 row1.set_title(UTF8ToUTF16("cnn")); 1049 1050 HistoryAndBookmarkRow row2; 1051 row2.set_raw_url("http://www.example.com"); 1052 row2.set_url(GURL("http://www.example.com")); 1053 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 1054 row2.set_is_bookmark(false); 1055 row2.set_title(UTF8ToUTF16("example")); 1056 std::vector<unsigned char> data; 1057 data.push_back('1'); 1058 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 1059 1060 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1061 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1062 scoped_ptr<AndroidProviderBackend> backend( 1063 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1064 &thumbnail_db_, bookmark_model_, &delegate_)); 1065 1066 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 1067 ASSERT_TRUE(id1); 1068 AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2); 1069 ASSERT_TRUE(id2); 1070 1071 int update_count; 1072 std::vector<base::string16> update_args; 1073 // Update the last visit time to a value greater than current one. 1074 HistoryAndBookmarkRow update_row1; 1075 update_row1.set_last_visit_time(Time::Now()); 1076 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 1077 delegate_.ResetDetails(); 1078 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?", 1079 update_args, &update_count)); 1080 // Verify notifications, Update involves modified URL. 1081 EXPECT_FALSE(delegate_.deleted_details()); 1082 ASSERT_TRUE(delegate_.modified_details()); 1083 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 1084 EXPECT_EQ(row1.url(), 1085 delegate_.modified_details()->changed_urls[0].url()); 1086 EXPECT_EQ(ToDatabaseTime(update_row1.last_visit_time()), 1087 ToDatabaseTime( 1088 delegate_.modified_details()->changed_urls[0].last_visit())); 1089 EXPECT_FALSE(delegate_.favicon_details()); 1090 1091 URLRow new_row1; 1092 ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), &new_row1)); 1093 EXPECT_EQ(11, new_row1.visit_count()); 1094 EXPECT_EQ(update_row1.last_visit_time(), new_row1.last_visit()); 1095 VisitVector visits; 1096 ASSERT_TRUE(history_db_.GetVisitsForURL(new_row1.id(), &visits)); 1097 // 1 new visit insertted. 1098 ASSERT_EQ(11u, visits.size()); 1099 EXPECT_EQ(update_row1.last_visit_time(), visits[10].visit_time); 1100 EXPECT_EQ(row1.last_visit_time(), visits[9].visit_time); 1101 1102 // Update the visit_tim to a value less than to current one. 1103 HistoryAndBookmarkRow update_row2; 1104 update_row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1105 update_args.clear(); 1106 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 1107 ASSERT_FALSE(backend->UpdateHistoryAndBookmarks(update_row2, "url = ?", 1108 update_args, &update_count)); 1109 } 1110 1111 TEST_F(AndroidProviderBackendTest, UpdateFavicon) { 1112 HistoryAndBookmarkRow row1; 1113 row1.set_raw_url("cnn.com"); 1114 row1.set_url(GURL("http://cnn.com")); 1115 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1116 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1117 row1.set_visit_count(10); 1118 row1.set_is_bookmark(true); 1119 row1.set_title(UTF8ToUTF16("cnn")); 1120 1121 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1122 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1123 scoped_ptr<AndroidProviderBackend> backend( 1124 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1125 &thumbnail_db_, bookmark_model_, &delegate_)); 1126 1127 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 1128 ASSERT_TRUE(id1); 1129 1130 int update_count; 1131 std::vector<base::string16> update_args; 1132 // Update the last visit time to a value greater than current one. 1133 HistoryAndBookmarkRow update_row1; 1134 1135 // Set favicon. 1136 std::vector<unsigned char> data; 1137 data.push_back('1'); 1138 update_row1.set_favicon(base::RefCountedBytes::TakeVector(&data)); 1139 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 1140 delegate_.ResetDetails(); 1141 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?", 1142 update_args, &update_count)); 1143 // Verify notifications. 1144 EXPECT_FALSE(delegate_.deleted_details()); 1145 EXPECT_FALSE(delegate_.modified_details()); 1146 ASSERT_TRUE(delegate_.favicon_details()); 1147 ASSERT_EQ(1u, delegate_.favicon_details()->urls.size()); 1148 ASSERT_TRUE(delegate_.favicon_details()->urls.end() != 1149 delegate_.favicon_details()->urls.find(row1.url())); 1150 1151 std::vector<IconMapping> icon_mappings; 1152 EXPECT_TRUE(thumbnail_db_.GetIconMappingsForPageURL( 1153 row1.url(), chrome::FAVICON, &icon_mappings)); 1154 EXPECT_EQ(1u, icon_mappings.size()); 1155 std::vector<FaviconBitmap> favicon_bitmaps; 1156 EXPECT_TRUE(thumbnail_db_.GetFaviconBitmaps(icon_mappings[0].icon_id, 1157 &favicon_bitmaps)); 1158 EXPECT_EQ(1u, favicon_bitmaps.size()); 1159 EXPECT_TRUE(favicon_bitmaps[0].bitmap_data.get()); 1160 EXPECT_EQ(1u, favicon_bitmaps[0].bitmap_data->size()); 1161 EXPECT_EQ('1', *favicon_bitmaps[0].bitmap_data->front()); 1162 1163 // Remove favicon. 1164 HistoryAndBookmarkRow update_row2; 1165 1166 // Set favicon. 1167 update_row1.set_favicon(new base::RefCountedBytes()); 1168 update_args.clear(); 1169 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 1170 delegate_.ResetDetails(); 1171 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?", 1172 update_args, &update_count)); 1173 // Verify notifications. 1174 EXPECT_FALSE(delegate_.deleted_details()); 1175 EXPECT_FALSE(delegate_.modified_details()); 1176 ASSERT_TRUE(delegate_.favicon_details()); 1177 ASSERT_EQ(1u, delegate_.favicon_details()->urls.size()); 1178 ASSERT_TRUE(delegate_.favicon_details()->urls.end() != 1179 delegate_.favicon_details()->urls.find(row1.url())); 1180 1181 EXPECT_FALSE(thumbnail_db_.GetIconMappingsForPageURL( 1182 row1.url(), chrome::FAVICON, NULL)); 1183 } 1184 1185 TEST_F(AndroidProviderBackendTest, UpdateSearchTermTable) { 1186 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1187 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1188 scoped_ptr<AndroidProviderBackend> backend( 1189 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1190 &thumbnail_db_, bookmark_model_, &delegate_)); 1191 // Insert a keyword search item to verify if the update succeeds. 1192 HistoryAndBookmarkRow row1; 1193 row1.set_raw_url("cnn.com"); 1194 row1.set_url(GURL("http://cnn.com")); 1195 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1196 row1.set_title(UTF8ToUTF16("cnn")); 1197 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1198 base::string16 term = UTF8ToUTF16("Search term 1"); 1199 URLID url_id = history_db_.GetRowForURL(row1.url(), NULL); 1200 ASSERT_TRUE(url_id); 1201 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term)); 1202 ASSERT_TRUE(backend->UpdateSearchTermTable()); 1203 SearchTermRow keyword_cache; 1204 SearchTermID id = history_db_.GetSearchTerm(term, &keyword_cache); 1205 ASSERT_TRUE(id); 1206 EXPECT_EQ(term, keyword_cache.term); 1207 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 1208 ToDatabaseTime(keyword_cache.last_visit_time)); 1209 1210 // Add another row. 1211 HistoryAndBookmarkRow row2; 1212 row2.set_raw_url("google.com"); 1213 row2.set_url(GURL("http://google.com")); 1214 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(2)); 1215 row2.set_title(UTF8ToUTF16("cnn")); 1216 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 1217 url_id = history_db_.GetRowForURL(row2.url(), NULL); 1218 ASSERT_TRUE(url_id); 1219 base::string16 term2 = UTF8ToUTF16("Search term 2"); 1220 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term2)); 1221 ASSERT_TRUE(backend->UpdateSearchTermTable()); 1222 SearchTermID search_id1 = history_db_.GetSearchTerm(term, 1223 &keyword_cache); 1224 // The id shouldn't changed. 1225 ASSERT_EQ(id, search_id1); 1226 EXPECT_EQ(term, keyword_cache.term); 1227 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 1228 ToDatabaseTime(keyword_cache.last_visit_time)); 1229 // Verify the row just inserted. 1230 SearchTermID id2 = history_db_.GetSearchTerm(term2, &keyword_cache); 1231 ASSERT_TRUE(id2); 1232 EXPECT_EQ(term2, keyword_cache.term); 1233 EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()), 1234 ToDatabaseTime(keyword_cache.last_visit_time)); 1235 1236 // Add 3rd row and associate it with term. 1237 HistoryAndBookmarkRow row3; 1238 row3.set_raw_url("search.com"); 1239 row3.set_url(GURL("http://search.com")); 1240 row3.set_last_visit_time(Time::Now()); 1241 row3.set_title(UTF8ToUTF16("search")); 1242 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row3)); 1243 url_id = history_db_.GetRowForURL(row3.url(), NULL); 1244 ASSERT_TRUE(url_id); 1245 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term)); 1246 ASSERT_TRUE(backend->UpdateSearchTermTable()); 1247 // Verify id not changed and last_visit_time updated. 1248 ASSERT_EQ(search_id1, history_db_.GetSearchTerm(term, &keyword_cache)); 1249 EXPECT_EQ(ToDatabaseTime(row3.last_visit_time()), 1250 ToDatabaseTime(keyword_cache.last_visit_time)); 1251 // The id of term2 wasn't changed. 1252 EXPECT_EQ(id2, history_db_.GetSearchTerm(term2, NULL)); 1253 1254 // Remove the term. 1255 ASSERT_TRUE(history_db_.DeleteKeywordSearchTerm(term)); 1256 ASSERT_TRUE(backend->UpdateSearchTermTable()); 1257 // The cache of term should removed. 1258 ASSERT_FALSE(history_db_.GetSearchTerm(term, NULL)); 1259 // The id of term2 wasn't changed. 1260 EXPECT_EQ(id2, history_db_.GetSearchTerm(term2, NULL)); 1261 } 1262 1263 TEST_F(AndroidProviderBackendTest, QuerySearchTerms) { 1264 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1265 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1266 scoped_ptr<AndroidProviderBackend> backend( 1267 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1268 &thumbnail_db_, bookmark_model_, &delegate_)); 1269 // Insert a keyword search item to verify if we can find it. 1270 HistoryAndBookmarkRow row1; 1271 row1.set_raw_url("cnn.com"); 1272 row1.set_url(GURL("http://cnn.com")); 1273 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1274 row1.set_title(UTF8ToUTF16("cnn")); 1275 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1276 base::string16 term = UTF8ToUTF16("Search term 1"); 1277 URLID url_id = history_db_.GetRowForURL(row1.url(), NULL); 1278 ASSERT_TRUE(url_id); 1279 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term)); 1280 1281 std::vector<SearchRow::ColumnID> projections; 1282 projections.push_back(SearchRow::ID); 1283 projections.push_back(SearchRow::SEARCH_TERM); 1284 projections.push_back(SearchRow::SEARCH_TIME); 1285 scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms( 1286 projections, std::string(), std::vector<base::string16>(), 1287 std::string())); 1288 ASSERT_TRUE(statement.get()); 1289 ASSERT_TRUE(statement->statement()->Step()); 1290 EXPECT_TRUE(statement->statement()->ColumnInt64(0)); 1291 EXPECT_EQ(term, statement->statement()->ColumnString16(1)); 1292 EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()), 1293 statement->statement()->ColumnInt64(2)); 1294 EXPECT_FALSE(statement->statement()->Step()); 1295 } 1296 1297 TEST_F(AndroidProviderBackendTest, UpdateSearchTerms) { 1298 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1299 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1300 scoped_ptr<AndroidProviderBackend> backend( 1301 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1302 &thumbnail_db_, bookmark_model_, &delegate_)); 1303 // Insert a keyword. 1304 HistoryAndBookmarkRow row1; 1305 row1.set_raw_url("cnn.com"); 1306 row1.set_url(GURL("http://cnn.com")); 1307 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1308 row1.set_title(UTF8ToUTF16("cnn")); 1309 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1310 base::string16 term = UTF8ToUTF16("Search term 1"); 1311 URLID url_id = history_db_.GetRowForURL(row1.url(), NULL); 1312 ASSERT_TRUE(url_id); 1313 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term)); 1314 1315 // Get the SearchTermID of the row we just inserted. 1316 std::vector<SearchRow::ColumnID> projections; 1317 projections.push_back(SearchRow::ID); 1318 projections.push_back(SearchRow::SEARCH_TIME); 1319 projections.push_back(SearchRow::SEARCH_TERM); 1320 std::vector<base::string16> args; 1321 args.push_back(term); 1322 scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms( 1323 projections, "search = ?", args, std::string())); 1324 ASSERT_TRUE(statement.get()); 1325 ASSERT_TRUE(statement->statement()->Step()); 1326 SearchTermID id = statement->statement()->ColumnInt64(0); 1327 ASSERT_TRUE(id); 1328 EXPECT_FALSE(statement->statement()->Step()); 1329 1330 // Update the search term and time. 1331 base::string16 update_term = UTF8ToUTF16("Update search term"); 1332 args.clear(); 1333 args.push_back(term); 1334 SearchRow search_row; 1335 search_row.set_search_term(update_term); 1336 search_row.set_url(GURL("http://google.com")); 1337 search_row.set_template_url_id(1); 1338 search_row.set_search_time(Time::Now() - TimeDelta::FromHours(1)); 1339 int update_count = 0; 1340 ASSERT_TRUE(backend->UpdateSearchTerms(search_row, "search = ?", args, 1341 &update_count)); 1342 EXPECT_EQ(1, update_count); 1343 1344 // Verify if the search term updated. 1345 // The origin term should be removed. 1346 std::vector<KeywordSearchTermRow> rows; 1347 ASSERT_TRUE(history_db_.GetKeywordSearchTermRows(term, &rows)); 1348 EXPECT_TRUE(rows.empty()); 1349 // The new term should be inserted. 1350 ASSERT_TRUE(history_db_.GetKeywordSearchTermRows(update_term, &rows)); 1351 ASSERT_EQ(1u, rows.size()); 1352 // The history of urls shouldn't be removed. 1353 ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), NULL)); 1354 // The new URL is inserted. 1355 ASSERT_TRUE(history_db_.GetRowForURL(search_row.url(), NULL)); 1356 1357 // Verfiy the AndoridSearchID isn't changed. 1358 args.clear(); 1359 args.push_back(update_term); 1360 statement.reset(backend->QuerySearchTerms(projections, "search = ?", args, 1361 std::string())); 1362 ASSERT_TRUE(statement.get()); 1363 ASSERT_TRUE(statement->statement()->Step()); 1364 // The id didn't change. 1365 EXPECT_EQ(id, statement->statement()->ColumnInt64(0)); 1366 // The search time was updated. 1367 EXPECT_EQ(ToDatabaseTime(search_row.search_time()), 1368 statement->statement()->ColumnInt64(1)); 1369 // The search term was updated. 1370 EXPECT_EQ(update_term, statement->statement()->ColumnString16(2)); 1371 EXPECT_FALSE(statement->statement()->Step()); 1372 1373 // Only update the search time. 1374 SearchRow update_time; 1375 update_time.set_search_time(Time::Now()); 1376 // Update it by id. 1377 args.clear(); 1378 std::ostringstream oss; 1379 oss << id; 1380 args.push_back(UTF8ToUTF16(oss.str())); 1381 update_count = 0; 1382 ASSERT_TRUE(backend->UpdateSearchTerms(update_time, "_id = ?", args, 1383 &update_count)); 1384 EXPECT_EQ(1, update_count); 1385 1386 // Verify the update. 1387 statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args, 1388 std::string())); 1389 ASSERT_TRUE(statement.get()); 1390 ASSERT_TRUE(statement->statement()->Step()); 1391 // The id didn't change. 1392 EXPECT_EQ(id, statement->statement()->ColumnInt64(0)); 1393 // The search time was updated. 1394 EXPECT_EQ(ToDatabaseTime(update_time.search_time()), 1395 statement->statement()->ColumnInt64(1)); 1396 // The search term didn't change. 1397 EXPECT_EQ(update_term, statement->statement()->ColumnString16(2)); 1398 EXPECT_FALSE(statement->statement()->Step()); 1399 } 1400 1401 TEST_F(AndroidProviderBackendTest, DeleteSearchTerms) { 1402 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1403 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1404 scoped_ptr<AndroidProviderBackend> backend( 1405 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1406 &thumbnail_db_, bookmark_model_, &delegate_)); 1407 // Insert a keyword. 1408 HistoryAndBookmarkRow row1; 1409 row1.set_raw_url("cnn.com"); 1410 row1.set_url(GURL("http://cnn.com")); 1411 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1412 row1.set_title(UTF8ToUTF16("cnn")); 1413 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1414 base::string16 term = UTF8ToUTF16("Search term 1"); 1415 URLID url_id = history_db_.GetRowForURL(row1.url(), NULL); 1416 ASSERT_TRUE(url_id); 1417 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term)); 1418 1419 // Get the SearchTermID of the row we just inserted. 1420 std::vector<SearchRow::ColumnID> projections; 1421 projections.push_back(SearchRow::ID); 1422 projections.push_back(SearchRow::SEARCH_TIME); 1423 projections.push_back(SearchRow::SEARCH_TERM); 1424 std::vector<base::string16> args; 1425 args.push_back(term); 1426 scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms( 1427 projections, "search = ?", args, std::string())); 1428 ASSERT_TRUE(statement.get()); 1429 ASSERT_TRUE(statement->statement()->Step()); 1430 SearchTermID id1 = statement->statement()->ColumnInt64(0); 1431 ASSERT_TRUE(id1); 1432 EXPECT_FALSE(statement->statement()->Step()); 1433 1434 // Insert a keyword. 1435 HistoryAndBookmarkRow row2; 1436 row2.set_raw_url("google.com"); 1437 row2.set_url(GURL("http://google.com")); 1438 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1439 row2.set_title(UTF8ToUTF16("google")); 1440 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 1441 base::string16 term2 = UTF8ToUTF16("Search term 2"); 1442 URLID url_id2 = history_db_.GetRowForURL(row2.url(), NULL); 1443 ASSERT_TRUE(url_id2); 1444 ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id2, 1, term2)); 1445 1446 // Get the SearchTermID of the row we just inserted. 1447 projections.clear(); 1448 projections.push_back(SearchRow::ID); 1449 projections.push_back(SearchRow::SEARCH_TIME); 1450 projections.push_back(SearchRow::SEARCH_TERM); 1451 args.clear(); 1452 args.push_back(term2); 1453 statement.reset(backend->QuerySearchTerms(projections, "search = ?", args, 1454 std::string())); 1455 ASSERT_TRUE(statement.get()); 1456 ASSERT_TRUE(statement->statement()->Step()); 1457 SearchTermID id2 = statement->statement()->ColumnInt64(0); 1458 ASSERT_TRUE(id2); 1459 EXPECT_FALSE(statement->statement()->Step()); 1460 1461 // Delete the first one. 1462 args.clear(); 1463 args.push_back(term); 1464 int deleted_count = 0; 1465 ASSERT_TRUE(backend->DeleteSearchTerms("search = ?", args, &deleted_count)); 1466 EXPECT_EQ(1, deleted_count); 1467 std::vector<KeywordSearchTermRow> rows; 1468 ASSERT_TRUE(history_db_.GetKeywordSearchTermRows(term, &rows)); 1469 EXPECT_TRUE(rows.empty()); 1470 // Verify we can't get the first term. 1471 args.clear(); 1472 std::ostringstream oss; 1473 oss << id1; 1474 args.push_back(UTF8ToUTF16(oss.str())); 1475 statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args, 1476 std::string())); 1477 ASSERT_TRUE(statement.get()); 1478 EXPECT_FALSE(statement->statement()->Step()); 1479 1480 // The second one is still there. 1481 args.clear(); 1482 std::ostringstream oss1; 1483 oss1 << id2; 1484 args.push_back(UTF8ToUTF16(oss1.str())); 1485 statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args, 1486 std::string())); 1487 ASSERT_TRUE(statement.get()); 1488 EXPECT_TRUE(statement->statement()->Step()); 1489 EXPECT_EQ(id2, statement->statement()->ColumnInt64(0)); 1490 EXPECT_FALSE(statement->statement()->Step()); 1491 1492 // Remove all search terms in no condition. 1493 deleted_count = 0; 1494 args.clear(); 1495 ASSERT_TRUE(backend->DeleteSearchTerms(std::string(), args, &deleted_count)); 1496 EXPECT_EQ(1, deleted_count); 1497 1498 // Verify the second one was removed. 1499 args.clear(); 1500 args.push_back(UTF8ToUTF16(oss1.str())); 1501 statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args, 1502 std::string())); 1503 ASSERT_TRUE(statement.get()); 1504 EXPECT_FALSE(statement->statement()->Step()); 1505 } 1506 1507 TEST_F(AndroidProviderBackendTest, InsertSearchTerm) { 1508 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1509 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1510 scoped_ptr<AndroidProviderBackend> backend( 1511 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1512 &thumbnail_db_, bookmark_model_, &delegate_)); 1513 SearchRow search_row; 1514 search_row.set_search_term(UTF8ToUTF16("google")); 1515 search_row.set_url(GURL("http://google.com")); 1516 search_row.set_template_url_id(1); 1517 search_row.set_search_time(Time::Now() - TimeDelta::FromHours(1)); 1518 1519 SearchTermID id = backend->InsertSearchTerm(search_row); 1520 ASSERT_TRUE(id); 1521 1522 std::vector<SearchRow::ColumnID> projections; 1523 projections.push_back(SearchRow::ID); 1524 projections.push_back(SearchRow::SEARCH_TIME); 1525 projections.push_back(SearchRow::SEARCH_TERM); 1526 std::vector<base::string16> args; 1527 std::ostringstream oss; 1528 oss << id; 1529 args.push_back(UTF8ToUTF16(oss.str())); 1530 scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms( 1531 projections, "_id = ?", args, std::string())); 1532 ASSERT_TRUE(statement.get()); 1533 ASSERT_TRUE(statement->statement()->Step()); 1534 EXPECT_EQ(id, statement->statement()->ColumnInt64(0)); 1535 EXPECT_EQ(ToDatabaseTime(search_row.search_time()), 1536 statement->statement()->ColumnInt64(1)); 1537 EXPECT_EQ(search_row.search_term(), 1538 statement->statement()->ColumnString16(2)); 1539 EXPECT_FALSE(statement->statement()->Step()); 1540 } 1541 1542 TEST_F(AndroidProviderBackendTest, DeleteHistory) { 1543 HistoryAndBookmarkRow row1; 1544 row1.set_raw_url("cnn.com"); 1545 row1.set_url(GURL("http://cnn.com")); 1546 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1547 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1548 row1.set_visit_count(10); 1549 row1.set_is_bookmark(true); 1550 row1.set_title(UTF8ToUTF16("cnn")); 1551 1552 HistoryAndBookmarkRow row2; 1553 row2.set_raw_url("http://www.example.com"); 1554 row2.set_url(GURL("http://www.example.com")); 1555 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 1556 row2.set_is_bookmark(false); 1557 row2.set_title(UTF8ToUTF16("example")); 1558 std::vector<unsigned char> data; 1559 data.push_back('1'); 1560 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 1561 1562 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1563 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1564 scoped_ptr<AndroidProviderBackend> backend( 1565 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1566 &thumbnail_db_, bookmark_model_, &delegate_)); 1567 1568 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 1569 ASSERT_TRUE(id1); 1570 AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2); 1571 ASSERT_TRUE(id2); 1572 1573 // Verify the row1 has been added in bookmark model. 1574 content::RunAllPendingInMessageLoop(); 1575 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 1576 const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0); 1577 ASSERT_TRUE(child); 1578 EXPECT_EQ(row1.title(), child->GetTitle()); 1579 EXPECT_EQ(row1.url(), child->url()); 1580 1581 // Delete history 1582 int deleted_count = 0; 1583 ASSERT_TRUE(backend->DeleteHistory(std::string(), 1584 std::vector<base::string16>(), 1585 &deleted_count)); 1586 EXPECT_EQ(2, deleted_count); 1587 // The row2 was deleted. 1588 EXPECT_FALSE(history_db_.GetRowForURL(row2.url(), NULL)); 1589 // Still find the row1. 1590 URLRow url_row; 1591 ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), &url_row)); 1592 // The visit_count was reset. 1593 EXPECT_EQ(0, url_row.visit_count()); 1594 EXPECT_EQ(Time::UnixEpoch(), url_row.last_visit()); 1595 1596 // Verify the row1 is still in bookmark model. 1597 content::RunAllPendingInMessageLoop(); 1598 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 1599 const BookmarkNode* child1 = bookmark_model_->mobile_node()->GetChild(0); 1600 ASSERT_TRUE(child1); 1601 EXPECT_EQ(row1.title(), child1->GetTitle()); 1602 EXPECT_EQ(row1.url(), child1->url()); 1603 1604 // Verify notification 1605 ASSERT_TRUE(delegate_.deleted_details()); 1606 ASSERT_EQ(2u, delegate_.deleted_details()->rows.size()); 1607 EXPECT_EQ(row1.url(), 1608 delegate_.modified_details()->changed_urls[0].url()); 1609 EXPECT_EQ(Time::UnixEpoch(), 1610 delegate_.modified_details()->changed_urls[0].last_visit()); 1611 EXPECT_EQ(1u, delegate_.favicon_details()->urls.size()); 1612 } 1613 1614 TEST_F(AndroidProviderBackendTest, TestMultipleNestingTransaction) { 1615 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1616 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1617 scoped_ptr<AndroidProviderBackend> backend( 1618 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1619 &thumbnail_db_, bookmark_model_, &delegate_)); 1620 1621 // Create the nested transactions. 1622 history_db_.BeginTransaction(); 1623 history_db_.BeginTransaction(); 1624 history_db_.BeginTransaction(); 1625 thumbnail_db_.BeginTransaction(); 1626 thumbnail_db_.BeginTransaction(); 1627 int history_transaction = history_db_.transaction_nesting(); 1628 int thumbnail_transaction = thumbnail_db_.transaction_nesting(); 1629 1630 // Insert a row to verify the transaction number are not changed 1631 // after a transaction commit. 1632 HistoryAndBookmarkRow row1; 1633 row1.set_raw_url("cnn.com"); 1634 row1.set_url(GURL("http://cnn.com")); 1635 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1636 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1637 row1.set_visit_count(10); 1638 row1.set_title(UTF8ToUTF16("cnn")); 1639 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1640 EXPECT_EQ(history_transaction, history_db_.transaction_nesting()); 1641 EXPECT_EQ(thumbnail_transaction, thumbnail_db_.transaction_nesting()); 1642 1643 // Insert the same URL, it should failed. The transaction are still same 1644 // after a rollback. 1645 ASSERT_FALSE(backend->InsertHistoryAndBookmark(row1)); 1646 EXPECT_EQ(history_transaction, history_db_.transaction_nesting()); 1647 EXPECT_EQ(thumbnail_transaction, thumbnail_db_.transaction_nesting()); 1648 1649 // Insert another row to verify we are still fine after the previous 1650 // rollback. 1651 HistoryAndBookmarkRow row2; 1652 row2.set_raw_url("http://www.example.com"); 1653 row2.set_url(GURL("http://www.example.com")); 1654 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 1655 row2.set_is_bookmark(false); 1656 row2.set_title(UTF8ToUTF16("example")); 1657 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 1658 EXPECT_EQ(history_transaction, history_db_.transaction_nesting()); 1659 EXPECT_EQ(thumbnail_transaction, thumbnail_db_.transaction_nesting()); 1660 } 1661 1662 TEST_F(AndroidProviderBackendTest, TestAndroidCTSComplianceForZeroVisitCount) { 1663 // This is to verify the last visit time and created time are same when visit 1664 // count is 0. 1665 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1666 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1667 scoped_ptr<AndroidProviderBackend> backend( 1668 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1669 &thumbnail_db_, bookmark_model_, &delegate_)); 1670 URLRow url_row(GURL("http://www.google.com")); 1671 url_row.set_last_visit(Time::Now()); 1672 url_row.set_visit_count(0); 1673 history_db_.AddURL(url_row); 1674 1675 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 1676 1677 projections.push_back(HistoryAndBookmarkRow::ID); 1678 projections.push_back(HistoryAndBookmarkRow::URL); 1679 projections.push_back(HistoryAndBookmarkRow::TITLE); 1680 projections.push_back(HistoryAndBookmarkRow::CREATED); 1681 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 1682 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 1683 projections.push_back(HistoryAndBookmarkRow::FAVICON); 1684 projections.push_back(HistoryAndBookmarkRow::BOOKMARK); 1685 1686 scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks( 1687 projections, std::string(), std::vector<base::string16>(), 1688 std::string("url ASC"))); 1689 1690 ASSERT_TRUE(statement->statement()->Step()); 1691 EXPECT_EQ(ToDatabaseTime(url_row.last_visit()), 1692 statement->statement()->ColumnInt64(3)); 1693 EXPECT_EQ(ToDatabaseTime(url_row.last_visit()), 1694 statement->statement()->ColumnInt64(4)); 1695 EXPECT_EQ(url_row.visit_count(), statement->statement()->ColumnInt(5)); 1696 } 1697 1698 TEST_F(AndroidProviderBackendTest, AndroidCTSComplianceFolderColumnExists) { 1699 // This is test is used to verify the 'folder' column exists, all bookmarks 1700 // returned when folder is 0 and the non bookmark rows returned when folder 1701 // is 1. 1702 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1703 ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_)); 1704 scoped_ptr<AndroidProviderBackend> backend( 1705 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1706 &thumbnail_db_, bookmark_model_, &delegate_)); 1707 HistoryAndBookmarkRow row1; 1708 row1.set_raw_url("cnn.com"); 1709 row1.set_url(GURL("http://cnn.com")); 1710 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1711 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1712 row1.set_visit_count(10); 1713 row1.set_is_bookmark(true); 1714 row1.set_title(UTF8ToUTF16("cnn")); 1715 1716 HistoryAndBookmarkRow row2; 1717 row2.set_raw_url("http://www.example.com"); 1718 row2.set_url(GURL("http://www.example.com")); 1719 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 1720 row2.set_is_bookmark(false); 1721 row2.set_title(UTF8ToUTF16("example")); 1722 std::vector<unsigned char> data; 1723 data.push_back('1'); 1724 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 1725 1726 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 1727 ASSERT_TRUE(id1); 1728 AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2); 1729 ASSERT_TRUE(id2); 1730 content::RunAllPendingInMessageLoop(); 1731 1732 // Query by folder=0, the row1 should returned. 1733 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 1734 1735 projections.push_back(HistoryAndBookmarkRow::URL); 1736 1737 scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks( 1738 projections, std::string("folder=0"), std::vector<base::string16>(), 1739 std::string("url ASC"))); 1740 ASSERT_TRUE(statement->statement()->Step()); 1741 EXPECT_EQ(row1.raw_url(), statement->statement()->ColumnString(0)); 1742 EXPECT_FALSE(statement->statement()->Step()); 1743 1744 // Query by folder=1, the row2 should returned. 1745 statement.reset(backend->QueryHistoryAndBookmarks( 1746 projections, std::string("folder=1"), std::vector<base::string16>(), 1747 std::string("url ASC"))); 1748 ASSERT_TRUE(statement->statement()->Step()); 1749 EXPECT_EQ(row2.url(), GURL(statement->statement()->ColumnString(0))); 1750 EXPECT_FALSE(statement->statement()->Step()); 1751 } 1752 1753 TEST_F(AndroidProviderBackendTest, QueryWithoutThumbnailDB) { 1754 GURL url1("http://www.cnn.com"); 1755 URLID url_id1 = 0; 1756 const base::string16 title1(UTF8ToUTF16("cnn")); 1757 std::vector<VisitInfo> visits1; 1758 Time last_visited1 = Time::Now() - TimeDelta::FromDays(1); 1759 Time created1 = last_visited1 - TimeDelta::FromDays(20); 1760 visits1.push_back(VisitInfo(created1, content::PAGE_TRANSITION_LINK)); 1761 visits1.push_back(VisitInfo(last_visited1 - TimeDelta::FromDays(1), 1762 content::PAGE_TRANSITION_LINK)); 1763 visits1.push_back(VisitInfo(last_visited1, content::PAGE_TRANSITION_LINK)); 1764 1765 GURL url2("http://www.example.com"); 1766 URLID url_id2 = 0; 1767 std::vector<VisitInfo> visits2; 1768 const base::string16 title2(UTF8ToUTF16("example")); 1769 Time last_visited2 = Time::Now(); 1770 Time created2 = last_visited2 - TimeDelta::FromDays(10); 1771 visits2.push_back(VisitInfo(created2, content::PAGE_TRANSITION_LINK)); 1772 visits2.push_back(VisitInfo(last_visited2 - TimeDelta::FromDays(5), 1773 content::PAGE_TRANSITION_LINK)); 1774 visits2.push_back(VisitInfo(last_visited2, content::PAGE_TRANSITION_LINK)); 1775 1776 // Only use the HistoryBackend to generate the test data. 1777 // HistoryBackend will shutdown after that. 1778 { 1779 scoped_refptr<HistoryBackend> history_backend; 1780 history_backend = new HistoryBackend(temp_dir_.path(), 0, 1781 new AndroidProviderBackendDelegate(), bookmark_model_); 1782 history_backend->Init(std::string(), false); 1783 history_backend->AddVisits(url1, visits1, history::SOURCE_SYNCED); 1784 history_backend->AddVisits(url2, visits2, history::SOURCE_SYNCED); 1785 URLRow url_row; 1786 1787 ASSERT_TRUE(history_backend->GetURL(url1, &url_row)); 1788 url_id1 = url_row.id(); 1789 url_row.set_title(title1); 1790 ASSERT_TRUE(history_backend->UpdateURL(url_id1, url_row)); 1791 1792 ASSERT_TRUE(history_backend->GetURL(url2, &url_row)); 1793 url_id2 = url_row.id(); 1794 url_row.set_title(title2); 1795 ASSERT_TRUE(history_backend->UpdateURL(url_id2, url_row)); 1796 1797 // Set favicon to url2. 1798 std::vector<unsigned char> data; 1799 data.push_back('1'); 1800 chrome::FaviconBitmapData bitmap_data_element; 1801 bitmap_data_element.bitmap_data = new base::RefCountedBytes(data); 1802 bitmap_data_element.pixel_size = gfx::Size(); 1803 bitmap_data_element.icon_url = GURL(); 1804 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data; 1805 favicon_bitmap_data.push_back(bitmap_data_element); 1806 1807 history_backend->SetFavicons(url2, chrome::FAVICON, favicon_bitmap_data); 1808 history_backend->Closing(); 1809 } 1810 1811 // The history_db_name and thumbnail_db_name files should be created by 1812 // HistoryBackend. We need to open the same database files. 1813 ASSERT_TRUE(base::PathExists(history_db_name_)); 1814 ASSERT_TRUE(base::PathExists(thumbnail_db_name_)); 1815 1816 // Only creates the history database 1817 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1818 1819 // Set url1 as bookmark. 1820 AddBookmark(url1); 1821 1822 scoped_ptr<AndroidProviderBackend> backend( 1823 new AndroidProviderBackend(android_cache_db_name_, &history_db_, NULL, 1824 bookmark_model_, &delegate_)); 1825 1826 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 1827 1828 projections.push_back(HistoryAndBookmarkRow::ID); 1829 projections.push_back(HistoryAndBookmarkRow::URL); 1830 projections.push_back(HistoryAndBookmarkRow::TITLE); 1831 projections.push_back(HistoryAndBookmarkRow::CREATED); 1832 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 1833 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 1834 projections.push_back(HistoryAndBookmarkRow::FAVICON); 1835 projections.push_back(HistoryAndBookmarkRow::BOOKMARK); 1836 1837 scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks( 1838 projections, std::string(), std::vector<base::string16>(), 1839 std::string("url ASC"))); 1840 ASSERT_TRUE(statement->statement()->Step()); 1841 ASSERT_EQ(url1, GURL(statement->statement()->ColumnString(1))); 1842 EXPECT_EQ(title1, statement->statement()->ColumnString16(2)); 1843 EXPECT_EQ(ToDatabaseTime(created1), 1844 statement->statement()->ColumnInt64(3)); 1845 EXPECT_EQ(ToDatabaseTime(last_visited1), 1846 statement->statement()->ColumnInt64(4)); 1847 EXPECT_EQ(3, statement->statement()->ColumnInt(5)); 1848 EXPECT_EQ(6, statement->favicon_index()); 1849 // No favicon. 1850 EXPECT_EQ(0, statement->statement()->ColumnByteLength(6)); 1851 EXPECT_TRUE(statement->statement()->ColumnBool(7)); 1852 1853 ASSERT_TRUE(statement->statement()->Step()); 1854 EXPECT_EQ(title2, statement->statement()->ColumnString16(2)); 1855 ASSERT_EQ(url2, GURL(statement->statement()->ColumnString(1))); 1856 EXPECT_EQ(ToDatabaseTime(created2), 1857 statement->statement()->ColumnInt64(3)); 1858 EXPECT_EQ(ToDatabaseTime(last_visited2), 1859 statement->statement()->ColumnInt64(4)); 1860 EXPECT_EQ(3, statement->statement()->ColumnInt(5)); 1861 std::vector<unsigned char> favicon2; 1862 EXPECT_EQ(6, statement->favicon_index()); 1863 // No favicon because thumbnail database wasn't initialized. 1864 EXPECT_EQ(0, statement->statement()->ColumnByteLength(6)); 1865 EXPECT_FALSE(statement->statement()->ColumnBool(7)); 1866 1867 // No more row. 1868 EXPECT_FALSE(statement->statement()->Step()); 1869 } 1870 1871 TEST_F(AndroidProviderBackendTest, InsertWithoutThumbnailDB) { 1872 HistoryAndBookmarkRow row1; 1873 row1.set_raw_url("cnn.com"); 1874 row1.set_url(GURL("http://cnn.com")); 1875 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1876 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1877 row1.set_visit_count(10); 1878 row1.set_is_bookmark(true); 1879 row1.set_title(UTF8ToUTF16("cnn")); 1880 1881 HistoryAndBookmarkRow row2; 1882 row2.set_raw_url("http://www.example.com"); 1883 row2.set_url(GURL("http://www.example.com")); 1884 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 1885 row2.set_is_bookmark(false); 1886 row2.set_title(UTF8ToUTF16("example")); 1887 std::vector<unsigned char> data; 1888 data.push_back('1'); 1889 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 1890 1891 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1892 scoped_ptr<AndroidProviderBackend> backend( 1893 new AndroidProviderBackend(android_cache_db_name_, &history_db_, NULL, 1894 bookmark_model_, &delegate_)); 1895 1896 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1897 EXPECT_FALSE(delegate_.deleted_details()); 1898 ASSERT_TRUE(delegate_.modified_details()); 1899 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 1900 EXPECT_EQ(row1.url(), delegate_.modified_details()->changed_urls[0].url()); 1901 EXPECT_EQ(row1.last_visit_time(), 1902 delegate_.modified_details()->changed_urls[0].last_visit()); 1903 EXPECT_EQ(row1.visit_count(), 1904 delegate_.modified_details()->changed_urls[0].visit_count()); 1905 EXPECT_EQ(row1.title(), 1906 delegate_.modified_details()->changed_urls[0].title()); 1907 EXPECT_FALSE(delegate_.favicon_details()); 1908 content::RunAllPendingInMessageLoop(); 1909 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 1910 const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0); 1911 ASSERT_TRUE(child); 1912 EXPECT_EQ(row1.title(), child->GetTitle()); 1913 EXPECT_EQ(row1.url(), child->url()); 1914 1915 delegate_.ResetDetails(); 1916 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 1917 EXPECT_FALSE(delegate_.deleted_details()); 1918 ASSERT_TRUE(delegate_.modified_details()); 1919 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 1920 EXPECT_EQ(row2.url(), delegate_.modified_details()->changed_urls[0].url()); 1921 EXPECT_EQ(row2.last_visit_time(), 1922 delegate_.modified_details()->changed_urls[0].last_visit()); 1923 EXPECT_EQ(row2.title(), 1924 delegate_.modified_details()->changed_urls[0].title()); 1925 // Favicon details is still false because thumbnail database wasn't 1926 // initialized, we ignore any changes of favicon. 1927 ASSERT_FALSE(delegate_.favicon_details()); 1928 } 1929 1930 TEST_F(AndroidProviderBackendTest, DeleteWithoutThumbnailDB) { 1931 HistoryAndBookmarkRow row1; 1932 row1.set_raw_url("cnn.com"); 1933 row1.set_url(GURL("http://cnn.com")); 1934 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 1935 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 1936 row1.set_visit_count(10); 1937 row1.set_is_bookmark(true); 1938 row1.set_title(UTF8ToUTF16("cnn")); 1939 1940 HistoryAndBookmarkRow row2; 1941 row2.set_raw_url("http://www.example.com"); 1942 row2.set_url(GURL("http://www.example.com")); 1943 row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10)); 1944 row2.set_is_bookmark(false); 1945 row2.set_title(UTF8ToUTF16("example")); 1946 std::vector<unsigned char> data; 1947 data.push_back('1'); 1948 row2.set_favicon(base::RefCountedBytes::TakeVector(&data)); 1949 1950 { 1951 HistoryDatabase history_db; 1952 ThumbnailDatabase thumbnail_db; 1953 ASSERT_EQ(sql::INIT_OK, history_db.Init(history_db_name_)); 1954 ASSERT_EQ(sql::INIT_OK, thumbnail_db.Init(thumbnail_db_name_)); 1955 1956 scoped_ptr<AndroidProviderBackend> backend( 1957 new AndroidProviderBackend(android_cache_db_name_, &history_db, 1958 &thumbnail_db, bookmark_model_, &delegate_)); 1959 1960 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1)); 1961 ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2)); 1962 // Verify the row1 has been added in bookmark model. 1963 content::RunAllPendingInMessageLoop(); 1964 ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count()); 1965 const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0); 1966 ASSERT_TRUE(child); 1967 EXPECT_EQ(row1.title(), child->GetTitle()); 1968 EXPECT_EQ(row1.url(), child->url()); 1969 } 1970 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 1971 scoped_ptr<AndroidProviderBackend> backend( 1972 new AndroidProviderBackend(android_cache_db_name_, &history_db_, 1973 NULL, bookmark_model_, &delegate_)); 1974 1975 // Delete all rows. 1976 std::vector<base::string16> args; 1977 int deleted_count = 0; 1978 delegate_.ResetDetails(); 1979 ASSERT_TRUE(backend->DeleteHistoryAndBookmarks("Favicon IS NULL", args, 1980 &deleted_count)); 1981 // All rows were deleted. 1982 EXPECT_EQ(2, deleted_count); 1983 // Verify the rows was removed from bookmark model. 1984 content::RunAllPendingInMessageLoop(); 1985 ASSERT_EQ(0, bookmark_model_->mobile_node()->child_count()); 1986 1987 // Verify notifications 1988 ASSERT_TRUE(delegate_.deleted_details()); 1989 EXPECT_FALSE(delegate_.modified_details()); 1990 EXPECT_EQ(2u, delegate_.deleted_details()->rows.size()); 1991 // No favicon has been deleted. 1992 EXPECT_FALSE(delegate_.favicon_details()); 1993 1994 // No row exists. 1995 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 1996 projections.push_back(HistoryAndBookmarkRow::ID); 1997 projections.push_back(HistoryAndBookmarkRow::URL); 1998 projections.push_back(HistoryAndBookmarkRow::TITLE); 1999 projections.push_back(HistoryAndBookmarkRow::CREATED); 2000 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 2001 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 2002 projections.push_back(HistoryAndBookmarkRow::FAVICON); 2003 projections.push_back(HistoryAndBookmarkRow::BOOKMARK); 2004 2005 scoped_ptr<AndroidStatement> statement1(backend->QueryHistoryAndBookmarks( 2006 projections, std::string(), std::vector<base::string16>(), 2007 std::string("url ASC"))); 2008 ASSERT_FALSE(statement1->statement()->Step()); 2009 } 2010 2011 TEST_F(AndroidProviderBackendTest, UpdateFaviconWithoutThumbnail) { 2012 HistoryAndBookmarkRow row1; 2013 row1.set_raw_url("cnn.com"); 2014 row1.set_url(GURL("http://cnn.com")); 2015 row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1)); 2016 row1.set_created(Time::Now() - TimeDelta::FromDays(20)); 2017 row1.set_visit_count(10); 2018 row1.set_is_bookmark(true); 2019 row1.set_title(UTF8ToUTF16("cnn")); 2020 2021 { 2022 HistoryDatabase history_db; 2023 ThumbnailDatabase thumbnail_db; 2024 ASSERT_EQ(sql::INIT_OK, history_db.Init(history_db_name_)); 2025 ASSERT_EQ(sql::INIT_OK, thumbnail_db.Init(thumbnail_db_name_)); 2026 scoped_ptr<AndroidProviderBackend> backend( 2027 new AndroidProviderBackend(android_cache_db_name_, &history_db, 2028 &thumbnail_db, bookmark_model_, &delegate_)); 2029 2030 AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1); 2031 ASSERT_TRUE(id1); 2032 } 2033 2034 ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_)); 2035 scoped_ptr<AndroidProviderBackend> backend( 2036 new AndroidProviderBackend(android_cache_db_name_, &history_db_, NULL, 2037 bookmark_model_, &delegate_)); 2038 2039 int update_count; 2040 std::vector<base::string16> update_args; 2041 // Update the last visit time to a value greater than current one. 2042 HistoryAndBookmarkRow update_row1; 2043 2044 // Set visit count. 2045 update_row1.set_visit_count(5); 2046 // Set favicon. 2047 std::vector<unsigned char> data; 2048 data.push_back('1'); 2049 update_row1.set_favicon(base::RefCountedBytes::TakeVector(&data)); 2050 update_args.push_back(UTF8ToUTF16(row1.raw_url())); 2051 delegate_.ResetDetails(); 2052 ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?", 2053 update_args, &update_count)); 2054 // Verify notifications. 2055 EXPECT_FALSE(delegate_.deleted_details()); 2056 ASSERT_TRUE(delegate_.modified_details()); 2057 ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size()); 2058 // No favicon will be updated as thumbnail database is missing. 2059 EXPECT_FALSE(delegate_.favicon_details()); 2060 } 2061 2062 } // namespace history 2063