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