1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Use of this source code is governed by a BSD-style license that can be
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// found in the LICENSE file.
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// History unit tests come in two flavors:
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// 1. The more complicated style is that the unit test creates a full history
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//    service. This spawns a background thread for the history backend, and
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//    all communication is asynchronous. This is useful for testing more
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//    complicated things or end-to-end behavior.
117fff32c808707eb6810d1057747069d7afce9939stefan@webrtc.org//
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// 2. The simpler style is to create a history backend on this thread and
133f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org//    access it directly without a HistoryService object. This is much simpler
143f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org//    because communication is synchronous. Generally, sets should go through
154d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org//    the history backend (since there is a lot of logic) but gets can come
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//    directly from the HistoryDatabase. This is because the backend generally
176696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org//    has no logic in the getter except threading stuff, which we don't want
187fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org//    to run.
197fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
207fff32c808707eb6810d1057747069d7afce9939stefan@webrtc.org#include <time.h>
217fff32c808707eb6810d1057747069d7afce9939stefan@webrtc.org
227fff32c808707eb6810d1057747069d7afce9939stefan@webrtc.org#include <algorithm>
231bb2146351979b6610107419b2a9c86cca2692a3stefan@webrtc.org#include <string>
244d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
254d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/basictypes.h"
26ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org#include "base/bind.h"
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "base/bind_helpers.h"
284d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/callback.h"
294d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/command_line.h"
304d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/compiler_specific.h"
314d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/files/file_path.h"
324d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/files/file_util.h"
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "base/files/scoped_temp_dir.h"
344d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/logging.h"
354d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/memory/scoped_ptr.h"
364d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/memory/scoped_vector.h"
374d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/message_loop/message_loop.h"
384d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/path_service.h"
394d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/strings/string_util.h"
404d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/strings/stringprintf.h"
414d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/strings/utf_string_conversions.h"
424d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/task/cancelable_task_tracker.h"
434d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/threading/platform_thread.h"
444d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "base/time/time.h"
454d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/download_row.h"
464d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/history_backend.h"
474d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/history_database.h"
484d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/history_db_task.h"
494d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/history_notifications.h"
504d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/history_service.h"
514d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/history_unittest_base.h"
524d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/browser/history/in_memory_history_backend.h"
534d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/common/chrome_constants.h"
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "chrome/common/chrome_paths.h"
554d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "chrome/tools/profiles/thumbnail-inl.h"
564d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "components/history/core/browser/in_memory_database.h"
574d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "components/history/core/browser/page_usage_data.h"
584d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "components/history/core/common/thumbnail_score.h"
594d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "content/public/browser/download_item.h"
604d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "content/public/browser/notification_details.h"
614d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "content/public/browser/notification_source.h"
624d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sql/connection.h"
63ba47616ee5a8d8a4d94e160b64b79a56845e291bandrew@webrtc.org#include "sql/statement.h"
644d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/attachments/attachment_id.h"
654d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/fake_sync_change_processor.h"
664d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/sync_change.h"
674d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/sync_change_processor.h"
684d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/sync_change_processor_wrapper_for_test.h"
694d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/sync_error.h"
704d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/sync_error_factory.h"
714d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/api/sync_merge_result.h"
724d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
734d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/protocol/history_delete_directive_specifics.pb.h"
744d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "sync/protocol/sync.pb.h"
754d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "testing/gtest/include/gtest/gtest.h"
764d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "third_party/skia/include/core/SkBitmap.h"
774d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org#include "ui/gfx/codec/jpeg_codec.h"
784d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
794d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgusing base::Time;
804d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgusing base::TimeDelta;
814d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgusing content::DownloadItem;
824d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace history {
844d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgclass HistoryBackendDBTest;
854d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Delegate class for when we create a backend without a HistoryService.
874d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org//
884d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org// This must be outside the anonymous namespace for the friend statement in
894d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org// HistoryBackendDBTest to work.
904d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgclass BackendDelegate : public HistoryBackend::Delegate {
914d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org public:
924d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  explicit BackendDelegate(HistoryBackendDBTest* history_test)
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      : history_test_(history_test) {
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
954d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
964d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void NotifyProfileError(sql::InitStatus init_status) OVERRIDE {}
974d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void SetInMemoryBackend(
984d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      scoped_ptr<InMemoryHistoryBackend> backend) OVERRIDE;
994d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void NotifyFaviconChanged(const std::set<GURL>& url) OVERRIDE {}
1004d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void BroadcastNotifications(
1014d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      int type,
1024d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      scoped_ptr<HistoryDetails> details) OVERRIDE;
1034d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void DBLoaded() OVERRIDE {}
1044d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void NotifyVisitDBObserversOnAddVisit(
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      const BriefVisitInfo& info) OVERRIDE {}
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private:
1074d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  HistoryBackendDBTest* history_test_;
1084d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org};
1094d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1104d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org// This must be outside the anonymous namespace for the friend statement in
1114d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org// HistoryBackend to work.
1124d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgclass HistoryBackendDBTest : public HistoryUnitTestBase {
1134d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org public:
1144d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  HistoryBackendDBTest() : db_(NULL) {
1154d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1164d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  virtual ~HistoryBackendDBTest() {
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
1194d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1204d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org protected:
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  friend class BackendDelegate;
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1234d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // Creates the HistoryBackend and HistoryDatabase on the current thread,
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // assigning the values to backend_ and db_.
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void CreateBackendAndDatabase() {
1264d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    backend_ =
1274d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        new HistoryBackend(history_dir_, new BackendDelegate(this), NULL);
1284d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    backend_->Init(std::string(), false);
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    db_ = backend_->db_.get();
1304d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    DCHECK(in_mem_backend_) << "Mem backend should have been set by "
1314d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        "HistoryBackend::Init";
1324d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1334d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1344d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  void CreateDBVersion(int version) {
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    base::FilePath data_path;
1364d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    data_path = data_path.AppendASCII("History");
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    data_path =
1394d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          data_path.AppendASCII(base::StringPrintf("history.%d.sql", version));
1404d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_NO_FATAL_FAILURE(
1414d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        ExecuteSQLScript(data_path, history_dir_.Append(
1424d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org            chrome::kHistoryFilename)));
1434d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1444d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void CreateArchivedDB() {
1464d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    base::FilePath data_path;
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
1484d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    data_path = data_path.AppendASCII("History");
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    data_path = data_path.AppendASCII("archived_history.4.sql");
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_NO_FATAL_FAILURE(
1514d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        ExecuteSQLScript(data_path, history_dir_.Append(
1524d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org            chrome::kArchivedHistoryFilename)));
1534d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1544d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1554d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // testing::Test
1564d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void SetUp() {
1574d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    history_dir_ = temp_dir_.path().AppendASCII("HistoryBackendDBTest");
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_TRUE(base::CreateDirectory(history_dir_));
1604d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1614d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1624d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  void DeleteBackend() {
1634d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    if (backend_.get()) {
1644d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      backend_->Closing();
1654d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      backend_ = NULL;
1664d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
1674d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1684d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1694d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  virtual void TearDown() {
1704d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    DeleteBackend();
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make sure we don't have any event pending that could disrupt the next
1734d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // test.
1744d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    base::MessageLoop::current()->PostTask(FROM_HERE,
1754d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                                           base::MessageLoop::QuitClosure());
1764d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    base::MessageLoop::current()->Run();
1774d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
1784d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1794d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  bool AddDownload(uint32 id,
1804d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                   DownloadItem::DownloadState state,
1814d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                   const Time& time) {
1824d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    std::vector<GURL> url_chain;
1834d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    url_chain.push_back(GURL("foo-url"));
1844d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
1854d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    DownloadRow download(base::FilePath(FILE_PATH_LITERAL("current-path")),
1864d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         base::FilePath(FILE_PATH_LITERAL("target-path")),
1874d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         url_chain,
1884d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         GURL("http://referrer.com/"),
1894d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         "application/vnd.oasis.opendocument.text",
1904d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         "application/octet-stream",
1914d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         time,
1924d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         time,
1934d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         std::string(),
1944d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         std::string(),
1954d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         0,
1964d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         512,
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         state,
1984d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1994d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         content::DOWNLOAD_INTERRUPT_REASON_NONE,
2004d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         id,
2014d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         false,
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "by_ext_id",
2034d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                         "by_ext_name");
2044d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    return db_->CreateDownload(download);
205e1c99022cc666e440e9fc74dc7cf8414987a47a5stefan@webrtc.org  }
2064d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2074d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  base::ScopedTempDir temp_dir_;
2084d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2094d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  base::MessageLoopForUI message_loop_;
2104d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2114d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // names of the database files
2124d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  base::FilePath history_dir_;
2134d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2144d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // Created via CreateBackendAndDatabase.
2154d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  scoped_refptr<HistoryBackend> backend_;
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  scoped_ptr<InMemoryHistoryBackend> in_mem_backend_;
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  HistoryDatabase* db_;  // Cached reference to the backend's database.
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org};
219e1c99022cc666e440e9fc74dc7cf8414987a47a5stefan@webrtc.org
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid BackendDelegate::SetInMemoryBackend(
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    scoped_ptr<InMemoryHistoryBackend> backend) {
2227fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // Save the in-memory backend to the history test object, this happens
2237fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // synchronously, so we don't have to do anything fancy.
2247fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  history_test_->in_mem_backend_.swap(backend);
2254d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org}
2264d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid BackendDelegate::BroadcastNotifications(
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int type,
229db74c61ddfa26c23d3e392b241c983010e10b1c5stefan@webrtc.org    scoped_ptr<HistoryDetails> details) {
2306696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org  // Currently, just send the notifications directly to the in-memory database.
2314d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // We may want do do something more fancy in the future.
2324d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  content::Details<HistoryDetails> det(details.get());
2334d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  history_test_->in_mem_backend_->Observe(type,
2344d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      content::Source<HistoryBackendDBTest>(NULL), det);
2354d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org}
2364d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2374d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgTEST_F(HistoryBackendDBTest, ClearBrowsingData_Downloads) {
2384d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  CreateBackendAndDatabase();
2394d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2404d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // Initially there should be nothing in the downloads database.
2417fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  std::vector<DownloadRow> downloads;
2427fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  db_->QueryDownloads(&downloads);
2437fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  EXPECT_EQ(0U, downloads.size());
2447fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2457fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // Add a download, test that it was added correctly, remove it, test that it
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // was removed.
2474d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  Time now = Time();
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uint32 id = 1;
2494d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_TRUE(AddDownload(id, DownloadItem::COMPLETE, Time()));
2504d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  db_->QueryDownloads(&downloads);
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  EXPECT_EQ(1U, downloads.size());
2524d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("current-path")),
2544d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org            downloads[0].current_path);
2554d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("target-path")),
2567fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org            downloads[0].target_path);
2576696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org  EXPECT_EQ(1UL, downloads[0].url_chain.size());
2586696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org  EXPECT_EQ(GURL("foo-url"), downloads[0].url_chain[0]);
2597fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  EXPECT_EQ(std::string("http://referrer.com/"),
2607fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org            std::string(downloads[0].referrer_url.spec()));
2617fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  EXPECT_EQ(now, downloads[0].start_time);
262db74c61ddfa26c23d3e392b241c983010e10b1c5stefan@webrtc.org  EXPECT_EQ(now, downloads[0].end_time);
263db74c61ddfa26c23d3e392b241c983010e10b1c5stefan@webrtc.org  EXPECT_EQ(0, downloads[0].received_bytes);
2646696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org  EXPECT_EQ(512, downloads[0].total_bytes);
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  EXPECT_EQ(DownloadItem::COMPLETE, downloads[0].state);
2664d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
2674d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org            downloads[0].danger_type);
2684d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
2694d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org            downloads[0].interrupt_reason);
2704d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_FALSE(downloads[0].opened);
2714d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ("by_ext_id", downloads[0].by_ext_id);
2724d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ("by_ext_name", downloads[0].by_ext_name);
2736696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org  EXPECT_EQ("application/vnd.oasis.opendocument.text", downloads[0].mime_type);
2747fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  EXPECT_EQ("application/octet-stream", downloads[0].original_mime_type);
27599681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org
2766696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org  db_->QueryDownloads(&downloads);
2774d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ(1U, downloads.size());
2784d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  db_->RemoveDownload(id);
2794d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  db_->QueryDownloads(&downloads);
2804d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  EXPECT_EQ(0U, downloads.size());
2814d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org}
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2834d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgTEST_F(HistoryBackendDBTest, MigrateDownloadsState) {
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Create the db we want.
2854d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
2864d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  {
2874d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // Open the db for manual manipulation.
2884d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Connection db;
2894d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
2904d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
2914d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // Manually insert corrupted rows; there's infrastructure in place now to
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // make this impossible, at least according to the test above.
2934d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    for (int state = 0; state < 5; ++state) {
2944d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      sql::Statement s(db.GetUniqueStatement(
2954d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org            "INSERT INTO downloads (id, full_path, url, start_time, "
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "received_bytes, total_bytes, state, end_time, opened) VALUES "
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
2986696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org      s.BindInt64(0, 1 + state);
2997fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      s.BindString(1, "path");
3007fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      s.BindString(2, "url");
3014d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      s.BindInt64(3, base::Time::Now().ToTimeT());
3024d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      s.BindInt64(4, 100);
3034d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      s.BindInt64(5, 100);
3044d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      s.BindInt(6, state);
3054d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      s.BindInt64(7, base::Time::Now().ToTimeT());
3064d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      s.BindInt(8, state % 2);
3074d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      ASSERT_TRUE(s.Run());
3084d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
3094d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
3104d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
3114d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // Re-open the db using the HistoryDatabase, which should migrate from version
3124d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // 22 to the current version, fixing just the row whose state was 3.
3134d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // Then close the db so that we can re-open it directly.
3144d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  CreateBackendAndDatabase();
3154d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  DeleteBackend();
3164d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  {
3174d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // Re-open the db for manual manipulation.
3184d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Connection db;
3194d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
3204d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    {
3214d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      // The version should have been updated.
3224d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      int cur_version = HistoryDatabase::GetCurrentVersion();
3234d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      ASSERT_LT(22, cur_version);
3244d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      sql::Statement s(db.GetUniqueStatement(
325ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org          "SELECT value FROM meta WHERE key = 'version'"));
3264d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_TRUE(s.Step());
3274d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(cur_version, s.ColumnInt(0));
3284d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
3294d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    {
3304d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      sql::Statement statement(db.GetUniqueStatement(
3314d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          "SELECT id, state, opened "
3324d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          "FROM downloads "
3334d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          "ORDER BY id"));
3344d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      int counter = 0;
3354d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      while (statement.Step()) {
3364d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        EXPECT_EQ(1 + counter, statement.ColumnInt64(0));
3374d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        // The only thing that migration should have changed was state from 3 to
3384d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        // 4.
339ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org        EXPECT_EQ(((counter == 3) ? 4 : counter), statement.ColumnInt(1));
3404d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        EXPECT_EQ(counter % 2, statement.ColumnInt(2));
3414d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        ++counter;
3424d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      }
3434d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(5, counter);
3444d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
3454d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
3464d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org}
3474d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
3484d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgTEST_F(HistoryBackendDBTest, MigrateDownloadsReasonPathsAndDangerType) {
3494d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  Time now(base::Time::Now());
3504d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
35122c283b04855b8775d323e8788a0438ce2d7c2b5henrike@webrtc.org  // Create the db we want.  The schema didn't change from 22->23, so just
35222c283b04855b8775d323e8788a0438ce2d7c2b5henrike@webrtc.org  // re-use the v22 file.
35322c283b04855b8775d323e8788a0438ce2d7c2b5henrike@webrtc.org  ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
3544d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  {
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Re-open the db for manual manipulation.
3564d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Connection db;
3574d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
3584d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
3594d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // Manually insert some rows.
3604d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Statement s(db.GetUniqueStatement(
3614d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        "INSERT INTO downloads (id, full_path, url, start_time, "
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        "received_bytes, total_bytes, state, end_time, opened) VALUES "
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int64 id = 0;
3664d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // Null path.
3674d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(0, ++id);
3684d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindString(1, std::string());
369ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindString(2, "http://whatever.com/index.html");
3704d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(3, now.ToTimeT());
371ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(4, 100);
3724d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(5, 100);
3734d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt(6, 1);
3744d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(7, now.ToTimeT());
3754d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt(8, 1);
3764d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(s.Run());
377ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.Reset(true);
378ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org
379ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    // Non-null path.
380ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(0, ++id);
381ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindString(1, "/path/to/some/file");
3824d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindString(2, "http://whatever.com/index1.html");
3834d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(3, now.ToTimeT());
384ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(4, 100);
385ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(5, 100);
3864d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt(6, 1);
3874d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(7, now.ToTimeT());
3884d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt(8, 1);
3894d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(s.Run());
3904d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
3914d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
3924d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // Re-open the db using the HistoryDatabase, which should migrate from version
3934d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // 23 to 24, creating the new tables and creating the new path, reason,
394ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org  // and danger columns.
3954d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  CreateBackendAndDatabase();
3964d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  DeleteBackend();
3974d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  {
398ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    // Re-open the db for manual manipulation.
3994d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Connection db;
4004d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
4024d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      // The version should have been updated.
4034d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      int cur_version = HistoryDatabase::GetCurrentVersion();
4044d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      ASSERT_LT(23, cur_version);
405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      sql::Statement s(db.GetUniqueStatement(
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          "SELECT value FROM meta WHERE key = 'version'"));
4074d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_TRUE(s.Step());
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(cur_version, s.ColumnInt(0));
4094d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
4104d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    {
4114d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      base::Time nowish(base::Time::FromTimeT(now.ToTimeT()));
4124d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
4134d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      // Confirm downloads table is valid.
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      sql::Statement statement(db.GetUniqueStatement(
4154d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          "SELECT id, interrupt_reason, current_path, target_path, "
4164d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          "       danger_type, start_time, end_time "
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          "FROM downloads ORDER BY id"));
4184d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_TRUE(statement.Step());
4194d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(1, statement.ColumnInt64(0));
4204d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
4214d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                statement.ColumnInt(1));
422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ("", statement.ColumnString(2));
4234d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ("", statement.ColumnString(3));
4244d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      // Implicit dependence on value of kDangerTypeNotDangerous from
4254d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      // download_database.cc.
4264d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(0, statement.ColumnInt(4));
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(5));
4286696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org      EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(6));
4296696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org
4306696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org      EXPECT_TRUE(statement.Step());
4316696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org      EXPECT_EQ(2, statement.ColumnInt64(0));
4324d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
4334d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org                statement.ColumnInt(1));
4346696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org      EXPECT_EQ("/path/to/some/file", statement.ColumnString(2));
435e1c99022cc666e440e9fc74dc7cf8414987a47a5stefan@webrtc.org      EXPECT_EQ("/path/to/some/file", statement.ColumnString(3));
4364d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(0, statement.ColumnInt(4));
4374d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(5));
4384d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(6));
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
4404d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_FALSE(statement.Step());
4414d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
4424d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    {
4436696fba9388a386f7d0e3e0d93df48d43f05cd95stefan@webrtc.org      // Confirm downloads_url_chains table is valid.
4444d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      sql::Statement statement(db.GetUniqueStatement(
4454d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          "SELECT id, chain_index, url FROM downloads_url_chains "
4464d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org          " ORDER BY id, chain_index"));
4474d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_TRUE(statement.Step());
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(1, statement.ColumnInt64(0));
449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, statement.ColumnInt(1));
4504d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ("http://whatever.com/index.html", statement.ColumnString(2));
4514d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
4524d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_TRUE(statement.Step());
453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(2, statement.ColumnInt64(0));
4544d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ(0, statement.ColumnInt(1));
4554d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org      EXPECT_EQ("http://whatever.com/index1.html", statement.ColumnString(2));
456ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org
457ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org      EXPECT_FALSE(statement.Step());
4584d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    }
4594d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
4604d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org}
4614d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org
4624d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.orgTEST_F(HistoryBackendDBTest, MigrateReferrer) {
4634d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  Time now(base::Time::Now());
4644d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
4654d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  {
4664d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Connection db;
4674d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
4684d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    sql::Statement s(db.GetUniqueStatement(
4694d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        "INSERT INTO downloads (id, full_path, url, start_time, "
4704d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        "received_bytes, total_bytes, state, end_time, opened) VALUES "
4714d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org        "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
4724d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    int64 db_handle = 0;
4734d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(0, ++db_handle);
4744d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindString(1, "full_path");
4754d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindString(2, "http://whatever.com/index.html");
4764d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt64(3, now.ToTimeT());
477ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(4, 100);
478ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(5, 100);
4794d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    s.BindInt(6, 1);
480ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt64(7, now.ToTimeT());
481ac772a43f023d08fc0222473e669924113274bddpbos@webrtc.org    s.BindInt(8, 1);
4824d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(s.Run());
4834d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  }
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Re-open the db using the HistoryDatabase, which should migrate to version
4854d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  // 26, creating the referrer column.
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  CreateBackendAndDatabase();
4874d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  DeleteBackend();
4884d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org  {
4894d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // Re-open the db for manual manipulation.
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    sql::Connection db;
4914d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
4924d2a2eccaef42c24ada13e98fe2917439d882033solenberg@webrtc.org    // 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
510TEST_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
573TEST_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
638TEST_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
654TEST_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
722TEST_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
770TEST_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
828TEST_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
887struct 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.
894const 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.
902const 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.
931TEST_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
979class 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
1116TEST_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
1139TEST_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
1214TEST_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
1300TEST_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
1351TEST_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
1380TEST_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
1492namespace {
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.
1499class 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
1526const int HistoryDBTaskImpl::kWantInvokeCount = 2;
1527
1528}  // namespace
1529
1530TEST_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
1550TEST_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.
1570TEST_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.
1617void 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.
1636TEST_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.
1727TEST_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
1806TEST_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