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