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