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