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