Home | History | Annotate | Download | only in history
      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 // History unit tests come in two flavors:
      6 //
      7 // 1. The more complicated style is that the unit test creates a full history
      8 //    service. This spawns a background thread for the history backend, and
      9 //    all communication is asynchronous. This is useful for testing more
     10 //    complicated things or end-to-end behavior.
     11 //
     12 // 2. The simpler style is to create a history backend on this thread and
     13 //    access it directly without a HistoryService object. This is much simpler
     14 //    because communication is synchronous. Generally, sets should go through
     15 //    the history backend (since there is a lot of logic) but gets can come
     16 //    directly from the HistoryDatabase. This is because the backend generally
     17 //    has no logic in the getter except threading stuff, which we don't want
     18 //    to run.
     19 
     20 #include <time.h>
     21 
     22 #include <algorithm>
     23 #include <string>
     24 
     25 #include "base/basictypes.h"
     26 #include "base/bind.h"
     27 #include "base/bind_helpers.h"
     28 #include "base/callback.h"
     29 #include "base/command_line.h"
     30 #include "base/compiler_specific.h"
     31 #include "base/file_util.h"
     32 #include "base/files/file_path.h"
     33 #include "base/files/scoped_temp_dir.h"
     34 #include "base/logging.h"
     35 #include "base/memory/scoped_ptr.h"
     36 #include "base/memory/scoped_vector.h"
     37 #include "base/message_loop/message_loop.h"
     38 #include "base/path_service.h"
     39 #include "base/strings/string_util.h"
     40 #include "base/strings/stringprintf.h"
     41 #include "base/strings/utf_string_conversions.h"
     42 #include "base/task/cancelable_task_tracker.h"
     43 #include "base/threading/platform_thread.h"
     44 #include "base/time/time.h"
     45 #include "chrome/browser/history/download_row.h"
     46 #include "chrome/browser/history/history_backend.h"
     47 #include "chrome/browser/history/history_database.h"
     48 #include "chrome/browser/history/history_db_task.h"
     49 #include "chrome/browser/history/history_notifications.h"
     50 #include "chrome/browser/history/history_service.h"
     51 #include "chrome/browser/history/history_unittest_base.h"
     52 #include "chrome/browser/history/in_memory_database.h"
     53 #include "chrome/browser/history/in_memory_history_backend.h"
     54 #include "chrome/browser/history/page_usage_data.h"
     55 #include "chrome/common/chrome_constants.h"
     56 #include "chrome/common/chrome_paths.h"
     57 #include "chrome/tools/profiles/thumbnail-inl.h"
     58 #include "components/history/core/common/thumbnail_score.h"
     59 #include "content/public/browser/download_item.h"
     60 #include "content/public/browser/notification_details.h"
     61 #include "content/public/browser/notification_source.h"
     62 #include "sql/connection.h"
     63 #include "sql/statement.h"
     64 #include "sync/api/attachments/attachment_id.h"
     65 #include "sync/api/attachments/attachment_service_proxy_for_test.h"
     66 #include "sync/api/fake_sync_change_processor.h"
     67 #include "sync/api/sync_change.h"
     68 #include "sync/api/sync_change_processor.h"
     69 #include "sync/api/sync_change_processor_wrapper_for_test.h"
     70 #include "sync/api/sync_error.h"
     71 #include "sync/api/sync_error_factory.h"
     72 #include "sync/api/sync_merge_result.h"
     73 #include "sync/protocol/history_delete_directive_specifics.pb.h"
     74 #include "sync/protocol/sync.pb.h"
     75 #include "testing/gtest/include/gtest/gtest.h"
     76 #include "third_party/skia/include/core/SkBitmap.h"
     77 #include "ui/gfx/codec/jpeg_codec.h"
     78 
     79 using base::Time;
     80 using base::TimeDelta;
     81 using content::DownloadItem;
     82 
     83 namespace history {
     84 class HistoryBackendDBTest;
     85 
     86 // Delegate class for when we create a backend without a HistoryService.
     87 //
     88 // This must be outside the anonymous namespace for the friend statement in
     89 // HistoryBackendDBTest to work.
     90 class BackendDelegate : public HistoryBackend::Delegate {
     91  public:
     92   explicit BackendDelegate(HistoryBackendDBTest* history_test)
     93       : history_test_(history_test) {
     94   }
     95 
     96   virtual void NotifyProfileError(sql::InitStatus init_status) OVERRIDE {}
     97   virtual void SetInMemoryBackend(
     98       scoped_ptr<InMemoryHistoryBackend> backend) OVERRIDE;
     99   virtual void BroadcastNotifications(
    100       int type,
    101       scoped_ptr<HistoryDetails> details) OVERRIDE;
    102   virtual void DBLoaded() OVERRIDE {}
    103   virtual void NotifyVisitDBObserversOnAddVisit(
    104       const BriefVisitInfo& info) OVERRIDE {}
    105  private:
    106   HistoryBackendDBTest* history_test_;
    107 };
    108 
    109 // This must be outside the anonymous namespace for the friend statement in
    110 // HistoryBackend to work.
    111 class HistoryBackendDBTest : public HistoryUnitTestBase {
    112  public:
    113   HistoryBackendDBTest() : db_(NULL) {
    114   }
    115 
    116   virtual ~HistoryBackendDBTest() {
    117   }
    118 
    119  protected:
    120   friend class BackendDelegate;
    121 
    122   // Creates the HistoryBackend and HistoryDatabase on the current thread,
    123   // assigning the values to backend_ and db_.
    124   void CreateBackendAndDatabase() {
    125     backend_ =
    126         new HistoryBackend(history_dir_, new BackendDelegate(this), NULL);
    127     backend_->Init(std::string(), false);
    128     db_ = backend_->db_.get();
    129     DCHECK(in_mem_backend_) << "Mem backend should have been set by "
    130         "HistoryBackend::Init";
    131   }
    132 
    133   void CreateDBVersion(int version) {
    134     base::FilePath data_path;
    135     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
    136     data_path = data_path.AppendASCII("History");
    137     data_path =
    138           data_path.AppendASCII(base::StringPrintf("history.%d.sql", version));
    139     ASSERT_NO_FATAL_FAILURE(
    140         ExecuteSQLScript(data_path, history_dir_.Append(
    141             chrome::kHistoryFilename)));
    142   }
    143 
    144   void CreateArchivedDB() {
    145     base::FilePath data_path;
    146     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
    147     data_path = data_path.AppendASCII("History");
    148     data_path = data_path.AppendASCII("archived_history.4.sql");
    149     ASSERT_NO_FATAL_FAILURE(
    150         ExecuteSQLScript(data_path, history_dir_.Append(
    151             chrome::kArchivedHistoryFilename)));
    152   }
    153 
    154   // testing::Test
    155   virtual void SetUp() {
    156     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    157     history_dir_ = temp_dir_.path().AppendASCII("HistoryBackendDBTest");
    158     ASSERT_TRUE(base::CreateDirectory(history_dir_));
    159   }
    160 
    161   void DeleteBackend() {
    162     if (backend_.get()) {
    163       backend_->Closing();
    164       backend_ = NULL;
    165     }
    166   }
    167 
    168   virtual void TearDown() {
    169     DeleteBackend();
    170 
    171     // Make sure we don't have any event pending that could disrupt the next
    172     // test.
    173     base::MessageLoop::current()->PostTask(FROM_HERE,
    174                                            base::MessageLoop::QuitClosure());
    175     base::MessageLoop::current()->Run();
    176   }
    177 
    178   bool AddDownload(uint32 id,
    179                    DownloadItem::DownloadState state,
    180                    const Time& time) {
    181     std::vector<GURL> url_chain;
    182     url_chain.push_back(GURL("foo-url"));
    183 
    184     DownloadRow download(base::FilePath(FILE_PATH_LITERAL("current-path")),
    185                          base::FilePath(FILE_PATH_LITERAL("target-path")),
    186                          url_chain,
    187                          GURL("http://referrer.com/"),
    188                          "application/vnd.oasis.opendocument.text",
    189                          "application/octet-stream",
    190                          time,
    191                          time,
    192                          std::string(),
    193                          std::string(),
    194                          0,
    195                          512,
    196                          state,
    197                          content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
    198                          content::DOWNLOAD_INTERRUPT_REASON_NONE,
    199                          id,
    200                          false,
    201                          "by_ext_id",
    202                          "by_ext_name");
    203     return db_->CreateDownload(download);
    204   }
    205 
    206   base::ScopedTempDir temp_dir_;
    207 
    208   base::MessageLoopForUI message_loop_;
    209 
    210   // names of the database files
    211   base::FilePath history_dir_;
    212 
    213   // Created via CreateBackendAndDatabase.
    214   scoped_refptr<HistoryBackend> backend_;
    215   scoped_ptr<InMemoryHistoryBackend> in_mem_backend_;
    216   HistoryDatabase* db_;  // Cached reference to the backend's database.
    217 };
    218 
    219 void BackendDelegate::SetInMemoryBackend(
    220     scoped_ptr<InMemoryHistoryBackend> backend) {
    221   // Save the in-memory backend to the history test object, this happens
    222   // synchronously, so we don't have to do anything fancy.
    223   history_test_->in_mem_backend_.swap(backend);
    224 }
    225 
    226 void BackendDelegate::BroadcastNotifications(
    227     int type,
    228     scoped_ptr<HistoryDetails> details) {
    229   // Currently, just send the notifications directly to the in-memory database.
    230   // We may want do do something more fancy in the future.
    231   content::Details<HistoryDetails> det(details.get());
    232   history_test_->in_mem_backend_->Observe(type,
    233       content::Source<HistoryBackendDBTest>(NULL), det);
    234 }
    235 
    236 TEST_F(HistoryBackendDBTest, ClearBrowsingData_Downloads) {
    237   CreateBackendAndDatabase();
    238 
    239   // Initially there should be nothing in the downloads database.
    240   std::vector<DownloadRow> downloads;
    241   db_->QueryDownloads(&downloads);
    242   EXPECT_EQ(0U, downloads.size());
    243 
    244   // Add a download, test that it was added correctly, remove it, test that it
    245   // was removed.
    246   Time now = Time();
    247   uint32 id = 1;
    248   EXPECT_TRUE(AddDownload(id, DownloadItem::COMPLETE, Time()));
    249   db_->QueryDownloads(&downloads);
    250   EXPECT_EQ(1U, downloads.size());
    251 
    252   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("current-path")),
    253             downloads[0].current_path);
    254   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("target-path")),
    255             downloads[0].target_path);
    256   EXPECT_EQ(1UL, downloads[0].url_chain.size());
    257   EXPECT_EQ(GURL("foo-url"), downloads[0].url_chain[0]);
    258   EXPECT_EQ(std::string("http://referrer.com/"),
    259             std::string(downloads[0].referrer_url.spec()));
    260   EXPECT_EQ(now, downloads[0].start_time);
    261   EXPECT_EQ(now, downloads[0].end_time);
    262   EXPECT_EQ(0, downloads[0].received_bytes);
    263   EXPECT_EQ(512, downloads[0].total_bytes);
    264   EXPECT_EQ(DownloadItem::COMPLETE, downloads[0].state);
    265   EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
    266             downloads[0].danger_type);
    267   EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
    268             downloads[0].interrupt_reason);
    269   EXPECT_FALSE(downloads[0].opened);
    270   EXPECT_EQ("by_ext_id", downloads[0].by_ext_id);
    271   EXPECT_EQ("by_ext_name", downloads[0].by_ext_name);
    272   EXPECT_EQ("application/vnd.oasis.opendocument.text", downloads[0].mime_type);
    273   EXPECT_EQ("application/octet-stream", downloads[0].original_mime_type);
    274 
    275   db_->QueryDownloads(&downloads);
    276   EXPECT_EQ(1U, downloads.size());
    277   db_->RemoveDownload(id);
    278   db_->QueryDownloads(&downloads);
    279   EXPECT_EQ(0U, downloads.size());
    280 }
    281 
    282 TEST_F(HistoryBackendDBTest, MigrateDownloadsState) {
    283   // Create the db we want.
    284   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
    285   {
    286     // Open the db for manual manipulation.
    287     sql::Connection db;
    288     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    289 
    290     // Manually insert corrupted rows; there's infrastructure in place now to
    291     // make this impossible, at least according to the test above.
    292     for (int state = 0; state < 5; ++state) {
    293       sql::Statement s(db.GetUniqueStatement(
    294             "INSERT INTO downloads (id, full_path, url, start_time, "
    295             "received_bytes, total_bytes, state, end_time, opened) VALUES "
    296             "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
    297       s.BindInt64(0, 1 + state);
    298       s.BindString(1, "path");
    299       s.BindString(2, "url");
    300       s.BindInt64(3, base::Time::Now().ToTimeT());
    301       s.BindInt64(4, 100);
    302       s.BindInt64(5, 100);
    303       s.BindInt(6, state);
    304       s.BindInt64(7, base::Time::Now().ToTimeT());
    305       s.BindInt(8, state % 2);
    306       ASSERT_TRUE(s.Run());
    307     }
    308   }
    309 
    310   // Re-open the db using the HistoryDatabase, which should migrate from version
    311   // 22 to the current version, fixing just the row whose state was 3.
    312   // Then close the db so that we can re-open it directly.
    313   CreateBackendAndDatabase();
    314   DeleteBackend();
    315   {
    316     // Re-open the db for manual manipulation.
    317     sql::Connection db;
    318     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    319     {
    320       // The version should have been updated.
    321       int cur_version = HistoryDatabase::GetCurrentVersion();
    322       ASSERT_LT(22, cur_version);
    323       sql::Statement s(db.GetUniqueStatement(
    324           "SELECT value FROM meta WHERE key = 'version'"));
    325       EXPECT_TRUE(s.Step());
    326       EXPECT_EQ(cur_version, s.ColumnInt(0));
    327     }
    328     {
    329       sql::Statement statement(db.GetUniqueStatement(
    330           "SELECT id, state, opened "
    331           "FROM downloads "
    332           "ORDER BY id"));
    333       int counter = 0;
    334       while (statement.Step()) {
    335         EXPECT_EQ(1 + counter, statement.ColumnInt64(0));
    336         // The only thing that migration should have changed was state from 3 to
    337         // 4.
    338         EXPECT_EQ(((counter == 3) ? 4 : counter), statement.ColumnInt(1));
    339         EXPECT_EQ(counter % 2, statement.ColumnInt(2));
    340         ++counter;
    341       }
    342       EXPECT_EQ(5, counter);
    343     }
    344   }
    345 }
    346 
    347 TEST_F(HistoryBackendDBTest, MigrateDownloadsReasonPathsAndDangerType) {
    348   Time now(base::Time::Now());
    349 
    350   // Create the db we want.  The schema didn't change from 22->23, so just
    351   // re-use the v22 file.
    352   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
    353   {
    354     // Re-open the db for manual manipulation.
    355     sql::Connection db;
    356     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    357 
    358     // Manually insert some rows.
    359     sql::Statement s(db.GetUniqueStatement(
    360         "INSERT INTO downloads (id, full_path, url, start_time, "
    361         "received_bytes, total_bytes, state, end_time, opened) VALUES "
    362         "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
    363 
    364     int64 id = 0;
    365     // Null path.
    366     s.BindInt64(0, ++id);
    367     s.BindString(1, std::string());
    368     s.BindString(2, "http://whatever.com/index.html");
    369     s.BindInt64(3, now.ToTimeT());
    370     s.BindInt64(4, 100);
    371     s.BindInt64(5, 100);
    372     s.BindInt(6, 1);
    373     s.BindInt64(7, now.ToTimeT());
    374     s.BindInt(8, 1);
    375     ASSERT_TRUE(s.Run());
    376     s.Reset(true);
    377 
    378     // Non-null path.
    379     s.BindInt64(0, ++id);
    380     s.BindString(1, "/path/to/some/file");
    381     s.BindString(2, "http://whatever.com/index1.html");
    382     s.BindInt64(3, now.ToTimeT());
    383     s.BindInt64(4, 100);
    384     s.BindInt64(5, 100);
    385     s.BindInt(6, 1);
    386     s.BindInt64(7, now.ToTimeT());
    387     s.BindInt(8, 1);
    388     ASSERT_TRUE(s.Run());
    389   }
    390 
    391   // Re-open the db using the HistoryDatabase, which should migrate from version
    392   // 23 to 24, creating the new tables and creating the new path, reason,
    393   // and danger columns.
    394   CreateBackendAndDatabase();
    395   DeleteBackend();
    396   {
    397     // Re-open the db for manual manipulation.
    398     sql::Connection db;
    399     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    400     {
    401       // The version should have been updated.
    402       int cur_version = HistoryDatabase::GetCurrentVersion();
    403       ASSERT_LT(23, cur_version);
    404       sql::Statement s(db.GetUniqueStatement(
    405           "SELECT value FROM meta WHERE key = 'version'"));
    406       EXPECT_TRUE(s.Step());
    407       EXPECT_EQ(cur_version, s.ColumnInt(0));
    408     }
    409     {
    410       base::Time nowish(base::Time::FromTimeT(now.ToTimeT()));
    411 
    412       // Confirm downloads table is valid.
    413       sql::Statement statement(db.GetUniqueStatement(
    414           "SELECT id, interrupt_reason, current_path, target_path, "
    415           "       danger_type, start_time, end_time "
    416           "FROM downloads ORDER BY id"));
    417       EXPECT_TRUE(statement.Step());
    418       EXPECT_EQ(1, statement.ColumnInt64(0));
    419       EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
    420                 statement.ColumnInt(1));
    421       EXPECT_EQ("", statement.ColumnString(2));
    422       EXPECT_EQ("", statement.ColumnString(3));
    423       // Implicit dependence on value of kDangerTypeNotDangerous from
    424       // download_database.cc.
    425       EXPECT_EQ(0, statement.ColumnInt(4));
    426       EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(5));
    427       EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(6));
    428 
    429       EXPECT_TRUE(statement.Step());
    430       EXPECT_EQ(2, statement.ColumnInt64(0));
    431       EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
    432                 statement.ColumnInt(1));
    433       EXPECT_EQ("/path/to/some/file", statement.ColumnString(2));
    434       EXPECT_EQ("/path/to/some/file", statement.ColumnString(3));
    435       EXPECT_EQ(0, statement.ColumnInt(4));
    436       EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(5));
    437       EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(6));
    438 
    439       EXPECT_FALSE(statement.Step());
    440     }
    441     {
    442       // Confirm downloads_url_chains table is valid.
    443       sql::Statement statement(db.GetUniqueStatement(
    444           "SELECT id, chain_index, url FROM downloads_url_chains "
    445           " ORDER BY id, chain_index"));
    446       EXPECT_TRUE(statement.Step());
    447       EXPECT_EQ(1, statement.ColumnInt64(0));
    448       EXPECT_EQ(0, statement.ColumnInt(1));
    449       EXPECT_EQ("http://whatever.com/index.html", statement.ColumnString(2));
    450 
    451       EXPECT_TRUE(statement.Step());
    452       EXPECT_EQ(2, statement.ColumnInt64(0));
    453       EXPECT_EQ(0, statement.ColumnInt(1));
    454       EXPECT_EQ("http://whatever.com/index1.html", statement.ColumnString(2));
    455 
    456       EXPECT_FALSE(statement.Step());
    457     }
    458   }
    459 }
    460 
    461 TEST_F(HistoryBackendDBTest, MigrateReferrer) {
    462   Time now(base::Time::Now());
    463   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
    464   {
    465     sql::Connection db;
    466     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    467     sql::Statement s(db.GetUniqueStatement(
    468         "INSERT INTO downloads (id, full_path, url, start_time, "
    469         "received_bytes, total_bytes, state, end_time, opened) VALUES "
    470         "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
    471     int64 db_handle = 0;
    472     s.BindInt64(0, ++db_handle);
    473     s.BindString(1, "full_path");
    474     s.BindString(2, "http://whatever.com/index.html");
    475     s.BindInt64(3, now.ToTimeT());
    476     s.BindInt64(4, 100);
    477     s.BindInt64(5, 100);
    478     s.BindInt(6, 1);
    479     s.BindInt64(7, now.ToTimeT());
    480     s.BindInt(8, 1);
    481     ASSERT_TRUE(s.Run());
    482   }
    483   // Re-open the db using the HistoryDatabase, which should migrate to version
    484   // 26, creating the referrer column.
    485   CreateBackendAndDatabase();
    486   DeleteBackend();
    487   {
    488     // Re-open the db for manual manipulation.
    489     sql::Connection db;
    490     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    491     // The version should have been updated.
    492     int cur_version = HistoryDatabase::GetCurrentVersion();
    493     ASSERT_LE(26, cur_version);
    494     {
    495       sql::Statement s(db.GetUniqueStatement(
    496           "SELECT value FROM meta WHERE key = 'version'"));
    497       EXPECT_TRUE(s.Step());
    498       EXPECT_EQ(cur_version, s.ColumnInt(0));
    499     }
    500     {
    501       sql::Statement s(db.GetUniqueStatement(
    502           "SELECT referrer from downloads"));
    503       EXPECT_TRUE(s.Step());
    504       EXPECT_EQ(std::string(), s.ColumnString(0));
    505     }
    506   }
    507 }
    508 
    509 TEST_F(HistoryBackendDBTest, MigrateDownloadedByExtension) {
    510   Time now(base::Time::Now());
    511   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(26));
    512   {
    513     sql::Connection db;
    514     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    515     {
    516       sql::Statement s(db.GetUniqueStatement(
    517           "INSERT INTO downloads (id, current_path, target_path, start_time, "
    518           "received_bytes, total_bytes, state, danger_type, interrupt_reason, "
    519           "end_time, opened, referrer) VALUES "
    520           "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
    521       s.BindInt64(0, 1);
    522       s.BindString(1, "current_path");
    523       s.BindString(2, "target_path");
    524       s.BindInt64(3, now.ToTimeT());
    525       s.BindInt64(4, 100);
    526       s.BindInt64(5, 100);
    527       s.BindInt(6, 1);
    528       s.BindInt(7, 0);
    529       s.BindInt(8, 0);
    530       s.BindInt64(9, now.ToTimeT());
    531       s.BindInt(10, 1);
    532       s.BindString(11, "referrer");
    533       ASSERT_TRUE(s.Run());
    534     }
    535     {
    536       sql::Statement s(db.GetUniqueStatement(
    537           "INSERT INTO downloads_url_chains (id, chain_index, url) VALUES "
    538           "(?, ?, ?)"));
    539       s.BindInt64(0, 4);
    540       s.BindInt64(1, 0);
    541       s.BindString(2, "url");
    542       ASSERT_TRUE(s.Run());
    543     }
    544   }
    545   // Re-open the db using the HistoryDatabase, which should migrate to version
    546   // 27, creating the by_ext_id and by_ext_name columns.
    547   CreateBackendAndDatabase();
    548   DeleteBackend();
    549   {
    550     // Re-open the db for manual manipulation.
    551     sql::Connection db;
    552     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    553     // The version should have been updated.
    554     int cur_version = HistoryDatabase::GetCurrentVersion();
    555     ASSERT_LE(27, cur_version);
    556     {
    557       sql::Statement s(db.GetUniqueStatement(
    558           "SELECT value FROM meta WHERE key = 'version'"));
    559       EXPECT_TRUE(s.Step());
    560       EXPECT_EQ(cur_version, s.ColumnInt(0));
    561     }
    562     {
    563       sql::Statement s(db.GetUniqueStatement(
    564           "SELECT by_ext_id, by_ext_name from downloads"));
    565       EXPECT_TRUE(s.Step());
    566       EXPECT_EQ(std::string(), s.ColumnString(0));
    567       EXPECT_EQ(std::string(), s.ColumnString(1));
    568     }
    569   }
    570 }
    571 
    572 TEST_F(HistoryBackendDBTest, MigrateDownloadValidators) {
    573   Time now(base::Time::Now());
    574   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27));
    575   {
    576     sql::Connection db;
    577     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    578     {
    579       sql::Statement s(db.GetUniqueStatement(
    580           "INSERT INTO downloads (id, current_path, target_path, start_time, "
    581           "received_bytes, total_bytes, state, danger_type, interrupt_reason, "
    582           "end_time, opened, referrer, by_ext_id, by_ext_name) VALUES "
    583           "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
    584       s.BindInt64(0, 1);
    585       s.BindString(1, "current_path");
    586       s.BindString(2, "target_path");
    587       s.BindInt64(3, now.ToTimeT());
    588       s.BindInt64(4, 100);
    589       s.BindInt64(5, 100);
    590       s.BindInt(6, 1);
    591       s.BindInt(7, 0);
    592       s.BindInt(8, 0);
    593       s.BindInt64(9, now.ToTimeT());
    594       s.BindInt(10, 1);
    595       s.BindString(11, "referrer");
    596       s.BindString(12, "by extension ID");
    597       s.BindString(13, "by extension name");
    598       ASSERT_TRUE(s.Run());
    599     }
    600     {
    601       sql::Statement s(db.GetUniqueStatement(
    602           "INSERT INTO downloads_url_chains (id, chain_index, url) VALUES "
    603           "(?, ?, ?)"));
    604       s.BindInt64(0, 4);
    605       s.BindInt64(1, 0);
    606       s.BindString(2, "url");
    607       ASSERT_TRUE(s.Run());
    608     }
    609   }
    610   // Re-open the db using the HistoryDatabase, which should migrate to the
    611   // current version, creating the etag and last_modified columns.
    612   CreateBackendAndDatabase();
    613   DeleteBackend();
    614   {
    615     // Re-open the db for manual manipulation.
    616     sql::Connection db;
    617     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    618     // The version should have been updated.
    619     int cur_version = HistoryDatabase::GetCurrentVersion();
    620     ASSERT_LE(28, cur_version);
    621     {
    622       sql::Statement s(db.GetUniqueStatement(
    623           "SELECT value FROM meta WHERE key = 'version'"));
    624       EXPECT_TRUE(s.Step());
    625       EXPECT_EQ(cur_version, s.ColumnInt(0));
    626     }
    627     {
    628       sql::Statement s(db.GetUniqueStatement(
    629           "SELECT etag, last_modified from downloads"));
    630       EXPECT_TRUE(s.Step());
    631       EXPECT_EQ(std::string(), s.ColumnString(0));
    632       EXPECT_EQ(std::string(), s.ColumnString(1));
    633     }
    634   }
    635 }
    636 
    637 TEST_F(HistoryBackendDBTest, PurgeArchivedDatabase) {
    638   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27));
    639   ASSERT_NO_FATAL_FAILURE(CreateArchivedDB());
    640 
    641   ASSERT_TRUE(base::PathExists(
    642       history_dir_.Append(chrome::kArchivedHistoryFilename)));
    643 
    644   CreateBackendAndDatabase();
    645   DeleteBackend();
    646 
    647   // We do not retain expired history entries in an archived database as of M37.
    648   // Verify that any legacy archived database is deleted on start-up.
    649   ASSERT_FALSE(base::PathExists(
    650       history_dir_.Append(chrome::kArchivedHistoryFilename)));
    651 }
    652 
    653 TEST_F(HistoryBackendDBTest, MigrateDownloadMimeType) {
    654   Time now(base::Time::Now());
    655   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(28));
    656   {
    657     sql::Connection db;
    658     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    659     {
    660       sql::Statement s(db.GetUniqueStatement(
    661           "INSERT INTO downloads (id, current_path, target_path, start_time, "
    662           "received_bytes, total_bytes, state, danger_type, interrupt_reason, "
    663           "end_time, opened, referrer, by_ext_id, by_ext_name, etag, "
    664           "last_modified) VALUES "
    665           "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
    666       s.BindInt64(0, 1);
    667       s.BindString(1, "current_path");
    668       s.BindString(2, "target_path");
    669       s.BindInt64(3, now.ToTimeT());
    670       s.BindInt64(4, 100);
    671       s.BindInt64(5, 100);
    672       s.BindInt(6, 1);
    673       s.BindInt(7, 0);
    674       s.BindInt(8, 0);
    675       s.BindInt64(9, now.ToTimeT());
    676       s.BindInt(10, 1);
    677       s.BindString(11, "referrer");
    678       s.BindString(12, "by extension ID");
    679       s.BindString(13, "by extension name");
    680       s.BindString(14, "etag");
    681       s.BindInt64(15, now.ToTimeT());
    682       ASSERT_TRUE(s.Run());
    683     }
    684     {
    685       sql::Statement s(db.GetUniqueStatement(
    686           "INSERT INTO downloads_url_chains (id, chain_index, url) VALUES "
    687           "(?, ?, ?)"));
    688       s.BindInt64(0, 4);
    689       s.BindInt64(1, 0);
    690       s.BindString(2, "url");
    691       ASSERT_TRUE(s.Run());
    692     }
    693   }
    694   // Re-open the db using the HistoryDatabase, which should migrate to the
    695   // current version, creating themime_type abd original_mime_type columns.
    696   CreateBackendAndDatabase();
    697   DeleteBackend();
    698   {
    699     // Re-open the db for manual manipulation.
    700     sql::Connection db;
    701     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    702     // The version should have been updated.
    703     int cur_version = HistoryDatabase::GetCurrentVersion();
    704     ASSERT_LE(29, cur_version);
    705     {
    706       sql::Statement s(db.GetUniqueStatement(
    707           "SELECT value FROM meta WHERE key = 'version'"));
    708       EXPECT_TRUE(s.Step());
    709       EXPECT_EQ(cur_version, s.ColumnInt(0));
    710     }
    711     {
    712       sql::Statement s(db.GetUniqueStatement(
    713           "SELECT mime_type, original_mime_type from downloads"));
    714       EXPECT_TRUE(s.Step());
    715       EXPECT_EQ(std::string(), s.ColumnString(0));
    716       EXPECT_EQ(std::string(), s.ColumnString(1));
    717     }
    718   }
    719 }
    720 
    721 TEST_F(HistoryBackendDBTest, ConfirmDownloadRowCreateAndDelete) {
    722   // Create the DB.
    723   CreateBackendAndDatabase();
    724 
    725   base::Time now(base::Time::Now());
    726 
    727   // Add some downloads.
    728   uint32 id1 = 1, id2 = 2, id3 = 3;
    729   AddDownload(id1, DownloadItem::COMPLETE, now);
    730   AddDownload(id2, DownloadItem::COMPLETE, now + base::TimeDelta::FromDays(2));
    731   AddDownload(id3, DownloadItem::COMPLETE, now - base::TimeDelta::FromDays(2));
    732 
    733   // Confirm that resulted in the correct number of rows in the DB.
    734   DeleteBackend();
    735   {
    736     sql::Connection db;
    737     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    738     sql::Statement statement(db.GetUniqueStatement(
    739         "Select Count(*) from downloads"));
    740     EXPECT_TRUE(statement.Step());
    741     EXPECT_EQ(3, statement.ColumnInt(0));
    742 
    743     sql::Statement statement1(db.GetUniqueStatement(
    744         "Select Count(*) from downloads_url_chains"));
    745     EXPECT_TRUE(statement1.Step());
    746     EXPECT_EQ(3, statement1.ColumnInt(0));
    747   }
    748 
    749   // Delete some rows and make sure the results are still correct.
    750   CreateBackendAndDatabase();
    751   db_->RemoveDownload(id2);
    752   db_->RemoveDownload(id3);
    753   DeleteBackend();
    754   {
    755     sql::Connection db;
    756     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    757     sql::Statement statement(db.GetUniqueStatement(
    758         "Select Count(*) from downloads"));
    759     EXPECT_TRUE(statement.Step());
    760     EXPECT_EQ(1, statement.ColumnInt(0));
    761 
    762     sql::Statement statement1(db.GetUniqueStatement(
    763         "Select Count(*) from downloads_url_chains"));
    764     EXPECT_TRUE(statement1.Step());
    765     EXPECT_EQ(1, statement1.ColumnInt(0));
    766   }
    767 }
    768 
    769 TEST_F(HistoryBackendDBTest, DownloadNukeRecordsMissingURLs) {
    770   CreateBackendAndDatabase();
    771   base::Time now(base::Time::Now());
    772   std::vector<GURL> url_chain;
    773   DownloadRow download(base::FilePath(FILE_PATH_LITERAL("foo-path")),
    774                        base::FilePath(FILE_PATH_LITERAL("foo-path")),
    775                        url_chain,
    776                        GURL(std::string()),
    777                        "application/octet-stream",
    778                        "application/octet-stream",
    779                        now,
    780                        now,
    781                        std::string(),
    782                        std::string(),
    783                        0,
    784                        512,
    785                        DownloadItem::COMPLETE,
    786                        content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
    787                        content::DOWNLOAD_INTERRUPT_REASON_NONE,
    788                        1,
    789                        0,
    790                        "by_ext_id",
    791                        "by_ext_name");
    792 
    793   // Creating records without any urls should fail.
    794   EXPECT_FALSE(db_->CreateDownload(download));
    795 
    796   download.url_chain.push_back(GURL("foo-url"));
    797   EXPECT_TRUE(db_->CreateDownload(download));
    798 
    799   // Pretend that the URLs were dropped.
    800   DeleteBackend();
    801   {
    802     sql::Connection db;
    803     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    804     sql::Statement statement(db.GetUniqueStatement(
    805         "DELETE FROM downloads_url_chains WHERE id=1"));
    806     ASSERT_TRUE(statement.Run());
    807   }
    808   CreateBackendAndDatabase();
    809   std::vector<DownloadRow> downloads;
    810   db_->QueryDownloads(&downloads);
    811   EXPECT_EQ(0U, downloads.size());
    812 
    813   // QueryDownloads should have nuked the corrupt record.
    814   DeleteBackend();
    815   {
    816     sql::Connection db;
    817     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    818     {
    819       sql::Statement statement(db.GetUniqueStatement(
    820             "SELECT count(*) from downloads"));
    821       ASSERT_TRUE(statement.Step());
    822       EXPECT_EQ(0, statement.ColumnInt(0));
    823     }
    824   }
    825 }
    826 
    827 TEST_F(HistoryBackendDBTest, ConfirmDownloadInProgressCleanup) {
    828   // Create the DB.
    829   CreateBackendAndDatabase();
    830 
    831   base::Time now(base::Time::Now());
    832 
    833   // Put an IN_PROGRESS download in the DB.
    834   AddDownload(1, DownloadItem::IN_PROGRESS, now);
    835 
    836   // Confirm that they made it into the DB unchanged.
    837   DeleteBackend();
    838   {
    839     sql::Connection db;
    840     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    841     sql::Statement statement(db.GetUniqueStatement(
    842         "Select Count(*) from downloads"));
    843     EXPECT_TRUE(statement.Step());
    844     EXPECT_EQ(1, statement.ColumnInt(0));
    845 
    846     sql::Statement statement1(db.GetUniqueStatement(
    847         "Select state, interrupt_reason from downloads"));
    848     EXPECT_TRUE(statement1.Step());
    849     EXPECT_EQ(DownloadDatabase::kStateInProgress, statement1.ColumnInt(0));
    850     EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, statement1.ColumnInt(1));
    851     EXPECT_FALSE(statement1.Step());
    852   }
    853 
    854   // Read in the DB through query downloads, then test that the
    855   // right transformation was returned.
    856   CreateBackendAndDatabase();
    857   std::vector<DownloadRow> results;
    858   db_->QueryDownloads(&results);
    859   ASSERT_EQ(1u, results.size());
    860   EXPECT_EQ(content::DownloadItem::INTERRUPTED, results[0].state);
    861   EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH,
    862             results[0].interrupt_reason);
    863 
    864   // Allow the update to propagate, shut down the DB, and confirm that
    865   // the query updated the on disk database as well.
    866   base::MessageLoop::current()->RunUntilIdle();
    867   DeleteBackend();
    868   {
    869     sql::Connection db;
    870     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
    871     sql::Statement statement(db.GetUniqueStatement(
    872         "Select Count(*) from downloads"));
    873     EXPECT_TRUE(statement.Step());
    874     EXPECT_EQ(1, statement.ColumnInt(0));
    875 
    876     sql::Statement statement1(db.GetUniqueStatement(
    877         "Select state, interrupt_reason from downloads"));
    878     EXPECT_TRUE(statement1.Step());
    879     EXPECT_EQ(DownloadDatabase::kStateInterrupted, statement1.ColumnInt(0));
    880     EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH,
    881               statement1.ColumnInt(1));
    882     EXPECT_FALSE(statement1.Step());
    883   }
    884 }
    885 
    886 struct InterruptReasonAssociation {
    887   std::string name;
    888   int value;
    889 };
    890 
    891 // Test is dependent on interrupt reasons being listed in header file
    892 // in order.
    893 const InterruptReasonAssociation current_reasons[] = {
    894 #define INTERRUPT_REASON(a, b) { #a, b },
    895 #include "content/public/browser/download_interrupt_reason_values.h"
    896 #undef INTERRUPT_REASON
    897 };
    898 
    899 // This represents a list of all reasons we've previously used;
    900 // Do Not Remove Any Entries From This List.
    901 const InterruptReasonAssociation historical_reasons[] = {
    902   {"FILE_FAILED",  1},
    903   {"FILE_ACCESS_DENIED",  2},
    904   {"FILE_NO_SPACE",  3},
    905   {"FILE_NAME_TOO_LONG",  5},
    906   {"FILE_TOO_LARGE",  6},
    907   {"FILE_VIRUS_INFECTED",  7},
    908   {"FILE_TRANSIENT_ERROR",  10},
    909   {"FILE_BLOCKED",  11},
    910   {"FILE_SECURITY_CHECK_FAILED",  12},
    911   {"FILE_TOO_SHORT", 13},
    912   {"NETWORK_FAILED",  20},
    913   {"NETWORK_TIMEOUT",  21},
    914   {"NETWORK_DISCONNECTED",  22},
    915   {"NETWORK_SERVER_DOWN",  23},
    916   {"NETWORK_INVALID_REQUEST", 24},
    917   {"SERVER_FAILED",  30},
    918   {"SERVER_NO_RANGE",  31},
    919   {"SERVER_PRECONDITION",  32},
    920   {"SERVER_BAD_CONTENT",  33},
    921   {"USER_CANCELED",  40},
    922   {"USER_SHUTDOWN",  41},
    923   {"CRASH",  50},
    924 };
    925 
    926 // Make sure no one has changed a DownloadInterruptReason we've previously
    927 // persisted.
    928 TEST_F(HistoryBackendDBTest,
    929        ConfirmDownloadInterruptReasonBackwardsCompatible) {
    930   // Are there any cases in which a historical number has been repurposed
    931   // for an error other than it's original?
    932   for (size_t i = 0; i < arraysize(current_reasons); i++) {
    933     const InterruptReasonAssociation& cur_reason(current_reasons[i]);
    934     bool found = false;
    935 
    936     for (size_t j = 0; j < arraysize(historical_reasons); ++j) {
    937       const InterruptReasonAssociation& hist_reason(historical_reasons[j]);
    938 
    939       if (hist_reason.value == cur_reason.value) {
    940         EXPECT_EQ(cur_reason.name, hist_reason.name)
    941             << "Same integer value used for old error \""
    942             << hist_reason.name
    943             << "\" as for new error \""
    944             << cur_reason.name
    945             << "\"." << std::endl
    946             << "**This will cause database conflicts with persisted values**"
    947             << std::endl
    948             << "Please assign a new, non-conflicting value for the new error.";
    949       }
    950 
    951       if (hist_reason.name == cur_reason.name) {
    952         EXPECT_EQ(cur_reason.value, hist_reason.value)
    953             << "Same name (\"" << hist_reason.name
    954             << "\") maps to a different value historically ("
    955             << hist_reason.value << ") and currently ("
    956             << cur_reason.value << ")" << std::endl
    957             << "This may cause database conflicts with persisted values"
    958             << std::endl
    959             << "If this error is the same as the old one, you should"
    960             << std::endl
    961             << "use the old value, and if it is different, you should"
    962             << std::endl
    963             << "use a new name.";
    964 
    965         found = true;
    966       }
    967     }
    968 
    969     EXPECT_TRUE(found)
    970         << "Error \"" << cur_reason.name << "\" not found in historical list."
    971         << std::endl
    972         << "Please add it.";
    973   }
    974 }
    975 
    976 class HistoryTest : public testing::Test {
    977  public:
    978   HistoryTest()
    979       : got_thumbnail_callback_(false),
    980         redirect_query_success_(false),
    981         query_url_success_(false) {
    982   }
    983 
    984   virtual ~HistoryTest() {
    985   }
    986 
    987   void OnSegmentUsageAvailable(CancelableRequestProvider::Handle handle,
    988                                std::vector<PageUsageData*>* data) {
    989     page_usage_data_.swap(*data);
    990     base::MessageLoop::current()->Quit();
    991   }
    992 
    993   void OnDeleteURLsDone(CancelableRequestProvider::Handle handle) {
    994     base::MessageLoop::current()->Quit();
    995   }
    996 
    997   void OnMostVisitedURLsAvailable(CancelableRequestProvider::Handle handle,
    998                                   MostVisitedURLList url_list) {
    999     most_visited_urls_.swap(url_list);
   1000     base::MessageLoop::current()->Quit();
   1001   }
   1002 
   1003  protected:
   1004   friend class BackendDelegate;
   1005 
   1006   // testing::Test
   1007   virtual void SetUp() {
   1008     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   1009     history_dir_ = temp_dir_.path().AppendASCII("HistoryTest");
   1010     ASSERT_TRUE(base::CreateDirectory(history_dir_));
   1011     history_service_.reset(new HistoryService);
   1012     if (!history_service_->Init(history_dir_)) {
   1013       history_service_.reset();
   1014       ADD_FAILURE();
   1015     }
   1016   }
   1017 
   1018   virtual void TearDown() {
   1019     if (history_service_)
   1020       CleanupHistoryService();
   1021 
   1022     // Make sure we don't have any event pending that could disrupt the next
   1023     // test.
   1024     base::MessageLoop::current()->PostTask(FROM_HERE,
   1025                                            base::MessageLoop::QuitClosure());
   1026     base::MessageLoop::current()->Run();
   1027   }
   1028 
   1029   void CleanupHistoryService() {
   1030     DCHECK(history_service_);
   1031 
   1032     history_service_->ClearCachedDataForContextID(0);
   1033     history_service_->SetOnBackendDestroyTask(base::MessageLoop::QuitClosure());
   1034     history_service_->Cleanup();
   1035     history_service_.reset();
   1036 
   1037     // Wait for the backend class to terminate before deleting the files and
   1038     // moving to the next test. Note: if this never terminates, somebody is
   1039     // probably leaking a reference to the history backend, so it never calls
   1040     // our destroy task.
   1041     base::MessageLoop::current()->Run();
   1042   }
   1043 
   1044   // Fills the query_url_row_ and query_url_visits_ structures with the
   1045   // information about the given URL and returns true. If the URL was not
   1046   // found, this will return false and those structures will not be changed.
   1047   bool QueryURL(HistoryService* history, const GURL& url) {
   1048     history_service_->QueryURL(
   1049         url,
   1050         true,
   1051         base::Bind(&HistoryTest::SaveURLAndQuit, base::Unretained(this)),
   1052         &tracker_);
   1053     base::MessageLoop::current()->Run();  // Will be exited in SaveURLAndQuit.
   1054     return query_url_success_;
   1055   }
   1056 
   1057   // Callback for HistoryService::QueryURL.
   1058   void SaveURLAndQuit(bool success,
   1059                       const URLRow& url_row,
   1060                       const VisitVector& visits) {
   1061     query_url_success_ = success;
   1062     if (query_url_success_) {
   1063       query_url_row_ = url_row;
   1064       query_url_visits_ = visits;
   1065     } else {
   1066       query_url_row_ = URLRow();
   1067       query_url_visits_.clear();
   1068     }
   1069     base::MessageLoop::current()->Quit();
   1070   }
   1071 
   1072   // Fills in saved_redirects_ with the redirect information for the given URL,
   1073   // returning true on success. False means the URL was not found.
   1074   bool QueryRedirectsFrom(HistoryService* history, const GURL& url) {
   1075     history_service_->QueryRedirectsFrom(
   1076         url, &consumer_,
   1077         base::Bind(&HistoryTest::OnRedirectQueryComplete,
   1078                    base::Unretained(this)));
   1079     base::MessageLoop::current()->Run();  // Will be exited in *QueryComplete.
   1080     return redirect_query_success_;
   1081   }
   1082 
   1083   // Callback for QueryRedirects.
   1084   void OnRedirectQueryComplete(HistoryService::Handle handle,
   1085                                GURL url,
   1086                                bool success,
   1087                                history::RedirectList* redirects) {
   1088     redirect_query_success_ = success;
   1089     if (redirect_query_success_)
   1090       saved_redirects_.swap(*redirects);
   1091     else
   1092       saved_redirects_.clear();
   1093     base::MessageLoop::current()->Quit();
   1094   }
   1095 
   1096   base::ScopedTempDir temp_dir_;
   1097 
   1098   base::MessageLoopForUI message_loop_;
   1099 
   1100   // PageUsageData vector to test segments.
   1101   ScopedVector<PageUsageData> page_usage_data_;
   1102 
   1103   MostVisitedURLList most_visited_urls_;
   1104 
   1105   // When non-NULL, this will be deleted on tear down and we will block until
   1106   // the backend thread has completed. This allows tests for the history
   1107   // service to use this feature, but other tests to ignore this.
   1108   scoped_ptr<HistoryService> history_service_;
   1109 
   1110   // names of the database files
   1111   base::FilePath history_dir_;
   1112 
   1113   // Set by the thumbnail callback when we get data, you should be sure to
   1114   // clear this before issuing a thumbnail request.
   1115   bool got_thumbnail_callback_;
   1116   std::vector<unsigned char> thumbnail_data_;
   1117 
   1118   // Set by the redirect callback when we get data. You should be sure to
   1119   // clear this before issuing a redirect request.
   1120   history::RedirectList saved_redirects_;
   1121   bool redirect_query_success_;
   1122 
   1123   // For history requests.
   1124   base::CancelableTaskTracker tracker_;
   1125   CancelableRequestConsumer consumer_;
   1126 
   1127   // For saving URL info after a call to QueryURL
   1128   bool query_url_success_;
   1129   URLRow query_url_row_;
   1130   VisitVector query_url_visits_;
   1131 };
   1132 
   1133 TEST_F(HistoryTest, AddPage) {
   1134   ASSERT_TRUE(history_service_.get());
   1135   // Add the page once from a child frame.
   1136   const GURL test_url("http://www.google.com/");
   1137   history_service_->AddPage(test_url, base::Time::Now(), NULL, 0, GURL(),
   1138                             history::RedirectList(),
   1139                             content::PAGE_TRANSITION_MANUAL_SUBFRAME,
   1140                             history::SOURCE_BROWSED, false);
   1141   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1142   EXPECT_EQ(1, query_url_row_.visit_count());
   1143   EXPECT_EQ(0, query_url_row_.typed_count());
   1144   EXPECT_TRUE(query_url_row_.hidden());  // Hidden because of child frame.
   1145 
   1146   // Add the page once from the main frame (should unhide it).
   1147   history_service_->AddPage(test_url, base::Time::Now(), NULL, 0, GURL(),
   1148                    history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1149                    history::SOURCE_BROWSED, false);
   1150   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1151   EXPECT_EQ(2, query_url_row_.visit_count());  // Added twice.
   1152   EXPECT_EQ(0, query_url_row_.typed_count());  // Never typed.
   1153   EXPECT_FALSE(query_url_row_.hidden());  // Because loaded in main frame.
   1154 }
   1155 
   1156 TEST_F(HistoryTest, AddRedirect) {
   1157   ASSERT_TRUE(history_service_.get());
   1158   const char* first_sequence[] = {
   1159     "http://first.page.com/",
   1160     "http://second.page.com/"};
   1161   int first_count = arraysize(first_sequence);
   1162   history::RedirectList first_redirects;
   1163   for (int i = 0; i < first_count; i++)
   1164     first_redirects.push_back(GURL(first_sequence[i]));
   1165 
   1166   // Add the sequence of pages as a server with no referrer. Note that we need
   1167   // to have a non-NULL page ID scope.
   1168   history_service_->AddPage(
   1169       first_redirects.back(), base::Time::Now(),
   1170       reinterpret_cast<ContextID>(1), 0, GURL(), first_redirects,
   1171       content::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED, true);
   1172 
   1173   // The first page should be added once with a link visit type (because we set
   1174   // LINK when we added the original URL, and a referrer of nowhere (0).
   1175   EXPECT_TRUE(QueryURL(history_service_.get(), first_redirects[0]));
   1176   EXPECT_EQ(1, query_url_row_.visit_count());
   1177   ASSERT_EQ(1U, query_url_visits_.size());
   1178   int64 first_visit = query_url_visits_[0].visit_id;
   1179   EXPECT_EQ(content::PAGE_TRANSITION_LINK |
   1180             content::PAGE_TRANSITION_CHAIN_START,
   1181             query_url_visits_[0].transition);
   1182   EXPECT_EQ(0, query_url_visits_[0].referring_visit);  // No referrer.
   1183 
   1184   // The second page should be a server redirect type with a referrer of the
   1185   // first page.
   1186   EXPECT_TRUE(QueryURL(history_service_.get(), first_redirects[1]));
   1187   EXPECT_EQ(1, query_url_row_.visit_count());
   1188   ASSERT_EQ(1U, query_url_visits_.size());
   1189   int64 second_visit = query_url_visits_[0].visit_id;
   1190   EXPECT_EQ(content::PAGE_TRANSITION_SERVER_REDIRECT |
   1191             content::PAGE_TRANSITION_CHAIN_END,
   1192             query_url_visits_[0].transition);
   1193   EXPECT_EQ(first_visit, query_url_visits_[0].referring_visit);
   1194 
   1195   // Check that the redirect finding function successfully reports it.
   1196   saved_redirects_.clear();
   1197   QueryRedirectsFrom(history_service_.get(), first_redirects[0]);
   1198   ASSERT_EQ(1U, saved_redirects_.size());
   1199   EXPECT_EQ(first_redirects[1], saved_redirects_[0]);
   1200 
   1201   // Now add a client redirect from that second visit to a third, client
   1202   // redirects are tracked by the RenderView prior to updating history,
   1203   // so we pass in a CLIENT_REDIRECT qualifier to mock that behavior.
   1204   history::RedirectList second_redirects;
   1205   second_redirects.push_back(first_redirects[1]);
   1206   second_redirects.push_back(GURL("http://last.page.com/"));
   1207   history_service_->AddPage(second_redirects[1], base::Time::Now(),
   1208                    reinterpret_cast<ContextID>(1), 1,
   1209                    second_redirects[0], second_redirects,
   1210                    static_cast<content::PageTransition>(
   1211                        content::PAGE_TRANSITION_LINK |
   1212                        content::PAGE_TRANSITION_CLIENT_REDIRECT),
   1213                    history::SOURCE_BROWSED, true);
   1214 
   1215   // The last page (source of the client redirect) should NOT have an
   1216   // additional visit added, because it was a client redirect (normally it
   1217   // would). We should only have 1 left over from the first sequence.
   1218   EXPECT_TRUE(QueryURL(history_service_.get(), second_redirects[0]));
   1219   EXPECT_EQ(1, query_url_row_.visit_count());
   1220 
   1221   // The final page should be set as a client redirect from the previous visit.
   1222   EXPECT_TRUE(QueryURL(history_service_.get(), second_redirects[1]));
   1223   EXPECT_EQ(1, query_url_row_.visit_count());
   1224   ASSERT_EQ(1U, query_url_visits_.size());
   1225   EXPECT_EQ(content::PAGE_TRANSITION_CLIENT_REDIRECT |
   1226             content::PAGE_TRANSITION_CHAIN_END,
   1227             query_url_visits_[0].transition);
   1228   EXPECT_EQ(second_visit, query_url_visits_[0].referring_visit);
   1229 }
   1230 
   1231 TEST_F(HistoryTest, MakeIntranetURLsTyped) {
   1232   ASSERT_TRUE(history_service_.get());
   1233 
   1234   // Add a non-typed visit to an intranet URL on an unvisited host.  This should
   1235   // get promoted to a typed visit.
   1236   const GURL test_url("http://intranet_host/path");
   1237   history_service_->AddPage(
   1238       test_url, base::Time::Now(), NULL, 0, GURL(),
   1239       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1240       history::SOURCE_BROWSED, false);
   1241   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1242   EXPECT_EQ(1, query_url_row_.visit_count());
   1243   EXPECT_EQ(1, query_url_row_.typed_count());
   1244   ASSERT_EQ(1U, query_url_visits_.size());
   1245   EXPECT_EQ(content::PAGE_TRANSITION_TYPED,
   1246       content::PageTransitionStripQualifier(query_url_visits_[0].transition));
   1247 
   1248   // Add more visits on the same host.  None of these should be promoted since
   1249   // there is already a typed visit.
   1250 
   1251   // Different path.
   1252   const GURL test_url2("http://intranet_host/different_path");
   1253   history_service_->AddPage(
   1254       test_url2, base::Time::Now(), NULL, 0, GURL(),
   1255       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1256       history::SOURCE_BROWSED, false);
   1257   EXPECT_TRUE(QueryURL(history_service_.get(), test_url2));
   1258   EXPECT_EQ(1, query_url_row_.visit_count());
   1259   EXPECT_EQ(0, query_url_row_.typed_count());
   1260   ASSERT_EQ(1U, query_url_visits_.size());
   1261   EXPECT_EQ(content::PAGE_TRANSITION_LINK,
   1262       content::PageTransitionStripQualifier(query_url_visits_[0].transition));
   1263 
   1264   // No path.
   1265   const GURL test_url3("http://intranet_host/");
   1266   history_service_->AddPage(
   1267       test_url3, base::Time::Now(), NULL, 0, GURL(),
   1268       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1269       history::SOURCE_BROWSED, false);
   1270   EXPECT_TRUE(QueryURL(history_service_.get(), test_url3));
   1271   EXPECT_EQ(1, query_url_row_.visit_count());
   1272   EXPECT_EQ(0, query_url_row_.typed_count());
   1273   ASSERT_EQ(1U, query_url_visits_.size());
   1274   EXPECT_EQ(content::PAGE_TRANSITION_LINK,
   1275       content::PageTransitionStripQualifier(query_url_visits_[0].transition));
   1276 
   1277   // Different scheme.
   1278   const GURL test_url4("https://intranet_host/");
   1279   history_service_->AddPage(
   1280       test_url4, base::Time::Now(), NULL, 0, GURL(),
   1281       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1282       history::SOURCE_BROWSED, false);
   1283   EXPECT_TRUE(QueryURL(history_service_.get(), test_url4));
   1284   EXPECT_EQ(1, query_url_row_.visit_count());
   1285   EXPECT_EQ(0, query_url_row_.typed_count());
   1286   ASSERT_EQ(1U, query_url_visits_.size());
   1287   EXPECT_EQ(content::PAGE_TRANSITION_LINK,
   1288       content::PageTransitionStripQualifier(query_url_visits_[0].transition));
   1289 
   1290   // Different transition.
   1291   const GURL test_url5("http://intranet_host/another_path");
   1292   history_service_->AddPage(
   1293       test_url5, base::Time::Now(), NULL, 0, GURL(),
   1294       history::RedirectList(),
   1295       content::PAGE_TRANSITION_AUTO_BOOKMARK,
   1296       history::SOURCE_BROWSED, false);
   1297   EXPECT_TRUE(QueryURL(history_service_.get(), test_url5));
   1298   EXPECT_EQ(1, query_url_row_.visit_count());
   1299   EXPECT_EQ(0, query_url_row_.typed_count());
   1300   ASSERT_EQ(1U, query_url_visits_.size());
   1301   EXPECT_EQ(content::PAGE_TRANSITION_AUTO_BOOKMARK,
   1302       content::PageTransitionStripQualifier(query_url_visits_[0].transition));
   1303 
   1304   // Original URL.
   1305   history_service_->AddPage(
   1306       test_url, base::Time::Now(), NULL, 0, GURL(),
   1307       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1308       history::SOURCE_BROWSED, false);
   1309   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1310   EXPECT_EQ(2, query_url_row_.visit_count());
   1311   EXPECT_EQ(1, query_url_row_.typed_count());
   1312   ASSERT_EQ(2U, query_url_visits_.size());
   1313   EXPECT_EQ(content::PAGE_TRANSITION_LINK,
   1314       content::PageTransitionStripQualifier(query_url_visits_[1].transition));
   1315 }
   1316 
   1317 TEST_F(HistoryTest, Typed) {
   1318   ASSERT_TRUE(history_service_.get());
   1319 
   1320   // Add the page once as typed.
   1321   const GURL test_url("http://www.google.com/");
   1322   history_service_->AddPage(
   1323       test_url, base::Time::Now(), NULL, 0, GURL(),
   1324       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1325       history::SOURCE_BROWSED, false);
   1326   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1327 
   1328   // We should have the same typed & visit count.
   1329   EXPECT_EQ(1, query_url_row_.visit_count());
   1330   EXPECT_EQ(1, query_url_row_.typed_count());
   1331 
   1332   // Add the page again not typed.
   1333   history_service_->AddPage(
   1334       test_url, base::Time::Now(), NULL, 0, GURL(),
   1335       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1336       history::SOURCE_BROWSED, false);
   1337   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1338 
   1339   // The second time should not have updated the typed count.
   1340   EXPECT_EQ(2, query_url_row_.visit_count());
   1341   EXPECT_EQ(1, query_url_row_.typed_count());
   1342 
   1343   // Add the page again as a generated URL.
   1344   history_service_->AddPage(
   1345       test_url, base::Time::Now(), NULL, 0, GURL(),
   1346       history::RedirectList(), content::PAGE_TRANSITION_GENERATED,
   1347       history::SOURCE_BROWSED, false);
   1348   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1349 
   1350   // This should have worked like a link click.
   1351   EXPECT_EQ(3, query_url_row_.visit_count());
   1352   EXPECT_EQ(1, query_url_row_.typed_count());
   1353 
   1354   // Add the page again as a reload.
   1355   history_service_->AddPage(
   1356       test_url, base::Time::Now(), NULL, 0, GURL(),
   1357       history::RedirectList(), content::PAGE_TRANSITION_RELOAD,
   1358       history::SOURCE_BROWSED, false);
   1359   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1360 
   1361   // This should not have incremented any visit counts.
   1362   EXPECT_EQ(3, query_url_row_.visit_count());
   1363   EXPECT_EQ(1, query_url_row_.typed_count());
   1364 }
   1365 
   1366 TEST_F(HistoryTest, SetTitle) {
   1367   ASSERT_TRUE(history_service_.get());
   1368 
   1369   // Add a URL.
   1370   const GURL existing_url("http://www.google.com/");
   1371   history_service_->AddPage(
   1372       existing_url, base::Time::Now(), history::SOURCE_BROWSED);
   1373 
   1374   // Set some title.
   1375   const base::string16 existing_title = base::UTF8ToUTF16("Google");
   1376   history_service_->SetPageTitle(existing_url, existing_title);
   1377 
   1378   // Make sure the title got set.
   1379   EXPECT_TRUE(QueryURL(history_service_.get(), existing_url));
   1380   EXPECT_EQ(existing_title, query_url_row_.title());
   1381 
   1382   // set a title on a nonexistent page
   1383   const GURL nonexistent_url("http://news.google.com/");
   1384   const base::string16 nonexistent_title = base::UTF8ToUTF16("Google News");
   1385   history_service_->SetPageTitle(nonexistent_url, nonexistent_title);
   1386 
   1387   // Make sure nothing got written.
   1388   EXPECT_FALSE(QueryURL(history_service_.get(), nonexistent_url));
   1389   EXPECT_EQ(base::string16(), query_url_row_.title());
   1390 
   1391   // TODO(brettw) this should also test redirects, which get the title of the
   1392   // destination page.
   1393 }
   1394 
   1395 // crbug.com/159387: This test fails when daylight savings time ends.
   1396 TEST_F(HistoryTest, DISABLED_Segments) {
   1397   ASSERT_TRUE(history_service_.get());
   1398 
   1399   static ContextID context_id = static_cast<ContextID>(this);
   1400 
   1401   // Add a URL.
   1402   const GURL existing_url("http://www.google.com/");
   1403   history_service_->AddPage(
   1404       existing_url, base::Time::Now(), context_id, 0, GURL(),
   1405       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1406       history::SOURCE_BROWSED, false);
   1407 
   1408   // Make sure a segment was created.
   1409   history_service_->QuerySegmentUsageSince(
   1410       &consumer_, Time::Now() - TimeDelta::FromDays(1), 10,
   1411       base::Bind(&HistoryTest::OnSegmentUsageAvailable,
   1412                  base::Unretained(this)));
   1413 
   1414   // Wait for processing.
   1415   base::MessageLoop::current()->Run();
   1416 
   1417   ASSERT_EQ(1U, page_usage_data_.size());
   1418   EXPECT_TRUE(page_usage_data_[0]->GetURL() == existing_url);
   1419   EXPECT_DOUBLE_EQ(3.0, page_usage_data_[0]->GetScore());
   1420 
   1421   // Add a URL which doesn't create a segment.
   1422   const GURL link_url("http://yahoo.com/");
   1423   history_service_->AddPage(
   1424       link_url, base::Time::Now(), context_id, 0, GURL(),
   1425       history::RedirectList(), content::PAGE_TRANSITION_LINK,
   1426       history::SOURCE_BROWSED, false);
   1427 
   1428   // Query again
   1429   history_service_->QuerySegmentUsageSince(
   1430       &consumer_, Time::Now() - TimeDelta::FromDays(1), 10,
   1431       base::Bind(&HistoryTest::OnSegmentUsageAvailable,
   1432                  base::Unretained(this)));
   1433 
   1434   // Wait for processing.
   1435   base::MessageLoop::current()->Run();
   1436 
   1437   // Make sure we still have one segment.
   1438   ASSERT_EQ(1U, page_usage_data_.size());
   1439   EXPECT_TRUE(page_usage_data_[0]->GetURL() == existing_url);
   1440 
   1441   // Add a page linked from existing_url.
   1442   history_service_->AddPage(
   1443       GURL("http://www.google.com/foo"), base::Time::Now(),
   1444       context_id, 3, existing_url, history::RedirectList(),
   1445       content::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED,
   1446       false);
   1447 
   1448   // Query again
   1449   history_service_->QuerySegmentUsageSince(
   1450       &consumer_, Time::Now() - TimeDelta::FromDays(1), 10,
   1451       base::Bind(&HistoryTest::OnSegmentUsageAvailable,
   1452                  base::Unretained(this)));
   1453 
   1454   // Wait for processing.
   1455   base::MessageLoop::current()->Run();
   1456 
   1457   // Make sure we still have one segment.
   1458   ASSERT_EQ(1U, page_usage_data_.size());
   1459   EXPECT_TRUE(page_usage_data_[0]->GetURL() == existing_url);
   1460 
   1461   // However, the score should have increased.
   1462   EXPECT_GT(page_usage_data_[0]->GetScore(), 5.0);
   1463 }
   1464 
   1465 TEST_F(HistoryTest, MostVisitedURLs) {
   1466   ASSERT_TRUE(history_service_.get());
   1467 
   1468   const GURL url0("http://www.google.com/url0/");
   1469   const GURL url1("http://www.google.com/url1/");
   1470   const GURL url2("http://www.google.com/url2/");
   1471   const GURL url3("http://www.google.com/url3/");
   1472   const GURL url4("http://www.google.com/url4/");
   1473 
   1474   static ContextID context_id = static_cast<ContextID>(this);
   1475 
   1476   // Add two pages.
   1477   history_service_->AddPage(
   1478       url0, base::Time::Now(), context_id, 0, GURL(),
   1479       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1480       history::SOURCE_BROWSED, false);
   1481   history_service_->AddPage(
   1482       url1, base::Time::Now(), context_id, 0, GURL(),
   1483       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1484       history::SOURCE_BROWSED, false);
   1485   history_service_->QueryMostVisitedURLs(
   1486       20, 90, &consumer_,
   1487       base::Bind(
   1488           &HistoryTest::OnMostVisitedURLsAvailable,
   1489           base::Unretained(this)));
   1490   base::MessageLoop::current()->Run();
   1491 
   1492   EXPECT_EQ(2U, most_visited_urls_.size());
   1493   EXPECT_EQ(url0, most_visited_urls_[0].url);
   1494   EXPECT_EQ(url1, most_visited_urls_[1].url);
   1495 
   1496   // Add another page.
   1497   history_service_->AddPage(
   1498       url2, base::Time::Now(), context_id, 0, GURL(),
   1499       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1500       history::SOURCE_BROWSED, false);
   1501   history_service_->QueryMostVisitedURLs(
   1502       20, 90, &consumer_,
   1503       base::Bind(
   1504           &HistoryTest::OnMostVisitedURLsAvailable,
   1505           base::Unretained(this)));
   1506   base::MessageLoop::current()->Run();
   1507 
   1508   EXPECT_EQ(3U, most_visited_urls_.size());
   1509   EXPECT_EQ(url0, most_visited_urls_[0].url);
   1510   EXPECT_EQ(url1, most_visited_urls_[1].url);
   1511   EXPECT_EQ(url2, most_visited_urls_[2].url);
   1512 
   1513   // Revisit url2, making it the top URL.
   1514   history_service_->AddPage(
   1515       url2, base::Time::Now(), context_id, 0, GURL(),
   1516       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1517       history::SOURCE_BROWSED, false);
   1518   history_service_->QueryMostVisitedURLs(
   1519       20, 90, &consumer_,
   1520       base::Bind(
   1521           &HistoryTest::OnMostVisitedURLsAvailable,
   1522           base::Unretained(this)));
   1523   base::MessageLoop::current()->Run();
   1524 
   1525   EXPECT_EQ(3U, most_visited_urls_.size());
   1526   EXPECT_EQ(url2, most_visited_urls_[0].url);
   1527   EXPECT_EQ(url0, most_visited_urls_[1].url);
   1528   EXPECT_EQ(url1, most_visited_urls_[2].url);
   1529 
   1530   // Revisit url1, making it the top URL.
   1531   history_service_->AddPage(
   1532       url1, base::Time::Now(), context_id, 0, GURL(),
   1533       history::RedirectList(), content::PAGE_TRANSITION_TYPED,
   1534       history::SOURCE_BROWSED, false);
   1535   history_service_->QueryMostVisitedURLs(
   1536       20, 90, &consumer_,
   1537       base::Bind(
   1538           &HistoryTest::OnMostVisitedURLsAvailable,
   1539           base::Unretained(this)));
   1540   base::MessageLoop::current()->Run();
   1541 
   1542   EXPECT_EQ(3U, most_visited_urls_.size());
   1543   EXPECT_EQ(url1, most_visited_urls_[0].url);
   1544   EXPECT_EQ(url2, most_visited_urls_[1].url);
   1545   EXPECT_EQ(url0, most_visited_urls_[2].url);
   1546 
   1547   // Redirects
   1548   history::RedirectList redirects;
   1549   redirects.push_back(url3);
   1550   redirects.push_back(url4);
   1551 
   1552   // Visit url4 using redirects.
   1553   history_service_->AddPage(
   1554       url4, base::Time::Now(), context_id, 0, GURL(),
   1555       redirects, content::PAGE_TRANSITION_TYPED,
   1556       history::SOURCE_BROWSED, false);
   1557   history_service_->QueryMostVisitedURLs(
   1558       20, 90, &consumer_,
   1559       base::Bind(
   1560           &HistoryTest::OnMostVisitedURLsAvailable,
   1561           base::Unretained(this)));
   1562   base::MessageLoop::current()->Run();
   1563 
   1564   EXPECT_EQ(4U, most_visited_urls_.size());
   1565   EXPECT_EQ(url1, most_visited_urls_[0].url);
   1566   EXPECT_EQ(url2, most_visited_urls_[1].url);
   1567   EXPECT_EQ(url0, most_visited_urls_[2].url);
   1568   EXPECT_EQ(url3, most_visited_urls_[3].url);
   1569   EXPECT_EQ(2U, most_visited_urls_[3].redirects.size());
   1570 }
   1571 
   1572 namespace {
   1573 
   1574 // A HistoryDBTask implementation. Each time RunOnDBThread is invoked
   1575 // invoke_count is increment. When invoked kWantInvokeCount times, true is
   1576 // returned from RunOnDBThread which should stop RunOnDBThread from being
   1577 // invoked again. When DoneRunOnMainThread is invoked, done_invoked is set to
   1578 // true.
   1579 class HistoryDBTaskImpl : public HistoryDBTask {
   1580  public:
   1581   static const int kWantInvokeCount;
   1582 
   1583   HistoryDBTaskImpl() : invoke_count(0), done_invoked(false) {}
   1584 
   1585   virtual bool RunOnDBThread(HistoryBackend* backend,
   1586                              HistoryDatabase* db) OVERRIDE {
   1587     return (++invoke_count == kWantInvokeCount);
   1588   }
   1589 
   1590   virtual void DoneRunOnMainThread() OVERRIDE {
   1591     done_invoked = true;
   1592     base::MessageLoop::current()->Quit();
   1593   }
   1594 
   1595   int invoke_count;
   1596   bool done_invoked;
   1597 
   1598  private:
   1599   virtual ~HistoryDBTaskImpl() {}
   1600 
   1601   DISALLOW_COPY_AND_ASSIGN(HistoryDBTaskImpl);
   1602 };
   1603 
   1604 // static
   1605 const int HistoryDBTaskImpl::kWantInvokeCount = 2;
   1606 
   1607 }  // namespace
   1608 
   1609 TEST_F(HistoryTest, HistoryDBTask) {
   1610   ASSERT_TRUE(history_service_.get());
   1611   CancelableRequestConsumerT<int, 0> request_consumer;
   1612   scoped_refptr<HistoryDBTaskImpl> task(new HistoryDBTaskImpl());
   1613   history_service_->ScheduleDBTask(task.get(), &request_consumer);
   1614   // Run the message loop. When HistoryDBTaskImpl::DoneRunOnMainThread runs,
   1615   // it will stop the message loop. If the test hangs here, it means
   1616   // DoneRunOnMainThread isn't being invoked correctly.
   1617   base::MessageLoop::current()->Run();
   1618   CleanupHistoryService();
   1619   // WARNING: history has now been deleted.
   1620   history_service_.reset();
   1621   ASSERT_EQ(HistoryDBTaskImpl::kWantInvokeCount, task->invoke_count);
   1622   ASSERT_TRUE(task->done_invoked);
   1623 }
   1624 
   1625 TEST_F(HistoryTest, HistoryDBTaskCanceled) {
   1626   ASSERT_TRUE(history_service_.get());
   1627   CancelableRequestConsumerT<int, 0> request_consumer;
   1628   scoped_refptr<HistoryDBTaskImpl> task(new HistoryDBTaskImpl());
   1629   history_service_->ScheduleDBTask(task.get(), &request_consumer);
   1630   request_consumer.CancelAllRequests();
   1631   CleanupHistoryService();
   1632   // WARNING: history has now been deleted.
   1633   history_service_.reset();
   1634   ASSERT_FALSE(task->done_invoked);
   1635 }
   1636 
   1637 // Create a local delete directive and process it while sync is
   1638 // online, and then when offline. The delete directive should be sent to sync,
   1639 // no error should be returned for the first time, and an error should be
   1640 // returned for the second time.
   1641 TEST_F(HistoryTest, ProcessLocalDeleteDirectiveSyncOnline) {
   1642   ASSERT_TRUE(history_service_.get());
   1643 
   1644   const GURL test_url("http://www.google.com/");
   1645   for (int64 i = 1; i <= 10; ++i) {
   1646     base::Time t =
   1647         base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
   1648     history_service_->AddPage(test_url, t, NULL, 0, GURL(),
   1649                               history::RedirectList(),
   1650                               content::PAGE_TRANSITION_LINK,
   1651                               history::SOURCE_BROWSED, false);
   1652   }
   1653 
   1654   sync_pb::HistoryDeleteDirectiveSpecifics delete_directive;
   1655   sync_pb::GlobalIdDirective* global_id_directive =
   1656       delete_directive.mutable_global_id_directive();
   1657   global_id_directive->add_global_id(
   1658       (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1))
   1659       .ToInternalValue());
   1660 
   1661   syncer::FakeSyncChangeProcessor change_processor;
   1662 
   1663   EXPECT_FALSE(
   1664       history_service_->MergeDataAndStartSyncing(
   1665                             syncer::HISTORY_DELETE_DIRECTIVES,
   1666                             syncer::SyncDataList(),
   1667                             scoped_ptr<syncer::SyncChangeProcessor>(
   1668                                 new syncer::SyncChangeProcessorWrapperForTest(
   1669                                     &change_processor)),
   1670                             scoped_ptr<syncer::SyncErrorFactory>())
   1671           .error()
   1672           .IsSet());
   1673 
   1674   syncer::SyncError err =
   1675       history_service_->ProcessLocalDeleteDirective(delete_directive);
   1676   EXPECT_FALSE(err.IsSet());
   1677   EXPECT_EQ(1u, change_processor.changes().size());
   1678 
   1679   history_service_->StopSyncing(syncer::HISTORY_DELETE_DIRECTIVES);
   1680   err = history_service_->ProcessLocalDeleteDirective(delete_directive);
   1681   EXPECT_TRUE(err.IsSet());
   1682   EXPECT_EQ(1u, change_processor.changes().size());
   1683 }
   1684 
   1685 // Closure function that runs periodically to check result of delete directive
   1686 // processing. Stop when timeout or processing ends indicated by the creation
   1687 // of sync changes.
   1688 void CheckDirectiveProcessingResult(
   1689     Time timeout,
   1690     const syncer::FakeSyncChangeProcessor* change_processor,
   1691     uint32 num_changes) {
   1692   if (base::Time::Now() > timeout ||
   1693       change_processor->changes().size() >= num_changes) {
   1694     return;
   1695   }
   1696 
   1697   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
   1698   base::MessageLoop::current()->PostTask(
   1699       FROM_HERE,
   1700       base::Bind(&CheckDirectiveProcessingResult, timeout,
   1701                  change_processor, num_changes));
   1702 }
   1703 
   1704 // Create a delete directive for a few specific history entries,
   1705 // including ones that don't exist. The expected entries should be
   1706 // deleted.
   1707 TEST_F(HistoryTest, ProcessGlobalIdDeleteDirective) {
   1708   ASSERT_TRUE(history_service_.get());
   1709   const GURL test_url("http://www.google.com/");
   1710   for (int64 i = 1; i <= 20; i++) {
   1711     base::Time t =
   1712         base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
   1713     history_service_->AddPage(test_url, t, NULL, 0, GURL(),
   1714                               history::RedirectList(),
   1715                               content::PAGE_TRANSITION_LINK,
   1716                               history::SOURCE_BROWSED, false);
   1717   }
   1718 
   1719   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1720   EXPECT_EQ(20, query_url_row_.visit_count());
   1721 
   1722   syncer::SyncDataList directives;
   1723   // 1st directive.
   1724   sync_pb::EntitySpecifics entity_specs;
   1725   sync_pb::GlobalIdDirective* global_id_directive =
   1726       entity_specs.mutable_history_delete_directive()
   1727           ->mutable_global_id_directive();
   1728   global_id_directive->add_global_id(
   1729       (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6))
   1730       .ToInternalValue());
   1731   global_id_directive->set_start_time_usec(3);
   1732   global_id_directive->set_end_time_usec(10);
   1733   directives.push_back(syncer::SyncData::CreateRemoteData(
   1734       1,
   1735       entity_specs,
   1736       base::Time(),
   1737       syncer::AttachmentIdList(),
   1738       syncer::AttachmentServiceProxyForTest::Create()));
   1739 
   1740   // 2nd directive.
   1741   global_id_directive->Clear();
   1742   global_id_directive->add_global_id(
   1743       (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(17))
   1744       .ToInternalValue());
   1745   global_id_directive->set_start_time_usec(13);
   1746   global_id_directive->set_end_time_usec(19);
   1747   directives.push_back(syncer::SyncData::CreateRemoteData(
   1748       2,
   1749       entity_specs,
   1750       base::Time(),
   1751       syncer::AttachmentIdList(),
   1752       syncer::AttachmentServiceProxyForTest::Create()));
   1753 
   1754   syncer::FakeSyncChangeProcessor change_processor;
   1755   EXPECT_FALSE(
   1756       history_service_->MergeDataAndStartSyncing(
   1757                             syncer::HISTORY_DELETE_DIRECTIVES,
   1758                             directives,
   1759                             scoped_ptr<syncer::SyncChangeProcessor>(
   1760                                 new syncer::SyncChangeProcessorWrapperForTest(
   1761                                     &change_processor)),
   1762                             scoped_ptr<syncer::SyncErrorFactory>())
   1763           .error()
   1764           .IsSet());
   1765 
   1766   // Inject a task to check status and keep message loop filled before directive
   1767   // processing finishes.
   1768   base::MessageLoop::current()->PostTask(
   1769       FROM_HERE,
   1770       base::Bind(&CheckDirectiveProcessingResult,
   1771                  base::Time::Now() + base::TimeDelta::FromSeconds(10),
   1772                  &change_processor, 2));
   1773   base::MessageLoop::current()->RunUntilIdle();
   1774   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1775   ASSERT_EQ(5, query_url_row_.visit_count());
   1776   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1),
   1777             query_url_visits_[0].visit_time);
   1778   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(2),
   1779             query_url_visits_[1].visit_time);
   1780   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(11),
   1781             query_url_visits_[2].visit_time);
   1782   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(12),
   1783             query_url_visits_[3].visit_time);
   1784   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(20),
   1785             query_url_visits_[4].visit_time);
   1786 
   1787   // Expect two sync changes for deleting processed directives.
   1788   const syncer::SyncChangeList& sync_changes = change_processor.changes();
   1789   ASSERT_EQ(2u, sync_changes.size());
   1790   EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
   1791   EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
   1792   EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
   1793   EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
   1794 }
   1795 
   1796 // Create delete directives for time ranges.  The expected entries should be
   1797 // deleted.
   1798 TEST_F(HistoryTest, ProcessTimeRangeDeleteDirective) {
   1799   ASSERT_TRUE(history_service_.get());
   1800   const GURL test_url("http://www.google.com/");
   1801   for (int64 i = 1; i <= 10; ++i) {
   1802     base::Time t =
   1803         base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
   1804     history_service_->AddPage(test_url, t, NULL, 0, GURL(),
   1805                               history::RedirectList(),
   1806                               content::PAGE_TRANSITION_LINK,
   1807                               history::SOURCE_BROWSED, false);
   1808   }
   1809 
   1810   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1811   EXPECT_EQ(10, query_url_row_.visit_count());
   1812 
   1813   syncer::SyncDataList directives;
   1814   // 1st directive.
   1815   sync_pb::EntitySpecifics entity_specs;
   1816   sync_pb::TimeRangeDirective* time_range_directive =
   1817       entity_specs.mutable_history_delete_directive()
   1818           ->mutable_time_range_directive();
   1819   time_range_directive->set_start_time_usec(2);
   1820   time_range_directive->set_end_time_usec(5);
   1821   directives.push_back(syncer::SyncData::CreateRemoteData(
   1822       1,
   1823       entity_specs,
   1824       base::Time(),
   1825       syncer::AttachmentIdList(),
   1826       syncer::AttachmentServiceProxyForTest::Create()));
   1827 
   1828   // 2nd directive.
   1829   time_range_directive->Clear();
   1830   time_range_directive->set_start_time_usec(8);
   1831   time_range_directive->set_end_time_usec(10);
   1832   directives.push_back(syncer::SyncData::CreateRemoteData(
   1833       2,
   1834       entity_specs,
   1835       base::Time(),
   1836       syncer::AttachmentIdList(),
   1837       syncer::AttachmentServiceProxyForTest::Create()));
   1838 
   1839   syncer::FakeSyncChangeProcessor change_processor;
   1840   EXPECT_FALSE(
   1841       history_service_->MergeDataAndStartSyncing(
   1842                             syncer::HISTORY_DELETE_DIRECTIVES,
   1843                             directives,
   1844                             scoped_ptr<syncer::SyncChangeProcessor>(
   1845                                 new syncer::SyncChangeProcessorWrapperForTest(
   1846                                     &change_processor)),
   1847                             scoped_ptr<syncer::SyncErrorFactory>())
   1848           .error()
   1849           .IsSet());
   1850 
   1851   // Inject a task to check status and keep message loop filled before
   1852   // directive processing finishes.
   1853   base::MessageLoop::current()->PostTask(
   1854       FROM_HERE,
   1855       base::Bind(&CheckDirectiveProcessingResult,
   1856                  base::Time::Now() + base::TimeDelta::FromSeconds(10),
   1857                  &change_processor, 2));
   1858   base::MessageLoop::current()->RunUntilIdle();
   1859   EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
   1860   ASSERT_EQ(3, query_url_row_.visit_count());
   1861   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1),
   1862             query_url_visits_[0].visit_time);
   1863   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6),
   1864             query_url_visits_[1].visit_time);
   1865   EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(7),
   1866             query_url_visits_[2].visit_time);
   1867 
   1868   // Expect two sync changes for deleting processed directives.
   1869   const syncer::SyncChangeList& sync_changes = change_processor.changes();
   1870   ASSERT_EQ(2u, sync_changes.size());
   1871   EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
   1872   EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
   1873   EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
   1874   EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
   1875 }
   1876 
   1877 TEST_F(HistoryBackendDBTest, MigratePresentations) {
   1878   // Create the db we want. Use 22 since segments didn't change in that time
   1879   // frame.
   1880   ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
   1881 
   1882   const SegmentID segment_id = 2;
   1883   const URLID url_id = 3;
   1884   const GURL url("http://www.foo.com");
   1885   const std::string url_name(VisitSegmentDatabase::ComputeSegmentName(url));
   1886   const base::string16 title(base::ASCIIToUTF16("Title1"));
   1887   const Time segment_time(Time::Now());
   1888 
   1889   {
   1890     // Re-open the db for manual manipulation.
   1891     sql::Connection db;
   1892     ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
   1893 
   1894     // Add an entry to urls.
   1895     {
   1896       sql::Statement s(db.GetUniqueStatement(
   1897                            "INSERT INTO urls "
   1898                            "(id, url, title, last_visit_time) VALUES "
   1899                            "(?, ?, ?, ?)"));
   1900       s.BindInt64(0, url_id);
   1901       s.BindString(1, url.spec());
   1902       s.BindString16(2, title);
   1903       s.BindInt64(3, segment_time.ToInternalValue());
   1904       ASSERT_TRUE(s.Run());
   1905     }
   1906 
   1907     // Add an entry to segments.
   1908     {
   1909       sql::Statement s(db.GetUniqueStatement(
   1910                            "INSERT INTO segments "
   1911                            "(id, name, url_id, pres_index) VALUES "
   1912                            "(?, ?, ?, ?)"));
   1913       s.BindInt64(0, segment_id);
   1914       s.BindString(1, url_name);
   1915       s.BindInt64(2, url_id);
   1916       s.BindInt(3, 4);  // pres_index
   1917       ASSERT_TRUE(s.Run());
   1918     }
   1919 
   1920     // And one to segment_usage.
   1921     {
   1922       sql::Statement s(db.GetUniqueStatement(
   1923                            "INSERT INTO segment_usage "
   1924                            "(id, segment_id, time_slot, visit_count) VALUES "
   1925                            "(?, ?, ?, ?)"));
   1926       s.BindInt64(0, 4);  // id.
   1927       s.BindInt64(1, segment_id);
   1928       s.BindInt64(2, segment_time.ToInternalValue());
   1929       s.BindInt(3, 5);  // visit count.
   1930       ASSERT_TRUE(s.Run());
   1931     }
   1932   }
   1933 
   1934   // Re-open the db, triggering migration.
   1935   CreateBackendAndDatabase();
   1936 
   1937   std::vector<PageUsageData*> results;
   1938   db_->QuerySegmentUsage(segment_time, 10, &results);
   1939   ASSERT_EQ(1u, results.size());
   1940   EXPECT_EQ(url, results[0]->GetURL());
   1941   EXPECT_EQ(segment_id, results[0]->GetID());
   1942   EXPECT_EQ(title, results[0]->GetTitle());
   1943   STLDeleteElements(&results);
   1944 }
   1945 
   1946 }  // namespace history
   1947