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, base::string16(), url));
153  }
154
155  bool GetAndroidURLsRows(std::vector<AndroidURLRow>* rows,
156                          AndroidProviderBackend* backend) {
157    sql::Statement statement(backend->db_->GetCachedStatement(SQL_FROM_HERE,
158        "SELECT id, raw_url, url_id FROM android_urls ORDER BY url_id ASC"));
159
160    while (statement.Step()) {
161      AndroidURLRow row;
162      row.id = statement.ColumnInt64(0);
163      row.raw_url = statement.ColumnString(1);
164      row.url_id = statement.ColumnInt64(2);
165      rows->push_back(row);
166    }
167    return true;
168  }
169
170  bool GetBookmarkCacheRows(std::vector<BookmarkCacheRow>* rows,
171                            AndroidProviderBackend* backend) {
172    sql::Statement statement(backend->db_->GetCachedStatement(SQL_FROM_HERE,
173        "SELECT created_time, last_visit_time, url_id, bookmark, favicon_id "
174        "FROM android_cache_db.bookmark_cache ORDER BY url_id ASC"));
175
176    while (statement.Step()) {
177      BookmarkCacheRow row;
178      row.create_time_ = FromDatabaseTime(statement.ColumnInt64(0));
179      row.last_visit_time_ = FromDatabaseTime(statement.ColumnInt64(1));
180      row.url_id_ = statement.ColumnInt64(2);
181      row.bookmark_ = statement.ColumnBool(3);
182      row.favicon_id_ = statement.ColumnInt64(4);
183      rows->push_back(row);
184    }
185    return true;
186  }
187
188  AndroidProviderBackendDelegate delegate_;
189  scoped_refptr<HistoryBackend> history_backend_;
190  HistoryDatabase history_db_;
191  ThumbnailDatabase thumbnail_db_;
192  base::ScopedTempDir temp_dir_;
193  base::FilePath android_cache_db_name_;
194  base::FilePath history_db_name_;
195  base::FilePath thumbnail_db_name_;
196
197  TestingProfileManager profile_manager_;
198  BookmarkModel* bookmark_model_;
199  base::MessageLoopForUI message_loop_;
200  content::TestBrowserThread ui_thread_;
201  content::TestBrowserThread file_thread_;
202
203
204  DISALLOW_COPY_AND_ASSIGN(AndroidProviderBackendTest);
205};
206
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  base::string16 title3(UTF8ToUTF16("bookmark"));
231  ASSERT_TRUE(bookmark_model_->AddURL(bookmark_model_->bookmark_bar_node(), 0,
232                                      title3, url3));
233  // Only use the HistoryBackend to generate the test data.
234  // HistoryBackend will shutdown after that.
235  {
236  scoped_refptr<HistoryBackend> history_backend;
237  history_backend = new HistoryBackend(temp_dir_.path(), 0,
238      new AndroidProviderBackendDelegate(), bookmark_model_);
239  history_backend->Init(std::string(), false);
240  history_backend->AddVisits(url1, visits1, history::SOURCE_SYNCED);
241  history_backend->AddVisits(url2, visits2, history::SOURCE_SYNCED);
242  URLRow url_row;
243
244  ASSERT_TRUE(history_backend->GetURL(url1, &url_row));
245  url_id1 = url_row.id();
246  ASSERT_TRUE(history_backend->GetURL(url2, &url_row));
247  url_id2 = url_row.id();
248
249  // Set favicon to url2.
250  std::vector<unsigned char> data;
251  data.push_back('1');
252  chrome::FaviconBitmapData bitmap_data_element;
253  bitmap_data_element.bitmap_data = new base::RefCountedBytes(data);
254  bitmap_data_element.pixel_size = gfx::Size();
255  bitmap_data_element.icon_url = GURL();
256  std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
257  favicon_bitmap_data.push_back(bitmap_data_element);
258
259  history_backend->SetFavicons(url2, chrome::FAVICON, favicon_bitmap_data);
260  history_backend->Closing();
261  }
262
263  // The history_db_name and thumbnail_db_name files should be created by
264  // HistoryBackend. We need to open the same database files.
265  ASSERT_TRUE(base::PathExists(history_db_name_));
266  ASSERT_TRUE(base::PathExists(thumbnail_db_name_));
267
268  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
269  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
270  // Set url1 as bookmark.
271  AddBookmark(url1);
272  scoped_ptr<AndroidProviderBackend> backend(
273      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
274                                 &thumbnail_db_, bookmark_model_, &delegate_));
275
276  ASSERT_TRUE(backend->EnsureInitializedAndUpdated());
277
278  // First verify that the bookmark which was not in the history has been added
279  // to history database.
280  URLRow url_row;
281  ASSERT_TRUE(history_db_.GetRowForURL(url3, &url_row));
282  URLID url_id3 = url_row.id();
283  ASSERT_EQ(url3, url_row.url());
284  ASSERT_EQ(title3, url_row.title());
285
286  std::vector<AndroidURLRow> android_url_rows;
287  ASSERT_TRUE(GetAndroidURLsRows(&android_url_rows, backend.get()));
288  ASSERT_EQ(3u, android_url_rows.size());
289  std::vector<AndroidURLRow>::iterator i = android_url_rows.begin();
290  EXPECT_EQ(url_id1, i->url_id);
291  EXPECT_EQ(url1.spec(), i->raw_url);
292  i++;
293  EXPECT_EQ(url_id2, i->url_id);
294  EXPECT_EQ(url2.spec(), i->raw_url);
295  i++;
296  EXPECT_EQ(url_id3, i->url_id);
297  EXPECT_EQ(url3.spec(), i->raw_url);
298
299  std::vector<BookmarkCacheRow> bookmark_cache_rows;
300  ASSERT_TRUE(GetBookmarkCacheRows(&bookmark_cache_rows, backend.get()));
301  ASSERT_EQ(3u, bookmark_cache_rows.size());
302  std::vector<BookmarkCacheRow>::const_iterator j = bookmark_cache_rows.begin();
303  EXPECT_EQ(url_id1, j->url_id_);
304  EXPECT_EQ(ToDatabaseTime(last_visited1), ToDatabaseTime(j->last_visit_time_));
305  EXPECT_EQ(ToDatabaseTime(created1), ToDatabaseTime(j->create_time_));
306  EXPECT_EQ(0, j->favicon_id_);
307  EXPECT_TRUE(j->bookmark_);
308  j++;
309  EXPECT_EQ(url_id2, j->url_id_);
310  EXPECT_EQ(ToDatabaseTime(last_visited2), ToDatabaseTime(j->last_visit_time_));
311  EXPECT_EQ(ToDatabaseTime(created2), ToDatabaseTime(j->create_time_));
312  EXPECT_NE(0, j->favicon_id_);
313  EXPECT_FALSE(j->bookmark_);
314
315  // Delete url2 from database.
316  ASSERT_TRUE(history_db_.DeleteURLRow(url_id2));
317  VisitVector visit_rows;
318  ASSERT_TRUE(history_db_.GetMostRecentVisitsForURL(url_id2, 10,
319                                                    &visit_rows));
320  ASSERT_EQ(3u, visit_rows.size());
321  for (VisitVector::const_iterator v = visit_rows.begin();
322       v != visit_rows.end(); v++)
323    history_db_.DeleteVisit(*v);
324
325  backend->UpdateTables();
326
327  android_url_rows.clear();
328  ASSERT_TRUE(GetAndroidURLsRows(&android_url_rows, backend.get()));
329  ASSERT_EQ(2u, android_url_rows.size());
330  i = android_url_rows.begin();
331  EXPECT_EQ(url_id1, i->url_id);
332  EXPECT_EQ(url1.spec(), i->raw_url);
333  ++i;
334  EXPECT_EQ(url_id3, i->url_id);
335  EXPECT_EQ(url3.spec(), i->raw_url);
336
337  bookmark_cache_rows.clear();
338  ASSERT_TRUE(GetBookmarkCacheRows(&bookmark_cache_rows, backend.get()));
339  ASSERT_EQ(2u, bookmark_cache_rows.size());
340  j = bookmark_cache_rows.begin();
341  EXPECT_EQ(url_id1, j->url_id_);
342  EXPECT_EQ(ToDatabaseTime(last_visited1), ToDatabaseTime(j->last_visit_time_));
343  EXPECT_EQ(ToDatabaseTime(created1), ToDatabaseTime(j->create_time_));
344  EXPECT_EQ(0, j->favicon_id_);
345  EXPECT_TRUE(j->bookmark_);
346  ++j;
347  EXPECT_EQ(url_id3, j->url_id_);
348  EXPECT_EQ(base::Time::UnixEpoch(), j->last_visit_time_);
349  EXPECT_EQ(base::Time::UnixEpoch(), j->create_time_);
350  EXPECT_EQ(0, j->favicon_id_);
351  EXPECT_TRUE(j->bookmark_);
352}
353
354TEST_F(AndroidProviderBackendTest, QueryHistoryAndBookmarks) {
355  GURL url1("http://www.cnn.com");
356  URLID url_id1 = 0;
357  const base::string16 title1(UTF8ToUTF16("cnn"));
358  std::vector<VisitInfo> visits1;
359  Time last_visited1 = Time::Now() - TimeDelta::FromDays(1);
360  Time created1 = last_visited1 - TimeDelta::FromDays(20);
361  visits1.push_back(VisitInfo(created1, content::PAGE_TRANSITION_LINK));
362  visits1.push_back(VisitInfo(last_visited1 - TimeDelta::FromDays(1),
363                              content::PAGE_TRANSITION_LINK));
364  visits1.push_back(VisitInfo(last_visited1, content::PAGE_TRANSITION_LINK));
365
366  GURL url2("http://www.example.com");
367  URLID url_id2 = 0;
368  std::vector<VisitInfo> visits2;
369  const base::string16 title2(UTF8ToUTF16("example"));
370  Time last_visited2 = Time::Now();
371  Time created2 = last_visited2 - TimeDelta::FromDays(10);
372  visits2.push_back(VisitInfo(created2, content::PAGE_TRANSITION_LINK));
373  visits2.push_back(VisitInfo(last_visited2 - TimeDelta::FromDays(5),
374                              content::PAGE_TRANSITION_LINK));
375  visits2.push_back(VisitInfo(last_visited2, content::PAGE_TRANSITION_LINK));
376
377  // Only use the HistoryBackend to generate the test data.
378  // HistoryBackend will shutdown after that.
379  {
380  scoped_refptr<HistoryBackend> history_backend;
381  history_backend = new HistoryBackend(temp_dir_.path(), 0,
382      new AndroidProviderBackendDelegate(), bookmark_model_);
383  history_backend->Init(std::string(), false);
384  history_backend->AddVisits(url1, visits1, history::SOURCE_SYNCED);
385  history_backend->AddVisits(url2, visits2, history::SOURCE_SYNCED);
386  URLRow url_row;
387
388  ASSERT_TRUE(history_backend->GetURL(url1, &url_row));
389  url_id1 = url_row.id();
390  url_row.set_title(title1);
391  ASSERT_TRUE(history_backend->UpdateURL(url_id1, url_row));
392
393  ASSERT_TRUE(history_backend->GetURL(url2, &url_row));
394  url_id2 = url_row.id();
395  url_row.set_title(title2);
396  ASSERT_TRUE(history_backend->UpdateURL(url_id2, url_row));
397
398  // Set favicon to url2.
399  std::vector<unsigned char> data;
400  data.push_back('1');
401  chrome::FaviconBitmapData bitmap_data_element;
402  bitmap_data_element.bitmap_data = new base::RefCountedBytes(data);
403  bitmap_data_element.pixel_size = gfx::Size();
404  bitmap_data_element.icon_url = GURL();
405  std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
406  favicon_bitmap_data.push_back(bitmap_data_element);
407
408  history_backend->SetFavicons(url2, chrome::FAVICON, favicon_bitmap_data);
409  history_backend->Closing();
410  }
411
412  // The history_db_name and thumbnail_db_name files should be created by
413  // HistoryBackend. We need to open the same database files.
414  ASSERT_TRUE(base::PathExists(history_db_name_));
415  ASSERT_TRUE(base::PathExists(thumbnail_db_name_));
416
417  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
418  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
419  // Set url1 as bookmark.
420  AddBookmark(url1);
421
422  scoped_ptr<AndroidProviderBackend> backend(
423      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
424                                 &thumbnail_db_, bookmark_model_, &delegate_));
425
426  std::vector<HistoryAndBookmarkRow::ColumnID> projections;
427
428  projections.push_back(HistoryAndBookmarkRow::ID);
429  projections.push_back(HistoryAndBookmarkRow::URL);
430  projections.push_back(HistoryAndBookmarkRow::TITLE);
431  projections.push_back(HistoryAndBookmarkRow::CREATED);
432  projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME);
433  projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT);
434  projections.push_back(HistoryAndBookmarkRow::FAVICON);
435  projections.push_back(HistoryAndBookmarkRow::BOOKMARK);
436
437  scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks(
438      projections, std::string(), std::vector<base::string16>(),
439      std::string("url ASC")));
440  ASSERT_TRUE(statement->statement()->Step());
441  ASSERT_EQ(url1, GURL(statement->statement()->ColumnString(1)));
442  EXPECT_EQ(title1, statement->statement()->ColumnString16(2));
443  EXPECT_EQ(ToDatabaseTime(created1),
444            statement->statement()->ColumnInt64(3));
445  EXPECT_EQ(ToDatabaseTime(last_visited1),
446            statement->statement()->ColumnInt64(4));
447  EXPECT_EQ(3, statement->statement()->ColumnInt(5));
448  EXPECT_EQ(6, statement->favicon_index());
449  // No favicon.
450  EXPECT_EQ(0, statement->statement()->ColumnByteLength(6));
451  EXPECT_TRUE(statement->statement()->ColumnBool(7));
452
453  ASSERT_TRUE(statement->statement()->Step());
454  EXPECT_EQ(title2, statement->statement()->ColumnString16(2));
455  ASSERT_EQ(url2, GURL(statement->statement()->ColumnString(1)));
456  EXPECT_EQ(ToDatabaseTime(created2),
457            statement->statement()->ColumnInt64(3));
458  EXPECT_EQ(ToDatabaseTime(last_visited2),
459            statement->statement()->ColumnInt64(4));
460  EXPECT_EQ(3, statement->statement()->ColumnInt(5));
461  std::vector<unsigned char> favicon2;
462  EXPECT_EQ(6, statement->favicon_index());
463  // Has favicon.
464  EXPECT_NE(0, statement->statement()->ColumnByteLength(6));
465  EXPECT_FALSE(statement->statement()->ColumnBool(7));
466
467  // No more row.
468  EXPECT_FALSE(statement->statement()->Step());
469
470  // Query by bookmark
471  statement.reset(backend->QueryHistoryAndBookmarks(projections, "bookmark=1",
472      std::vector<base::string16>(), std::string("url ASC")));
473  // Only URL1 is returned.
474  ASSERT_TRUE(statement->statement()->Step());
475  ASSERT_EQ(url1, GURL(statement->statement()->ColumnString(1)));
476  EXPECT_FALSE(statement->statement()->Step());
477
478  statement.reset(backend->QueryHistoryAndBookmarks(projections, "bookmark=0",
479      std::vector<base::string16>(), std::string("url ASC")));
480  // Only URL2 is returned.
481  ASSERT_TRUE(statement->statement()->Step());
482  ASSERT_EQ(url2, GURL(statement->statement()->ColumnString(1)));
483  EXPECT_FALSE(statement->statement()->Step());
484}
485
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<base::string16>(),
558      std::string("url ASC")));
559  ASSERT_TRUE(statement->statement()->Step());
560  ASSERT_EQ(row1.raw_url(), statement->statement()->ColumnString(1));
561  EXPECT_EQ(row1.title(), statement->statement()->ColumnString16(2));
562  EXPECT_EQ(ToDatabaseTime(row1.created()),
563            statement->statement()->ColumnInt64(3));
564  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
565            statement->statement()->ColumnInt64(4));
566  EXPECT_EQ(row1.visit_count(), statement->statement()->ColumnInt(5));
567  EXPECT_EQ(6, statement->favicon_index());
568  // No favicon.
569  EXPECT_EQ(0, statement->statement()->ColumnByteLength(6));
570
571  // TODO: Find a way to test the bookmark was added in BookmarkModel.
572  // The bookmark was added in UI thread, there is no good way to test it.
573  EXPECT_TRUE(statement->statement()->ColumnBool(7));
574
575  ASSERT_TRUE(statement->statement()->Step());
576  EXPECT_EQ(row2.title(), statement->statement()->ColumnString16(2));
577  EXPECT_EQ(row2.url(), GURL(statement->statement()->ColumnString(1)));
578  EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()),
579            statement->statement()->ColumnInt64(3));
580  EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()),
581            statement->statement()->ColumnInt64(4));
582  EXPECT_EQ(1, statement->statement()->ColumnInt(5));
583  EXPECT_EQ(6, statement->favicon_index());
584  // Has favicon.
585  EXPECT_NE(0, statement->statement()->ColumnByteLength(6));
586  // TODO: Find a way to test the bookmark was added in BookmarkModel.
587  // The bookmark was added in UI thread, there is no good way to test it.
588  EXPECT_FALSE(statement->statement()->ColumnBool(7));
589
590  // No more row.
591  EXPECT_FALSE(statement->statement()->Step());
592}
593
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<base::string16> args;
633  int deleted_count = 0;
634  delegate_.ResetDetails();
635  ASSERT_TRUE(backend->DeleteHistoryAndBookmarks("Favicon IS NULL", args,
636                                                 &deleted_count));
637  EXPECT_EQ(1, deleted_count);
638  // Verify the row1 was removed from bookmark model.
639  content::RunAllPendingInMessageLoop();
640  ASSERT_EQ(0, bookmark_model_->mobile_node()->child_count());
641
642  // Verify notifications
643  ASSERT_TRUE(delegate_.deleted_details());
644  EXPECT_FALSE(delegate_.modified_details());
645  EXPECT_EQ(1u, delegate_.deleted_details()->rows.size());
646  EXPECT_EQ(row1.url(), delegate_.deleted_details()->rows[0].url());
647  EXPECT_EQ(row1.last_visit_time(),
648            delegate_.deleted_details()->rows[0].last_visit());
649  EXPECT_EQ(row1.title(),
650            delegate_.deleted_details()->rows[0].title());
651  EXPECT_FALSE(delegate_.favicon_details());
652
653  std::vector<HistoryAndBookmarkRow::ColumnID> projections;
654  projections.push_back(HistoryAndBookmarkRow::ID);
655  projections.push_back(HistoryAndBookmarkRow::URL);
656  projections.push_back(HistoryAndBookmarkRow::TITLE);
657  projections.push_back(HistoryAndBookmarkRow::CREATED);
658  projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME);
659  projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT);
660  projections.push_back(HistoryAndBookmarkRow::FAVICON);
661  projections.push_back(HistoryAndBookmarkRow::BOOKMARK);
662
663  scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks(
664      projections, std::string(), std::vector<base::string16>(),
665      std::string("url ASC")));
666  ASSERT_TRUE(statement->statement()->Step());
667
668  EXPECT_EQ(row2.title(), statement->statement()->ColumnString16(2));
669  EXPECT_EQ(row2.url(), GURL(statement->statement()->ColumnString(1)));
670  EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()),
671            statement->statement()->ColumnInt64(3));
672  EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()),
673            statement->statement()->ColumnInt64(4));
674  EXPECT_EQ(1, statement->statement()->ColumnInt(5));
675  EXPECT_EQ(6, statement->favicon_index());
676  // Has favicon.
677  EXPECT_NE(0, statement->statement()->ColumnByteLength(6));
678  // TODO: Find a way to test the bookmark was added in BookmarkModel.
679  // The bookmark was added in UI thread, there is no good way to test it.
680  EXPECT_FALSE(statement->statement()->ColumnBool(7));
681  // No more row.
682  EXPECT_FALSE(statement->statement()->Step());
683
684  deleted_count = 0;
685  // Delete row2.
686  delegate_.ResetDetails();
687  ASSERT_TRUE(backend->DeleteHistoryAndBookmarks("bookmark = 0",
688                  std::vector<base::string16>(), &deleted_count));
689  // Verify notifications
690  ASSERT_TRUE(delegate_.deleted_details());
691  EXPECT_FALSE(delegate_.modified_details());
692  EXPECT_EQ(1u, delegate_.deleted_details()->rows.size());
693  EXPECT_EQ(row2.url(), delegate_.deleted_details()->rows[0].url());
694  EXPECT_EQ(row2.last_visit_time(),
695            delegate_.deleted_details()->rows[0].last_visit());
696  EXPECT_EQ(row2.title(),
697            delegate_.deleted_details()->rows[0].title());
698  ASSERT_TRUE(delegate_.favicon_details());
699  ASSERT_EQ(1u, delegate_.favicon_details()->urls.size());
700  ASSERT_TRUE(delegate_.favicon_details()->urls.end() !=
701              delegate_.favicon_details()->urls.find(row2.url()));
702
703  ASSERT_EQ(1, deleted_count);
704  scoped_ptr<AndroidStatement> statement1(backend->QueryHistoryAndBookmarks(
705      projections, std::string(), std::vector<base::string16>(),
706      std::string("url ASC")));
707  ASSERT_FALSE(statement1->statement()->Step());
708}
709
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<base::string16> update_args;
836  // Try to update the mutiple rows with the same URL, this should failed.
837  HistoryAndBookmarkRow update_row1;
838  update_row1.set_raw_url("newwebiste.com");
839  update_row1.set_url(GURL("http://newwebsite.com"));
840  update_args.clear();
841  ASSERT_FALSE(backend->UpdateHistoryAndBookmarks(update_row1, std::string(),
842                                                  update_args, &update_count));
843
844  // Only update one URL.
845  update_args.clear();
846  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
847  delegate_.ResetDetails();
848  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?",
849                                                 update_args, &update_count));
850  // Verify notifications, Update involves insert and delete URLS.
851  ASSERT_TRUE(delegate_.deleted_details());
852  EXPECT_EQ(1u, delegate_.deleted_details()->rows.size());
853  EXPECT_EQ(row1.url(), delegate_.deleted_details()->rows[0].url());
854  EXPECT_EQ(row1.last_visit_time(),
855            delegate_.deleted_details()->rows[0].last_visit());
856  EXPECT_EQ(row1.title(),
857            delegate_.deleted_details()->rows[0].title());
858  ASSERT_TRUE(delegate_.modified_details());
859  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
860  EXPECT_EQ(update_row1.url(),
861            delegate_.modified_details()->changed_urls[0].url());
862  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
863            ToDatabaseTime(
864                delegate_.modified_details()->changed_urls[0].last_visit()));
865  EXPECT_EQ(row1.title(),
866            delegate_.modified_details()->changed_urls[0].title());
867  EXPECT_FALSE(delegate_.favicon_details());
868
869  EXPECT_EQ(1, update_count);
870  // We shouldn't find orignal url anymore.
871  EXPECT_FALSE(history_db_.GetRowForURL(row1.url(), NULL));
872  visits.clear();
873  EXPECT_TRUE(history_db_.GetVisitsForURL(url_id1, &visits));
874  EXPECT_EQ(0u, visits.size());
875  // Verify new URL.
876  URLRow new_row;
877  EXPECT_TRUE(history_db_.GetRowForURL(update_row1.url(), &new_row));
878  EXPECT_EQ(10, new_row.visit_count());
879  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
880            ToDatabaseTime(new_row.last_visit()));
881  visits.clear();
882  EXPECT_TRUE(history_db_.GetVisitsForURL(new_row.id(), &visits));
883  EXPECT_EQ(10u, visits.size());
884  AndroidURLRow android_url_row1;
885  ASSERT_TRUE(history_db_.GetAndroidURLRow(new_row.id(), &android_url_row1));
886  // Android URL ID shouldn't change.
887  EXPECT_EQ(id1, android_url_row1.id);
888
889  // Verify the bookmark model was updated.
890  content::RunAllPendingInMessageLoop();
891  ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count());
892  const BookmarkNode* child1 = bookmark_model_->mobile_node()->GetChild(0);
893  ASSERT_TRUE(child1);
894  EXPECT_EQ(row1.title(), child1->GetTitle());
895  EXPECT_EQ(update_row1.url(), child1->url());
896
897  // Update the URL with visit count, created time, and last visit time.
898  HistoryAndBookmarkRow update_row2;
899  update_row2.set_raw_url("somethingelse.com");
900  update_row2.set_url(GURL("http://somethingelse.com"));
901  update_row2.set_last_visit_time(Time::Now());
902  update_row2.set_created(Time::Now() - TimeDelta::FromDays(20));
903  update_row2.set_visit_count(10);
904
905  update_args.clear();
906  update_args.push_back(UTF8ToUTF16(row2.raw_url()));
907  delegate_.ResetDetails();
908  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row2, "url = ?",
909                                                 update_args, &update_count));
910  // Verify notifications, Update involves insert and delete URLS.
911  ASSERT_TRUE(delegate_.deleted_details());
912  EXPECT_EQ(1u, delegate_.deleted_details()->rows.size());
913  EXPECT_EQ(row2.url(), delegate_.deleted_details()->rows[0].url());
914  EXPECT_EQ(row2.last_visit_time(),
915            delegate_.deleted_details()->rows[0].last_visit());
916  EXPECT_EQ(row2.title(),
917            delegate_.deleted_details()->rows[0].title());
918  ASSERT_TRUE(delegate_.modified_details());
919  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
920  EXPECT_EQ(update_row2.url(),
921            delegate_.modified_details()->changed_urls[0].url());
922  EXPECT_EQ(ToDatabaseTime(update_row2.last_visit_time()),
923            ToDatabaseTime(
924                delegate_.modified_details()->changed_urls[0].last_visit()));
925  EXPECT_EQ(update_row2.visit_count(),
926            delegate_.modified_details()->changed_urls[0].visit_count());
927  ASSERT_TRUE(delegate_.favicon_details());
928  ASSERT_EQ(2u, delegate_.favicon_details()->urls.size());
929  ASSERT_TRUE(delegate_.favicon_details()->urls.end() !=
930              delegate_.favicon_details()->urls.find(row2.url()));
931  ASSERT_TRUE(delegate_.favicon_details()->urls.end() !=
932              delegate_.favicon_details()->urls.find(update_row2.url()));
933
934  EXPECT_EQ(1, update_count);
935  // We shouldn't find orignal url anymore.
936  EXPECT_FALSE(history_db_.GetRowForURL(row2.url(), NULL));
937  visits.clear();
938  EXPECT_TRUE(history_db_.GetVisitsForURL(url_id2, &visits));
939  EXPECT_EQ(0u, visits.size());
940
941  // Verify new URL.
942  URLRow new_row2;
943  ASSERT_TRUE(history_db_.GetRowForURL(update_row2.url(), &new_row2));
944  EXPECT_EQ(10, new_row2.visit_count());
945  EXPECT_EQ(update_row2.last_visit_time(), new_row2.last_visit());
946  visits.clear();
947  EXPECT_TRUE(history_db_.GetVisitsForURL(new_row2.id(), &visits));
948  EXPECT_EQ(10u, visits.size());
949  AndroidURLRow android_url_row2;
950  ASSERT_TRUE(history_db_.GetAndroidURLRow(new_row2.id(), &android_url_row2));
951  // Android URL ID shouldn't change.
952  EXPECT_EQ(id2, android_url_row2.id);
953
954  ASSERT_TRUE(history_db_.GetVisitsForURL(new_row2.id(), &visits));
955  ASSERT_EQ(10u, visits.size());
956  EXPECT_EQ(update_row2.created(), visits[0].visit_time);
957  EXPECT_EQ(update_row2.last_visit_time(), visits[9].visit_time);
958}
959
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<base::string16> update_args;
993  // Update the visit_count to a value less than current one.
994  HistoryAndBookmarkRow update_row1;
995  update_row1.set_visit_count(5);
996  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
997  delegate_.ResetDetails();
998  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?",
999                                                 update_args, &update_count));
1000  // Verify notifications, Update involves modified URL.
1001  EXPECT_FALSE(delegate_.deleted_details());
1002  ASSERT_TRUE(delegate_.modified_details());
1003  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
1004  EXPECT_EQ(row1.url(),
1005            delegate_.modified_details()->changed_urls[0].url());
1006  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
1007            ToDatabaseTime(
1008                delegate_.modified_details()->changed_urls[0].last_visit()));
1009  EXPECT_EQ(update_row1.visit_count(),
1010            delegate_.modified_details()->changed_urls[0].visit_count());
1011  EXPECT_FALSE(delegate_.favicon_details());
1012
1013  // All visits should be removed, and 5 new visit insertted.
1014  URLRow new_row1;
1015  ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), &new_row1));
1016  EXPECT_EQ(5, new_row1.visit_count());
1017  VisitVector visits;
1018  ASSERT_TRUE(history_db_.GetVisitsForURL(new_row1.id(), &visits));
1019  ASSERT_EQ(5u, visits.size());
1020  EXPECT_EQ(row1.last_visit_time(), visits[4].visit_time);
1021  EXPECT_GT(row1.last_visit_time(), visits[0].visit_time);
1022
1023  // Update the visit_count to a value equal to current one.
1024  HistoryAndBookmarkRow update_row2;
1025  update_row2.set_visit_count(1);
1026  update_args.clear();
1027  update_args.push_back(UTF8ToUTF16(row2.raw_url()));
1028  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row2, "url = ?",
1029                                                 update_args, &update_count));
1030  // All shouldn't have any change.
1031  URLRow new_row2;
1032  ASSERT_TRUE(history_db_.GetRowForURL(row2.url(), &new_row2));
1033  EXPECT_EQ(1, new_row2.visit_count());
1034
1035  ASSERT_TRUE(history_db_.GetVisitsForURL(new_row2.id(), &visits));
1036  ASSERT_EQ(1u, visits.size());
1037  EXPECT_EQ(row2.last_visit_time(), visits[0].visit_time);
1038}
1039
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<base::string16> update_args;
1073  // Update the last visit time to a value greater than current one.
1074  HistoryAndBookmarkRow update_row1;
1075  update_row1.set_last_visit_time(Time::Now());
1076  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
1077  delegate_.ResetDetails();
1078  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?",
1079                                                 update_args, &update_count));
1080  // Verify notifications, Update involves modified URL.
1081  EXPECT_FALSE(delegate_.deleted_details());
1082  ASSERT_TRUE(delegate_.modified_details());
1083  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
1084  EXPECT_EQ(row1.url(),
1085            delegate_.modified_details()->changed_urls[0].url());
1086  EXPECT_EQ(ToDatabaseTime(update_row1.last_visit_time()),
1087            ToDatabaseTime(
1088                delegate_.modified_details()->changed_urls[0].last_visit()));
1089  EXPECT_FALSE(delegate_.favicon_details());
1090
1091  URLRow new_row1;
1092  ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), &new_row1));
1093  EXPECT_EQ(11, new_row1.visit_count());
1094  EXPECT_EQ(update_row1.last_visit_time(), new_row1.last_visit());
1095  VisitVector visits;
1096  ASSERT_TRUE(history_db_.GetVisitsForURL(new_row1.id(), &visits));
1097  // 1 new visit insertted.
1098  ASSERT_EQ(11u, visits.size());
1099  EXPECT_EQ(update_row1.last_visit_time(), visits[10].visit_time);
1100  EXPECT_EQ(row1.last_visit_time(), visits[9].visit_time);
1101
1102  // Update the visit_tim to a value less than to current one.
1103  HistoryAndBookmarkRow update_row2;
1104  update_row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1105  update_args.clear();
1106  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
1107  ASSERT_FALSE(backend->UpdateHistoryAndBookmarks(update_row2, "url = ?",
1108                                                  update_args, &update_count));
1109}
1110
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<base::string16> update_args;
1132  // Update the last visit time to a value greater than current one.
1133  HistoryAndBookmarkRow update_row1;
1134
1135  // Set favicon.
1136  std::vector<unsigned char> data;
1137  data.push_back('1');
1138  update_row1.set_favicon(base::RefCountedBytes::TakeVector(&data));
1139  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
1140  delegate_.ResetDetails();
1141  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?",
1142                                                 update_args, &update_count));
1143  // Verify notifications.
1144  EXPECT_FALSE(delegate_.deleted_details());
1145  EXPECT_FALSE(delegate_.modified_details());
1146  ASSERT_TRUE(delegate_.favicon_details());
1147  ASSERT_EQ(1u, delegate_.favicon_details()->urls.size());
1148  ASSERT_TRUE(delegate_.favicon_details()->urls.end() !=
1149              delegate_.favicon_details()->urls.find(row1.url()));
1150
1151  std::vector<IconMapping> icon_mappings;
1152  EXPECT_TRUE(thumbnail_db_.GetIconMappingsForPageURL(
1153      row1.url(), chrome::FAVICON, &icon_mappings));
1154  EXPECT_EQ(1u, icon_mappings.size());
1155  std::vector<FaviconBitmap> favicon_bitmaps;
1156  EXPECT_TRUE(thumbnail_db_.GetFaviconBitmaps(icon_mappings[0].icon_id,
1157                                              &favicon_bitmaps));
1158  EXPECT_EQ(1u, favicon_bitmaps.size());
1159  EXPECT_TRUE(favicon_bitmaps[0].bitmap_data.get());
1160  EXPECT_EQ(1u, favicon_bitmaps[0].bitmap_data->size());
1161  EXPECT_EQ('1', *favicon_bitmaps[0].bitmap_data->front());
1162
1163  // Remove favicon.
1164  HistoryAndBookmarkRow update_row2;
1165
1166  // Set favicon.
1167  update_row1.set_favicon(new base::RefCountedBytes());
1168  update_args.clear();
1169  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
1170  delegate_.ResetDetails();
1171  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?",
1172                                                 update_args, &update_count));
1173  // Verify notifications.
1174  EXPECT_FALSE(delegate_.deleted_details());
1175  EXPECT_FALSE(delegate_.modified_details());
1176  ASSERT_TRUE(delegate_.favicon_details());
1177  ASSERT_EQ(1u, delegate_.favicon_details()->urls.size());
1178  ASSERT_TRUE(delegate_.favicon_details()->urls.end() !=
1179              delegate_.favicon_details()->urls.find(row1.url()));
1180
1181  EXPECT_FALSE(thumbnail_db_.GetIconMappingsForPageURL(
1182      row1.url(), chrome::FAVICON, NULL));
1183}
1184
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  base::string16 term = UTF8ToUTF16("Search term 1");
1199  URLID url_id = history_db_.GetRowForURL(row1.url(), NULL);
1200  ASSERT_TRUE(url_id);
1201  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term));
1202  ASSERT_TRUE(backend->UpdateSearchTermTable());
1203  SearchTermRow keyword_cache;
1204  SearchTermID id = history_db_.GetSearchTerm(term, &keyword_cache);
1205  ASSERT_TRUE(id);
1206  EXPECT_EQ(term, keyword_cache.term);
1207  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
1208            ToDatabaseTime(keyword_cache.last_visit_time));
1209
1210  // Add another row.
1211  HistoryAndBookmarkRow row2;
1212  row2.set_raw_url("google.com");
1213  row2.set_url(GURL("http://google.com"));
1214  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(2));
1215  row2.set_title(UTF8ToUTF16("cnn"));
1216  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2));
1217  url_id = history_db_.GetRowForURL(row2.url(), NULL);
1218  ASSERT_TRUE(url_id);
1219  base::string16 term2 = UTF8ToUTF16("Search term 2");
1220  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term2));
1221  ASSERT_TRUE(backend->UpdateSearchTermTable());
1222  SearchTermID search_id1 = history_db_.GetSearchTerm(term,
1223                                                           &keyword_cache);
1224  // The id shouldn't changed.
1225  ASSERT_EQ(id, search_id1);
1226  EXPECT_EQ(term, keyword_cache.term);
1227  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
1228            ToDatabaseTime(keyword_cache.last_visit_time));
1229  // Verify the row just inserted.
1230  SearchTermID id2 = history_db_.GetSearchTerm(term2, &keyword_cache);
1231  ASSERT_TRUE(id2);
1232  EXPECT_EQ(term2, keyword_cache.term);
1233  EXPECT_EQ(ToDatabaseTime(row2.last_visit_time()),
1234            ToDatabaseTime(keyword_cache.last_visit_time));
1235
1236  // Add 3rd row and associate it with term.
1237  HistoryAndBookmarkRow row3;
1238  row3.set_raw_url("search.com");
1239  row3.set_url(GURL("http://search.com"));
1240  row3.set_last_visit_time(Time::Now());
1241  row3.set_title(UTF8ToUTF16("search"));
1242  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row3));
1243  url_id = history_db_.GetRowForURL(row3.url(), NULL);
1244  ASSERT_TRUE(url_id);
1245  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term));
1246  ASSERT_TRUE(backend->UpdateSearchTermTable());
1247  // Verify id not changed and last_visit_time updated.
1248  ASSERT_EQ(search_id1, history_db_.GetSearchTerm(term, &keyword_cache));
1249  EXPECT_EQ(ToDatabaseTime(row3.last_visit_time()),
1250            ToDatabaseTime(keyword_cache.last_visit_time));
1251  // The id of term2 wasn't changed.
1252  EXPECT_EQ(id2, history_db_.GetSearchTerm(term2, NULL));
1253
1254  // Remove the term.
1255  ASSERT_TRUE(history_db_.DeleteKeywordSearchTerm(term));
1256  ASSERT_TRUE(backend->UpdateSearchTermTable());
1257  // The cache of term should removed.
1258  ASSERT_FALSE(history_db_.GetSearchTerm(term, NULL));
1259  // The id of term2 wasn't changed.
1260  EXPECT_EQ(id2, history_db_.GetSearchTerm(term2, NULL));
1261}
1262
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  base::string16 term = UTF8ToUTF16("Search term 1");
1277  URLID url_id = history_db_.GetRowForURL(row1.url(), NULL);
1278  ASSERT_TRUE(url_id);
1279  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term));
1280
1281  std::vector<SearchRow::ColumnID> projections;
1282  projections.push_back(SearchRow::ID);
1283  projections.push_back(SearchRow::SEARCH_TERM);
1284  projections.push_back(SearchRow::SEARCH_TIME);
1285  scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms(
1286      projections, std::string(), std::vector<base::string16>(),
1287      std::string()));
1288  ASSERT_TRUE(statement.get());
1289  ASSERT_TRUE(statement->statement()->Step());
1290  EXPECT_TRUE(statement->statement()->ColumnInt64(0));
1291  EXPECT_EQ(term, statement->statement()->ColumnString16(1));
1292  EXPECT_EQ(ToDatabaseTime(row1.last_visit_time()),
1293            statement->statement()->ColumnInt64(2));
1294  EXPECT_FALSE(statement->statement()->Step());
1295}
1296
1297TEST_F(AndroidProviderBackendTest, UpdateSearchTerms) {
1298  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1299  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1300  scoped_ptr<AndroidProviderBackend> backend(
1301      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1302                                 &thumbnail_db_, bookmark_model_, &delegate_));
1303  // Insert a keyword.
1304  HistoryAndBookmarkRow row1;
1305  row1.set_raw_url("cnn.com");
1306  row1.set_url(GURL("http://cnn.com"));
1307  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1308  row1.set_title(UTF8ToUTF16("cnn"));
1309  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1));
1310  base::string16 term = UTF8ToUTF16("Search term 1");
1311  URLID url_id = history_db_.GetRowForURL(row1.url(), NULL);
1312  ASSERT_TRUE(url_id);
1313  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term));
1314
1315  // Get the SearchTermID of the row we just inserted.
1316  std::vector<SearchRow::ColumnID> projections;
1317  projections.push_back(SearchRow::ID);
1318  projections.push_back(SearchRow::SEARCH_TIME);
1319  projections.push_back(SearchRow::SEARCH_TERM);
1320  std::vector<base::string16> args;
1321  args.push_back(term);
1322  scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms(
1323      projections, "search = ?", args, std::string()));
1324  ASSERT_TRUE(statement.get());
1325  ASSERT_TRUE(statement->statement()->Step());
1326  SearchTermID id = statement->statement()->ColumnInt64(0);
1327  ASSERT_TRUE(id);
1328  EXPECT_FALSE(statement->statement()->Step());
1329
1330  // Update the search term and time.
1331  base::string16 update_term = UTF8ToUTF16("Update search term");
1332  args.clear();
1333  args.push_back(term);
1334  SearchRow search_row;
1335  search_row.set_search_term(update_term);
1336  search_row.set_url(GURL("http://google.com"));
1337  search_row.set_template_url_id(1);
1338  search_row.set_search_time(Time::Now() - TimeDelta::FromHours(1));
1339  int update_count = 0;
1340  ASSERT_TRUE(backend->UpdateSearchTerms(search_row, "search = ?", args,
1341                                         &update_count));
1342  EXPECT_EQ(1, update_count);
1343
1344  // Verify if the search term updated.
1345  // The origin term should be removed.
1346  std::vector<KeywordSearchTermRow> rows;
1347  ASSERT_TRUE(history_db_.GetKeywordSearchTermRows(term, &rows));
1348  EXPECT_TRUE(rows.empty());
1349  // The new term should be inserted.
1350  ASSERT_TRUE(history_db_.GetKeywordSearchTermRows(update_term, &rows));
1351  ASSERT_EQ(1u, rows.size());
1352  // The history of urls shouldn't be removed.
1353  ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), NULL));
1354  // The new URL is inserted.
1355  ASSERT_TRUE(history_db_.GetRowForURL(search_row.url(), NULL));
1356
1357  // Verfiy the AndoridSearchID isn't changed.
1358  args.clear();
1359  args.push_back(update_term);
1360  statement.reset(backend->QuerySearchTerms(projections, "search = ?", args,
1361                                            std::string()));
1362  ASSERT_TRUE(statement.get());
1363  ASSERT_TRUE(statement->statement()->Step());
1364  // The id didn't change.
1365  EXPECT_EQ(id, statement->statement()->ColumnInt64(0));
1366  // The search time was updated.
1367  EXPECT_EQ(ToDatabaseTime(search_row.search_time()),
1368            statement->statement()->ColumnInt64(1));
1369  // The search term was updated.
1370  EXPECT_EQ(update_term, statement->statement()->ColumnString16(2));
1371  EXPECT_FALSE(statement->statement()->Step());
1372
1373  // Only update the search time.
1374  SearchRow update_time;
1375  update_time.set_search_time(Time::Now());
1376  // Update it by id.
1377  args.clear();
1378  std::ostringstream oss;
1379  oss << id;
1380  args.push_back(UTF8ToUTF16(oss.str()));
1381  update_count = 0;
1382  ASSERT_TRUE(backend->UpdateSearchTerms(update_time, "_id = ?", args,
1383                                         &update_count));
1384  EXPECT_EQ(1, update_count);
1385
1386  // Verify the update.
1387  statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args,
1388                                            std::string()));
1389  ASSERT_TRUE(statement.get());
1390  ASSERT_TRUE(statement->statement()->Step());
1391  // The id didn't change.
1392  EXPECT_EQ(id, statement->statement()->ColumnInt64(0));
1393  // The search time was updated.
1394  EXPECT_EQ(ToDatabaseTime(update_time.search_time()),
1395            statement->statement()->ColumnInt64(1));
1396  // The search term didn't change.
1397  EXPECT_EQ(update_term, statement->statement()->ColumnString16(2));
1398  EXPECT_FALSE(statement->statement()->Step());
1399}
1400
1401TEST_F(AndroidProviderBackendTest, DeleteSearchTerms) {
1402  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1403  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1404  scoped_ptr<AndroidProviderBackend> backend(
1405      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1406                                 &thumbnail_db_, bookmark_model_, &delegate_));
1407  // Insert a keyword.
1408  HistoryAndBookmarkRow row1;
1409  row1.set_raw_url("cnn.com");
1410  row1.set_url(GURL("http://cnn.com"));
1411  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1412  row1.set_title(UTF8ToUTF16("cnn"));
1413  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1));
1414  base::string16 term = UTF8ToUTF16("Search term 1");
1415  URLID url_id = history_db_.GetRowForURL(row1.url(), NULL);
1416  ASSERT_TRUE(url_id);
1417  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id, 1, term));
1418
1419  // Get the SearchTermID of the row we just inserted.
1420  std::vector<SearchRow::ColumnID> projections;
1421  projections.push_back(SearchRow::ID);
1422  projections.push_back(SearchRow::SEARCH_TIME);
1423  projections.push_back(SearchRow::SEARCH_TERM);
1424  std::vector<base::string16> args;
1425  args.push_back(term);
1426  scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms(
1427      projections, "search = ?", args, std::string()));
1428  ASSERT_TRUE(statement.get());
1429  ASSERT_TRUE(statement->statement()->Step());
1430  SearchTermID id1 = statement->statement()->ColumnInt64(0);
1431  ASSERT_TRUE(id1);
1432  EXPECT_FALSE(statement->statement()->Step());
1433
1434  // Insert a keyword.
1435  HistoryAndBookmarkRow row2;
1436  row2.set_raw_url("google.com");
1437  row2.set_url(GURL("http://google.com"));
1438  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1439  row2.set_title(UTF8ToUTF16("google"));
1440  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2));
1441  base::string16 term2 = UTF8ToUTF16("Search term 2");
1442  URLID url_id2 = history_db_.GetRowForURL(row2.url(), NULL);
1443  ASSERT_TRUE(url_id2);
1444  ASSERT_TRUE(history_db_.SetKeywordSearchTermsForURL(url_id2, 1, term2));
1445
1446  // Get the SearchTermID of the row we just inserted.
1447  projections.clear();
1448  projections.push_back(SearchRow::ID);
1449  projections.push_back(SearchRow::SEARCH_TIME);
1450  projections.push_back(SearchRow::SEARCH_TERM);
1451  args.clear();
1452  args.push_back(term2);
1453  statement.reset(backend->QuerySearchTerms(projections, "search = ?", args,
1454                                            std::string()));
1455  ASSERT_TRUE(statement.get());
1456  ASSERT_TRUE(statement->statement()->Step());
1457  SearchTermID id2 = statement->statement()->ColumnInt64(0);
1458  ASSERT_TRUE(id2);
1459  EXPECT_FALSE(statement->statement()->Step());
1460
1461  // Delete the first one.
1462  args.clear();
1463  args.push_back(term);
1464  int deleted_count = 0;
1465  ASSERT_TRUE(backend->DeleteSearchTerms("search = ?", args, &deleted_count));
1466  EXPECT_EQ(1, deleted_count);
1467  std::vector<KeywordSearchTermRow> rows;
1468  ASSERT_TRUE(history_db_.GetKeywordSearchTermRows(term, &rows));
1469  EXPECT_TRUE(rows.empty());
1470  // Verify we can't get the first term.
1471  args.clear();
1472  std::ostringstream oss;
1473  oss << id1;
1474  args.push_back(UTF8ToUTF16(oss.str()));
1475  statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args,
1476                                            std::string()));
1477  ASSERT_TRUE(statement.get());
1478  EXPECT_FALSE(statement->statement()->Step());
1479
1480  // The second one is still there.
1481  args.clear();
1482  std::ostringstream oss1;
1483  oss1 << id2;
1484  args.push_back(UTF8ToUTF16(oss1.str()));
1485  statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args,
1486                                            std::string()));
1487  ASSERT_TRUE(statement.get());
1488  EXPECT_TRUE(statement->statement()->Step());
1489  EXPECT_EQ(id2, statement->statement()->ColumnInt64(0));
1490  EXPECT_FALSE(statement->statement()->Step());
1491
1492  // Remove all search terms in no condition.
1493  deleted_count = 0;
1494  args.clear();
1495  ASSERT_TRUE(backend->DeleteSearchTerms(std::string(), args, &deleted_count));
1496  EXPECT_EQ(1, deleted_count);
1497
1498  // Verify the second one was removed.
1499  args.clear();
1500  args.push_back(UTF8ToUTF16(oss1.str()));
1501  statement.reset(backend->QuerySearchTerms(projections, "_id = ?", args,
1502                                            std::string()));
1503  ASSERT_TRUE(statement.get());
1504  EXPECT_FALSE(statement->statement()->Step());
1505}
1506
1507TEST_F(AndroidProviderBackendTest, InsertSearchTerm) {
1508  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1509  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1510  scoped_ptr<AndroidProviderBackend> backend(
1511      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1512                                 &thumbnail_db_, bookmark_model_, &delegate_));
1513  SearchRow search_row;
1514  search_row.set_search_term(UTF8ToUTF16("google"));
1515  search_row.set_url(GURL("http://google.com"));
1516  search_row.set_template_url_id(1);
1517  search_row.set_search_time(Time::Now() - TimeDelta::FromHours(1));
1518
1519  SearchTermID id = backend->InsertSearchTerm(search_row);
1520  ASSERT_TRUE(id);
1521
1522  std::vector<SearchRow::ColumnID> projections;
1523  projections.push_back(SearchRow::ID);
1524  projections.push_back(SearchRow::SEARCH_TIME);
1525  projections.push_back(SearchRow::SEARCH_TERM);
1526  std::vector<base::string16> args;
1527  std::ostringstream oss;
1528  oss << id;
1529  args.push_back(UTF8ToUTF16(oss.str()));
1530  scoped_ptr<AndroidStatement> statement(backend->QuerySearchTerms(
1531      projections, "_id = ?", args, std::string()));
1532  ASSERT_TRUE(statement.get());
1533  ASSERT_TRUE(statement->statement()->Step());
1534  EXPECT_EQ(id, statement->statement()->ColumnInt64(0));
1535  EXPECT_EQ(ToDatabaseTime(search_row.search_time()),
1536            statement->statement()->ColumnInt64(1));
1537  EXPECT_EQ(search_row.search_term(),
1538            statement->statement()->ColumnString16(2));
1539  EXPECT_FALSE(statement->statement()->Step());
1540}
1541
1542TEST_F(AndroidProviderBackendTest, DeleteHistory) {
1543  HistoryAndBookmarkRow row1;
1544  row1.set_raw_url("cnn.com");
1545  row1.set_url(GURL("http://cnn.com"));
1546  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1547  row1.set_created(Time::Now() - TimeDelta::FromDays(20));
1548  row1.set_visit_count(10);
1549  row1.set_is_bookmark(true);
1550  row1.set_title(UTF8ToUTF16("cnn"));
1551
1552  HistoryAndBookmarkRow row2;
1553  row2.set_raw_url("http://www.example.com");
1554  row2.set_url(GURL("http://www.example.com"));
1555  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10));
1556  row2.set_is_bookmark(false);
1557  row2.set_title(UTF8ToUTF16("example"));
1558  std::vector<unsigned char> data;
1559  data.push_back('1');
1560  row2.set_favicon(base::RefCountedBytes::TakeVector(&data));
1561
1562  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1563  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1564  scoped_ptr<AndroidProviderBackend> backend(
1565      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1566                                 &thumbnail_db_, bookmark_model_, &delegate_));
1567
1568  AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1);
1569  ASSERT_TRUE(id1);
1570  AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2);
1571  ASSERT_TRUE(id2);
1572
1573  // Verify the row1 has been added in bookmark model.
1574  content::RunAllPendingInMessageLoop();
1575  ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count());
1576  const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0);
1577  ASSERT_TRUE(child);
1578  EXPECT_EQ(row1.title(), child->GetTitle());
1579  EXPECT_EQ(row1.url(), child->url());
1580
1581  // Delete history
1582  int deleted_count = 0;
1583  ASSERT_TRUE(backend->DeleteHistory(std::string(),
1584                                     std::vector<base::string16>(),
1585                                     &deleted_count));
1586  EXPECT_EQ(2, deleted_count);
1587  // The row2 was deleted.
1588  EXPECT_FALSE(history_db_.GetRowForURL(row2.url(), NULL));
1589  // Still find the row1.
1590  URLRow url_row;
1591  ASSERT_TRUE(history_db_.GetRowForURL(row1.url(), &url_row));
1592  // The visit_count was reset.
1593  EXPECT_EQ(0, url_row.visit_count());
1594  EXPECT_EQ(Time::UnixEpoch(), url_row.last_visit());
1595
1596  // Verify the row1 is still in bookmark model.
1597  content::RunAllPendingInMessageLoop();
1598  ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count());
1599  const BookmarkNode* child1 = bookmark_model_->mobile_node()->GetChild(0);
1600  ASSERT_TRUE(child1);
1601  EXPECT_EQ(row1.title(), child1->GetTitle());
1602  EXPECT_EQ(row1.url(), child1->url());
1603
1604  // Verify notification
1605  ASSERT_TRUE(delegate_.deleted_details());
1606  ASSERT_EQ(2u, delegate_.deleted_details()->rows.size());
1607  EXPECT_EQ(row1.url(),
1608            delegate_.modified_details()->changed_urls[0].url());
1609  EXPECT_EQ(Time::UnixEpoch(),
1610            delegate_.modified_details()->changed_urls[0].last_visit());
1611  EXPECT_EQ(1u, delegate_.favicon_details()->urls.size());
1612}
1613
1614TEST_F(AndroidProviderBackendTest, TestMultipleNestingTransaction) {
1615  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1616  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1617  scoped_ptr<AndroidProviderBackend> backend(
1618      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1619                                 &thumbnail_db_, bookmark_model_, &delegate_));
1620
1621  // Create the nested transactions.
1622  history_db_.BeginTransaction();
1623  history_db_.BeginTransaction();
1624  history_db_.BeginTransaction();
1625  thumbnail_db_.BeginTransaction();
1626  thumbnail_db_.BeginTransaction();
1627  int history_transaction = history_db_.transaction_nesting();
1628  int thumbnail_transaction = thumbnail_db_.transaction_nesting();
1629
1630  // Insert a row to verify the transaction number are not changed
1631  // after a transaction commit.
1632  HistoryAndBookmarkRow row1;
1633  row1.set_raw_url("cnn.com");
1634  row1.set_url(GURL("http://cnn.com"));
1635  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1636  row1.set_created(Time::Now() - TimeDelta::FromDays(20));
1637  row1.set_visit_count(10);
1638  row1.set_title(UTF8ToUTF16("cnn"));
1639  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1));
1640  EXPECT_EQ(history_transaction, history_db_.transaction_nesting());
1641  EXPECT_EQ(thumbnail_transaction, thumbnail_db_.transaction_nesting());
1642
1643  // Insert the same URL, it should failed. The transaction are still same
1644  // after a rollback.
1645  ASSERT_FALSE(backend->InsertHistoryAndBookmark(row1));
1646  EXPECT_EQ(history_transaction, history_db_.transaction_nesting());
1647  EXPECT_EQ(thumbnail_transaction, thumbnail_db_.transaction_nesting());
1648
1649  // Insert another row to verify we are still fine after the previous
1650  // rollback.
1651  HistoryAndBookmarkRow row2;
1652  row2.set_raw_url("http://www.example.com");
1653  row2.set_url(GURL("http://www.example.com"));
1654  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10));
1655  row2.set_is_bookmark(false);
1656  row2.set_title(UTF8ToUTF16("example"));
1657  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2));
1658  EXPECT_EQ(history_transaction, history_db_.transaction_nesting());
1659  EXPECT_EQ(thumbnail_transaction, thumbnail_db_.transaction_nesting());
1660}
1661
1662TEST_F(AndroidProviderBackendTest, TestAndroidCTSComplianceForZeroVisitCount) {
1663  // This is to verify the last visit time and created time are same when visit
1664  // count is 0.
1665  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1666  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1667  scoped_ptr<AndroidProviderBackend> backend(
1668      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1669                                 &thumbnail_db_, bookmark_model_, &delegate_));
1670  URLRow url_row(GURL("http://www.google.com"));
1671  url_row.set_last_visit(Time::Now());
1672  url_row.set_visit_count(0);
1673  history_db_.AddURL(url_row);
1674
1675  std::vector<HistoryAndBookmarkRow::ColumnID> projections;
1676
1677  projections.push_back(HistoryAndBookmarkRow::ID);
1678  projections.push_back(HistoryAndBookmarkRow::URL);
1679  projections.push_back(HistoryAndBookmarkRow::TITLE);
1680  projections.push_back(HistoryAndBookmarkRow::CREATED);
1681  projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME);
1682  projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT);
1683  projections.push_back(HistoryAndBookmarkRow::FAVICON);
1684  projections.push_back(HistoryAndBookmarkRow::BOOKMARK);
1685
1686  scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks(
1687      projections, std::string(), std::vector<base::string16>(),
1688      std::string("url ASC")));
1689
1690  ASSERT_TRUE(statement->statement()->Step());
1691  EXPECT_EQ(ToDatabaseTime(url_row.last_visit()),
1692            statement->statement()->ColumnInt64(3));
1693  EXPECT_EQ(ToDatabaseTime(url_row.last_visit()),
1694            statement->statement()->ColumnInt64(4));
1695  EXPECT_EQ(url_row.visit_count(), statement->statement()->ColumnInt(5));
1696}
1697
1698TEST_F(AndroidProviderBackendTest, AndroidCTSComplianceFolderColumnExists) {
1699  // This is test is used to verify the 'folder' column exists, all bookmarks
1700  // returned when folder is 0 and the non bookmark rows returned when folder
1701  // is 1.
1702  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1703  ASSERT_EQ(sql::INIT_OK, thumbnail_db_.Init(thumbnail_db_name_));
1704  scoped_ptr<AndroidProviderBackend> backend(
1705      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1706                                 &thumbnail_db_, bookmark_model_, &delegate_));
1707  HistoryAndBookmarkRow row1;
1708  row1.set_raw_url("cnn.com");
1709  row1.set_url(GURL("http://cnn.com"));
1710  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1711  row1.set_created(Time::Now() - TimeDelta::FromDays(20));
1712  row1.set_visit_count(10);
1713  row1.set_is_bookmark(true);
1714  row1.set_title(UTF8ToUTF16("cnn"));
1715
1716  HistoryAndBookmarkRow row2;
1717  row2.set_raw_url("http://www.example.com");
1718  row2.set_url(GURL("http://www.example.com"));
1719  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10));
1720  row2.set_is_bookmark(false);
1721  row2.set_title(UTF8ToUTF16("example"));
1722  std::vector<unsigned char> data;
1723  data.push_back('1');
1724  row2.set_favicon(base::RefCountedBytes::TakeVector(&data));
1725
1726  AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1);
1727  ASSERT_TRUE(id1);
1728  AndroidURLID id2 = backend->InsertHistoryAndBookmark(row2);
1729  ASSERT_TRUE(id2);
1730  content::RunAllPendingInMessageLoop();
1731
1732  // Query by folder=0, the row1 should returned.
1733  std::vector<HistoryAndBookmarkRow::ColumnID> projections;
1734
1735  projections.push_back(HistoryAndBookmarkRow::URL);
1736
1737  scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks(
1738      projections, std::string("folder=0"), std::vector<base::string16>(),
1739      std::string("url ASC")));
1740  ASSERT_TRUE(statement->statement()->Step());
1741  EXPECT_EQ(row1.raw_url(), statement->statement()->ColumnString(0));
1742  EXPECT_FALSE(statement->statement()->Step());
1743
1744  // Query by folder=1, the row2 should returned.
1745  statement.reset(backend->QueryHistoryAndBookmarks(
1746      projections, std::string("folder=1"), std::vector<base::string16>(),
1747      std::string("url ASC")));
1748  ASSERT_TRUE(statement->statement()->Step());
1749  EXPECT_EQ(row2.url(), GURL(statement->statement()->ColumnString(0)));
1750  EXPECT_FALSE(statement->statement()->Step());
1751}
1752
1753TEST_F(AndroidProviderBackendTest, QueryWithoutThumbnailDB) {
1754  GURL url1("http://www.cnn.com");
1755  URLID url_id1 = 0;
1756  const base::string16 title1(UTF8ToUTF16("cnn"));
1757  std::vector<VisitInfo> visits1;
1758  Time last_visited1 = Time::Now() - TimeDelta::FromDays(1);
1759  Time created1 = last_visited1 - TimeDelta::FromDays(20);
1760  visits1.push_back(VisitInfo(created1, content::PAGE_TRANSITION_LINK));
1761  visits1.push_back(VisitInfo(last_visited1 - TimeDelta::FromDays(1),
1762                              content::PAGE_TRANSITION_LINK));
1763  visits1.push_back(VisitInfo(last_visited1, content::PAGE_TRANSITION_LINK));
1764
1765  GURL url2("http://www.example.com");
1766  URLID url_id2 = 0;
1767  std::vector<VisitInfo> visits2;
1768  const base::string16 title2(UTF8ToUTF16("example"));
1769  Time last_visited2 = Time::Now();
1770  Time created2 = last_visited2 - TimeDelta::FromDays(10);
1771  visits2.push_back(VisitInfo(created2, content::PAGE_TRANSITION_LINK));
1772  visits2.push_back(VisitInfo(last_visited2 - TimeDelta::FromDays(5),
1773                              content::PAGE_TRANSITION_LINK));
1774  visits2.push_back(VisitInfo(last_visited2, content::PAGE_TRANSITION_LINK));
1775
1776  // Only use the HistoryBackend to generate the test data.
1777  // HistoryBackend will shutdown after that.
1778  {
1779  scoped_refptr<HistoryBackend> history_backend;
1780  history_backend = new HistoryBackend(temp_dir_.path(), 0,
1781      new AndroidProviderBackendDelegate(), bookmark_model_);
1782  history_backend->Init(std::string(), false);
1783  history_backend->AddVisits(url1, visits1, history::SOURCE_SYNCED);
1784  history_backend->AddVisits(url2, visits2, history::SOURCE_SYNCED);
1785  URLRow url_row;
1786
1787  ASSERT_TRUE(history_backend->GetURL(url1, &url_row));
1788  url_id1 = url_row.id();
1789  url_row.set_title(title1);
1790  ASSERT_TRUE(history_backend->UpdateURL(url_id1, url_row));
1791
1792  ASSERT_TRUE(history_backend->GetURL(url2, &url_row));
1793  url_id2 = url_row.id();
1794  url_row.set_title(title2);
1795  ASSERT_TRUE(history_backend->UpdateURL(url_id2, url_row));
1796
1797  // Set favicon to url2.
1798  std::vector<unsigned char> data;
1799  data.push_back('1');
1800  chrome::FaviconBitmapData bitmap_data_element;
1801  bitmap_data_element.bitmap_data = new base::RefCountedBytes(data);
1802  bitmap_data_element.pixel_size = gfx::Size();
1803  bitmap_data_element.icon_url = GURL();
1804  std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
1805  favicon_bitmap_data.push_back(bitmap_data_element);
1806
1807  history_backend->SetFavicons(url2, chrome::FAVICON, favicon_bitmap_data);
1808  history_backend->Closing();
1809  }
1810
1811  // The history_db_name and thumbnail_db_name files should be created by
1812  // HistoryBackend. We need to open the same database files.
1813  ASSERT_TRUE(base::PathExists(history_db_name_));
1814  ASSERT_TRUE(base::PathExists(thumbnail_db_name_));
1815
1816  // Only creates the history database
1817  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1818
1819  // Set url1 as bookmark.
1820  AddBookmark(url1);
1821
1822  scoped_ptr<AndroidProviderBackend> backend(
1823      new AndroidProviderBackend(android_cache_db_name_, &history_db_, NULL,
1824                                 bookmark_model_, &delegate_));
1825
1826  std::vector<HistoryAndBookmarkRow::ColumnID> projections;
1827
1828  projections.push_back(HistoryAndBookmarkRow::ID);
1829  projections.push_back(HistoryAndBookmarkRow::URL);
1830  projections.push_back(HistoryAndBookmarkRow::TITLE);
1831  projections.push_back(HistoryAndBookmarkRow::CREATED);
1832  projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME);
1833  projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT);
1834  projections.push_back(HistoryAndBookmarkRow::FAVICON);
1835  projections.push_back(HistoryAndBookmarkRow::BOOKMARK);
1836
1837  scoped_ptr<AndroidStatement> statement(backend->QueryHistoryAndBookmarks(
1838      projections, std::string(), std::vector<base::string16>(),
1839      std::string("url ASC")));
1840  ASSERT_TRUE(statement->statement()->Step());
1841  ASSERT_EQ(url1, GURL(statement->statement()->ColumnString(1)));
1842  EXPECT_EQ(title1, statement->statement()->ColumnString16(2));
1843  EXPECT_EQ(ToDatabaseTime(created1),
1844            statement->statement()->ColumnInt64(3));
1845  EXPECT_EQ(ToDatabaseTime(last_visited1),
1846            statement->statement()->ColumnInt64(4));
1847  EXPECT_EQ(3, statement->statement()->ColumnInt(5));
1848  EXPECT_EQ(6, statement->favicon_index());
1849  // No favicon.
1850  EXPECT_EQ(0, statement->statement()->ColumnByteLength(6));
1851  EXPECT_TRUE(statement->statement()->ColumnBool(7));
1852
1853  ASSERT_TRUE(statement->statement()->Step());
1854  EXPECT_EQ(title2, statement->statement()->ColumnString16(2));
1855  ASSERT_EQ(url2, GURL(statement->statement()->ColumnString(1)));
1856  EXPECT_EQ(ToDatabaseTime(created2),
1857            statement->statement()->ColumnInt64(3));
1858  EXPECT_EQ(ToDatabaseTime(last_visited2),
1859            statement->statement()->ColumnInt64(4));
1860  EXPECT_EQ(3, statement->statement()->ColumnInt(5));
1861  std::vector<unsigned char> favicon2;
1862  EXPECT_EQ(6, statement->favicon_index());
1863  // No favicon because thumbnail database wasn't initialized.
1864  EXPECT_EQ(0, statement->statement()->ColumnByteLength(6));
1865  EXPECT_FALSE(statement->statement()->ColumnBool(7));
1866
1867  // No more row.
1868  EXPECT_FALSE(statement->statement()->Step());
1869}
1870
1871TEST_F(AndroidProviderBackendTest, InsertWithoutThumbnailDB) {
1872  HistoryAndBookmarkRow row1;
1873  row1.set_raw_url("cnn.com");
1874  row1.set_url(GURL("http://cnn.com"));
1875  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1876  row1.set_created(Time::Now() - TimeDelta::FromDays(20));
1877  row1.set_visit_count(10);
1878  row1.set_is_bookmark(true);
1879  row1.set_title(UTF8ToUTF16("cnn"));
1880
1881  HistoryAndBookmarkRow row2;
1882  row2.set_raw_url("http://www.example.com");
1883  row2.set_url(GURL("http://www.example.com"));
1884  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10));
1885  row2.set_is_bookmark(false);
1886  row2.set_title(UTF8ToUTF16("example"));
1887  std::vector<unsigned char> data;
1888  data.push_back('1');
1889  row2.set_favicon(base::RefCountedBytes::TakeVector(&data));
1890
1891  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1892  scoped_ptr<AndroidProviderBackend> backend(
1893      new AndroidProviderBackend(android_cache_db_name_, &history_db_, NULL,
1894                                 bookmark_model_, &delegate_));
1895
1896  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1));
1897  EXPECT_FALSE(delegate_.deleted_details());
1898  ASSERT_TRUE(delegate_.modified_details());
1899  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
1900  EXPECT_EQ(row1.url(), delegate_.modified_details()->changed_urls[0].url());
1901  EXPECT_EQ(row1.last_visit_time(),
1902            delegate_.modified_details()->changed_urls[0].last_visit());
1903  EXPECT_EQ(row1.visit_count(),
1904            delegate_.modified_details()->changed_urls[0].visit_count());
1905  EXPECT_EQ(row1.title(),
1906            delegate_.modified_details()->changed_urls[0].title());
1907  EXPECT_FALSE(delegate_.favicon_details());
1908  content::RunAllPendingInMessageLoop();
1909  ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count());
1910  const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0);
1911  ASSERT_TRUE(child);
1912  EXPECT_EQ(row1.title(), child->GetTitle());
1913  EXPECT_EQ(row1.url(), child->url());
1914
1915  delegate_.ResetDetails();
1916  ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2));
1917  EXPECT_FALSE(delegate_.deleted_details());
1918  ASSERT_TRUE(delegate_.modified_details());
1919  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
1920  EXPECT_EQ(row2.url(), delegate_.modified_details()->changed_urls[0].url());
1921  EXPECT_EQ(row2.last_visit_time(),
1922            delegate_.modified_details()->changed_urls[0].last_visit());
1923  EXPECT_EQ(row2.title(),
1924            delegate_.modified_details()->changed_urls[0].title());
1925  // Favicon details is still false because thumbnail database wasn't
1926  // initialized, we ignore any changes of favicon.
1927  ASSERT_FALSE(delegate_.favicon_details());
1928}
1929
1930TEST_F(AndroidProviderBackendTest, DeleteWithoutThumbnailDB) {
1931  HistoryAndBookmarkRow row1;
1932  row1.set_raw_url("cnn.com");
1933  row1.set_url(GURL("http://cnn.com"));
1934  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
1935  row1.set_created(Time::Now() - TimeDelta::FromDays(20));
1936  row1.set_visit_count(10);
1937  row1.set_is_bookmark(true);
1938  row1.set_title(UTF8ToUTF16("cnn"));
1939
1940  HistoryAndBookmarkRow row2;
1941  row2.set_raw_url("http://www.example.com");
1942  row2.set_url(GURL("http://www.example.com"));
1943  row2.set_last_visit_time(Time::Now() - TimeDelta::FromDays(10));
1944  row2.set_is_bookmark(false);
1945  row2.set_title(UTF8ToUTF16("example"));
1946  std::vector<unsigned char> data;
1947  data.push_back('1');
1948  row2.set_favicon(base::RefCountedBytes::TakeVector(&data));
1949
1950  {
1951    HistoryDatabase history_db;
1952    ThumbnailDatabase thumbnail_db;
1953    ASSERT_EQ(sql::INIT_OK, history_db.Init(history_db_name_));
1954    ASSERT_EQ(sql::INIT_OK, thumbnail_db.Init(thumbnail_db_name_));
1955
1956    scoped_ptr<AndroidProviderBackend> backend(
1957        new AndroidProviderBackend(android_cache_db_name_, &history_db,
1958                                   &thumbnail_db, bookmark_model_, &delegate_));
1959
1960    ASSERT_TRUE(backend->InsertHistoryAndBookmark(row1));
1961    ASSERT_TRUE(backend->InsertHistoryAndBookmark(row2));
1962    // Verify the row1 has been added in bookmark model.
1963    content::RunAllPendingInMessageLoop();
1964    ASSERT_EQ(1, bookmark_model_->mobile_node()->child_count());
1965    const BookmarkNode* child = bookmark_model_->mobile_node()->GetChild(0);
1966    ASSERT_TRUE(child);
1967    EXPECT_EQ(row1.title(), child->GetTitle());
1968    EXPECT_EQ(row1.url(), child->url());
1969  }
1970  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
1971  scoped_ptr<AndroidProviderBackend> backend(
1972      new AndroidProviderBackend(android_cache_db_name_, &history_db_,
1973                                 NULL, bookmark_model_, &delegate_));
1974
1975  // Delete all rows.
1976  std::vector<base::string16> args;
1977  int deleted_count = 0;
1978  delegate_.ResetDetails();
1979  ASSERT_TRUE(backend->DeleteHistoryAndBookmarks("Favicon IS NULL", args,
1980                                                 &deleted_count));
1981  // All rows were deleted.
1982  EXPECT_EQ(2, deleted_count);
1983  // Verify the rows was removed from bookmark model.
1984  content::RunAllPendingInMessageLoop();
1985  ASSERT_EQ(0, bookmark_model_->mobile_node()->child_count());
1986
1987  // Verify notifications
1988  ASSERT_TRUE(delegate_.deleted_details());
1989  EXPECT_FALSE(delegate_.modified_details());
1990  EXPECT_EQ(2u, delegate_.deleted_details()->rows.size());
1991  // No favicon has been deleted.
1992  EXPECT_FALSE(delegate_.favicon_details());
1993
1994  // No row exists.
1995  std::vector<HistoryAndBookmarkRow::ColumnID> projections;
1996  projections.push_back(HistoryAndBookmarkRow::ID);
1997  projections.push_back(HistoryAndBookmarkRow::URL);
1998  projections.push_back(HistoryAndBookmarkRow::TITLE);
1999  projections.push_back(HistoryAndBookmarkRow::CREATED);
2000  projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME);
2001  projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT);
2002  projections.push_back(HistoryAndBookmarkRow::FAVICON);
2003  projections.push_back(HistoryAndBookmarkRow::BOOKMARK);
2004
2005  scoped_ptr<AndroidStatement> statement1(backend->QueryHistoryAndBookmarks(
2006      projections, std::string(), std::vector<base::string16>(),
2007      std::string("url ASC")));
2008  ASSERT_FALSE(statement1->statement()->Step());
2009}
2010
2011TEST_F(AndroidProviderBackendTest, UpdateFaviconWithoutThumbnail) {
2012  HistoryAndBookmarkRow row1;
2013  row1.set_raw_url("cnn.com");
2014  row1.set_url(GURL("http://cnn.com"));
2015  row1.set_last_visit_time(Time::Now() - TimeDelta::FromDays(1));
2016  row1.set_created(Time::Now() - TimeDelta::FromDays(20));
2017  row1.set_visit_count(10);
2018  row1.set_is_bookmark(true);
2019  row1.set_title(UTF8ToUTF16("cnn"));
2020
2021  {
2022    HistoryDatabase history_db;
2023    ThumbnailDatabase thumbnail_db;
2024    ASSERT_EQ(sql::INIT_OK, history_db.Init(history_db_name_));
2025    ASSERT_EQ(sql::INIT_OK, thumbnail_db.Init(thumbnail_db_name_));
2026    scoped_ptr<AndroidProviderBackend> backend(
2027        new AndroidProviderBackend(android_cache_db_name_, &history_db,
2028            &thumbnail_db, bookmark_model_, &delegate_));
2029
2030    AndroidURLID id1 = backend->InsertHistoryAndBookmark(row1);
2031    ASSERT_TRUE(id1);
2032  }
2033
2034  ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name_));
2035  scoped_ptr<AndroidProviderBackend> backend(
2036      new AndroidProviderBackend(android_cache_db_name_, &history_db_, NULL,
2037                                 bookmark_model_, &delegate_));
2038
2039  int update_count;
2040  std::vector<base::string16> update_args;
2041  // Update the last visit time to a value greater than current one.
2042  HistoryAndBookmarkRow update_row1;
2043
2044  // Set visit count.
2045  update_row1.set_visit_count(5);
2046  // Set favicon.
2047  std::vector<unsigned char> data;
2048  data.push_back('1');
2049  update_row1.set_favicon(base::RefCountedBytes::TakeVector(&data));
2050  update_args.push_back(UTF8ToUTF16(row1.raw_url()));
2051  delegate_.ResetDetails();
2052  ASSERT_TRUE(backend->UpdateHistoryAndBookmarks(update_row1, "url = ?",
2053                                                 update_args, &update_count));
2054  // Verify notifications.
2055  EXPECT_FALSE(delegate_.deleted_details());
2056  ASSERT_TRUE(delegate_.modified_details());
2057  ASSERT_EQ(1u, delegate_.modified_details()->changed_urls.size());
2058  // No favicon will be updated as thumbnail database is missing.
2059  EXPECT_FALSE(delegate_.favicon_details());
2060}
2061
2062}  // namespace history
2063