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