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