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