Commit 28b6c87f authored by Dan Harrington's avatar Dan Harrington Committed by Commit Bot

Remove OfflinePageMetadataStore

OfflinePageMetadataStore was only referenced in the unittest, now it has been
removed. A few methods/types were migrated to OfflinePageMetadataStoreSQL,
others were removed because the were no longer in use.

I removed some tests that only tested the removed methods. Other methods
that were used to test the database and were moved to the test file, like
GetOfflinePages and AddOfflinePage.

offline_page_metadata_store_unittest.cc will be renamed
offline_page_metadata_store_sql_unittest.cc in a follow-up.

Bug: 778813
Change-Id: I6315cd5fb43b8a56b84dcede8c388286dd96e39c
Reviewed-on: https://chromium-review.googlesource.com/949502Reviewed-by: default avatarYafei Duan <romax@chromium.org>
Reviewed-by: default avatarCarlos Knippschild <carlosk@chromium.org>
Commit-Queue: Dan H <harringtond@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541621}
parent f4167f1f
......@@ -56,7 +56,6 @@ static_library("core") {
"offline_page_client_policy.h",
"offline_page_item.cc",
"offline_page_item.h",
"offline_page_metadata_store.h",
"offline_page_metadata_store_sql.cc",
"offline_page_metadata_store_sql.h",
"offline_page_model.cc",
......
......@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/offline_pages/core/offline_page_metadata_store.h"
#include "components/offline_pages/core/offline_page_metadata_store_sql.h"
#include "components/offline_pages/core/offline_page_model.h"
#include "components/offline_pages/core/offline_page_types.h"
#include "components/offline_pages/core/task.h"
......
......@@ -30,7 +30,6 @@
#include "components/offline_pages/core/model/persistent_pages_consistency_check_task.h"
#include "components/offline_pages/core/model/temporary_pages_consistency_check_task.h"
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/offline_page_metadata_store.h"
#include "components/offline_pages/core/offline_page_metadata_store_sql.h"
#include "components/offline_pages/core/offline_page_model.h"
#include "components/offline_pages/core/offline_store_utils.h"
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGE_METADATA_STORE_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGE_METADATA_STORE_H_
#include <stdint.h>
#include <vector>
#include "base/callback.h"
#include "components/offline_pages/core/offline_page_item.h"
#include "components/offline_pages/core/offline_store_types.h"
namespace offline_pages {
typedef StoreUpdateResult<OfflinePageItem> OfflinePagesUpdateResult;
// OfflinePageMetadataStore keeps metadata for the offline pages.
// Ability to create multiple instances of the store as well as behavior of
// asynchronous operations when the object is being destroyed, before such
// operation finishes will depend on implementation. It should be possible to
// issue multiple asynchronous operations in parallel.
class OfflinePageMetadataStore {
public:
// This enum is used in an UMA histogram. Hence the entries here shouldn't
// be deleted or re-ordered and new ones should be added to the end.
enum LoadStatus {
LOAD_SUCCEEDED,
STORE_INIT_FAILED,
STORE_LOAD_FAILED,
DATA_PARSING_FAILED,
// NOTE: always keep this entry at the end.
LOAD_STATUS_COUNT
};
typedef base::Callback<void(bool /* success */)> InitializeCallback;
typedef base::Callback<void(bool /* success */)> ResetCallback;
typedef base::Callback<void(std::vector<OfflinePageItem>)> LoadCallback;
typedef base::Callback<void(ItemActionStatus)> AddCallback;
typedef base::Callback<void(std::unique_ptr<OfflinePagesUpdateResult>)>
UpdateCallback;
virtual ~OfflinePageMetadataStore(){};
// Initializes the store. Should be called before any other methods.
virtual void Initialize(const InitializeCallback& callback) = 0;
// Get all of the offline pages from the store.
virtual void GetOfflinePages(const LoadCallback& callback) = 0;
// Asynchronously adds an offline page item metadata to the store.
virtual void AddOfflinePage(const OfflinePageItem& offline_page,
const AddCallback& callback) = 0;
// Asynchronously updates a set of offline page items in the store.
virtual void UpdateOfflinePages(const std::vector<OfflinePageItem>& pages,
const UpdateCallback& callback) = 0;
// Asynchronously removes offline page metadata from the store.
// Result of the update is passed in callback.
virtual void RemoveOfflinePages(const std::vector<int64_t>& offline_ids,
const UpdateCallback& callback) = 0;
// Resets the store.
virtual void Reset(const ResetCallback& callback) = 0;
// Gets the store state.
virtual StoreState state() const = 0;
};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGE_METADATA_STORE_H_
......@@ -273,121 +273,6 @@ bool CreateSchema(sql::Connection* db) {
return true;
}
bool DeleteByOfflineId(sql::Connection* db, int64_t offline_id) {
static const char kSql[] =
"DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id=?";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, offline_id);
return statement.Run();
}
// Create an offline page item from a SQL result. Expects complete rows with
// all columns present.
OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
int64_t id = statement->ColumnInt64(0);
base::Time creation_time =
store_utils::FromDatabaseTime(statement->ColumnInt64(1));
int64_t file_size = statement->ColumnInt64(2);
base::Time last_access_time =
store_utils::FromDatabaseTime(statement->ColumnInt64(3));
int access_count = statement->ColumnInt(4);
int64_t system_download_id = statement->ColumnInt64(5);
base::Time file_missing_time =
store_utils::FromDatabaseTime(statement->ColumnInt64(6));
int upgrade_attempt = statement->ColumnInt(7);
ClientId client_id(statement->ColumnString(8), statement->ColumnString(9));
GURL url(statement->ColumnString(10));
base::FilePath path(
store_utils::FromDatabaseFilePath(statement->ColumnString(11)));
base::string16 title = statement->ColumnString16(12);
GURL original_url(statement->ColumnString(13));
std::string request_origin = statement->ColumnString(14);
std::string digest = statement->ColumnString(15);
OfflinePageItem item(url, id, client_id, path, file_size, creation_time);
item.last_access_time = last_access_time;
item.access_count = access_count;
item.title = title;
item.original_url = original_url;
item.request_origin = request_origin;
item.system_download_id = system_download_id;
item.file_missing_time = file_missing_time;
item.upgrade_attempt = upgrade_attempt;
item.digest = digest;
return item;
}
ItemActionStatus AddOfflinePageSync(const OfflinePageItem& item,
sql::Connection* db) {
if (!db)
return ItemActionStatus::STORE_ERROR;
// Using 'INSERT OR FAIL' or 'INSERT OR ABORT' in the query below causes debug
// builds to DLOG.
const char kSql[] =
"INSERT OR IGNORE INTO " OFFLINE_PAGES_TABLE_NAME
" (offline_id, online_url, client_namespace, client_id, file_path, "
"file_size, creation_time, last_access_time, access_count, "
"title, original_url, request_origin, system_download_id, "
"file_missing_time, upgrade_attempt, digest)"
" VALUES "
" (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, item.offline_id);
statement.BindString(1, item.url.spec());
statement.BindString(2, item.client_id.name_space);
statement.BindString(3, item.client_id.id);
statement.BindString(4, store_utils::ToDatabaseFilePath(item.file_path));
statement.BindInt64(5, item.file_size);
statement.BindInt64(6, store_utils::ToDatabaseTime(item.creation_time));
statement.BindInt64(7, store_utils::ToDatabaseTime(item.last_access_time));
statement.BindInt(8, item.access_count);
statement.BindString16(9, item.title);
statement.BindString(10, item.original_url.spec());
statement.BindString(11, item.request_origin);
statement.BindInt64(12, item.system_download_id);
statement.BindInt64(13, store_utils::ToDatabaseTime(item.file_missing_time));
statement.BindInt(14, item.upgrade_attempt);
statement.BindString(15, item.digest);
if (!statement.Run())
return ItemActionStatus::STORE_ERROR;
if (db->GetLastChangeCount() == 0)
return ItemActionStatus::ALREADY_EXISTS;
return ItemActionStatus::SUCCESS;
}
bool Update(sql::Connection* db, const OfflinePageItem& item) {
const char kSql[] =
"UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
" SET online_url = ?, client_namespace = ?, client_id = ?, file_path = ?,"
" file_size = ?, creation_time = ?, last_access_time = ?,"
" access_count = ?, title = ?, original_url = ?, request_origin = ?,"
" system_download_id = ?, file_missing_time = ?, upgrade_attempt = ?,"
" digest = ?"
" WHERE offline_id = ?";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindString(0, item.url.spec());
statement.BindString(1, item.client_id.name_space);
statement.BindString(2, item.client_id.id);
statement.BindString(3, store_utils::ToDatabaseFilePath(item.file_path));
statement.BindInt64(4, item.file_size);
statement.BindInt64(5, store_utils::ToDatabaseTime(item.creation_time));
statement.BindInt64(6, store_utils::ToDatabaseTime(item.last_access_time));
statement.BindInt(7, item.access_count);
statement.BindString16(8, item.title);
statement.BindString(9, item.original_url.spec());
statement.BindString(10, item.request_origin);
statement.BindInt64(11, item.system_download_id);
statement.BindInt64(12, store_utils::ToDatabaseTime(item.file_missing_time));
statement.BindInt(13, item.upgrade_attempt);
statement.BindString(14, item.digest);
statement.BindInt64(15, item.offline_id);
return statement.Run() && db->GetLastChangeCount() > 0;
}
bool PrepareDirectory(const base::FilePath& path) {
base::File::Error error = base::File::FILE_OK;
if (!base::DirectoryExists(path.DirName())) {
......@@ -439,172 +324,6 @@ void CloseDatabaseSync(
callback_runner->PostTask(FROM_HERE, std::move(callback));
}
void RecordLoadResult(OfflinePageMetadataStore::LoadStatus status,
int32_t page_count) {
UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status,
OfflinePageMetadataStore::LOAD_STATUS_COUNT);
if (status == OfflinePageMetadataStore::LOAD_SUCCEEDED) {
UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount", page_count);
} else {
DVLOG(1) << "Offline pages database loading failed: " << status;
}
}
// This method does a simple check whether DB was initialized properly.
// It is only relevant for direct call to Initialize.
bool CheckDBLoadedSync(sql::Connection* db) {
return db != nullptr;
}
bool GetPageByOfflineIdSync(sql::Connection* db,
int64_t offline_id,
OfflinePageItem* item) {
const char kSql[] =
"SELECT * FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, offline_id);
if (statement.Step()) {
*item = MakeOfflinePageItem(&statement);
return true;
}
return false;
}
std::vector<OfflinePageItem> GetOfflinePagesSync(sql::Connection* db) {
std::vector<OfflinePageItem> result;
if (!db)
return result;
const char kSql[] = "SELECT * FROM " OFFLINE_PAGES_TABLE_NAME;
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
while (statement.Step())
result.push_back(MakeOfflinePageItem(&statement));
if (statement.Succeeded()) {
RecordLoadResult(OfflinePageMetadataStore::LOAD_SUCCEEDED, result.size());
} else {
result.clear();
RecordLoadResult(OfflinePageMetadataStore::STORE_LOAD_FAILED, 0);
}
return result;
}
void GetOfflinePagesResultWrapper(
const OfflinePageMetadataStore::LoadCallback& load_callback,
std::vector<OfflinePageItem> result) {
load_callback.Run(result);
}
std::unique_ptr<OfflinePagesUpdateResult> BuildUpdateResultForIds(
StoreState store_state,
const std::vector<int64_t>& offline_ids,
ItemActionStatus action_status) {
std::unique_ptr<OfflinePagesUpdateResult> result(
new OfflinePagesUpdateResult(store_state));
for (const auto& offline_id : offline_ids)
result->item_statuses.push_back(std::make_pair(offline_id, action_status));
return result;
}
std::unique_ptr<OfflinePagesUpdateResult> BuildUpdateResultForPages(
StoreState store_state,
const std::vector<OfflinePageItem>& pages,
ItemActionStatus action_status) {
std::unique_ptr<OfflinePagesUpdateResult> result(
new OfflinePagesUpdateResult(store_state));
for (const auto& page : pages)
result->item_statuses.push_back(
std::make_pair(page.offline_id, action_status));
return result;
}
std::unique_ptr<OfflinePagesUpdateResult> UpdateOfflinePagesSync(
const std::vector<OfflinePageItem>& pages,
sql::Connection* db) {
if (!db) {
return BuildUpdateResultForPages(StoreState::NOT_LOADED, pages,
ItemActionStatus::STORE_ERROR);
}
sql::Transaction transaction(db);
if (!transaction.Begin()) {
return BuildUpdateResultForPages(StoreState::LOADED, pages,
ItemActionStatus::STORE_ERROR);
}
std::unique_ptr<OfflinePagesUpdateResult> result(
new OfflinePagesUpdateResult(StoreState::LOADED));
for (const auto& page : pages) {
if (Update(db, page)) {
result->updated_items.push_back(page);
result->item_statuses.push_back(
std::make_pair(page.offline_id, ItemActionStatus::SUCCESS));
} else {
result->item_statuses.push_back(
std::make_pair(page.offline_id, ItemActionStatus::NOT_FOUND));
}
}
if (!transaction.Commit()) {
return BuildUpdateResultForPages(StoreState::LOADED, pages,
ItemActionStatus::STORE_ERROR);
}
return result;
}
std::unique_ptr<OfflinePagesUpdateResult> RemoveOfflinePagesSync(
const std::vector<int64_t>& offline_ids,
sql::Connection* db) {
if (!db) {
return BuildUpdateResultForIds(StoreState::NOT_LOADED, offline_ids,
ItemActionStatus::STORE_ERROR);
}
if (offline_ids.empty()) {
return BuildUpdateResultForIds(StoreState::LOADED, offline_ids,
ItemActionStatus::NOT_FOUND);
}
// If you create a transaction but don't Commit() it is automatically
// rolled back by its destructor when it falls out of scope.
sql::Transaction transaction(db);
if (!transaction.Begin()) {
return BuildUpdateResultForIds(StoreState::LOADED, offline_ids,
ItemActionStatus::STORE_ERROR);
}
std::unique_ptr<OfflinePagesUpdateResult> result(
new OfflinePagesUpdateResult(StoreState::LOADED));
for (int64_t offline_id : offline_ids) {
OfflinePageItem page;
ItemActionStatus status;
if (!GetPageByOfflineIdSync(db, offline_id, &page)) {
status = ItemActionStatus::NOT_FOUND;
} else if (!DeleteByOfflineId(db, offline_id)) {
status = ItemActionStatus::STORE_ERROR;
} else {
status = ItemActionStatus::SUCCESS;
result->updated_items.push_back(page);
}
result->item_statuses.push_back(std::make_pair(offline_id, status));
}
if (!transaction.Commit()) {
return BuildUpdateResultForIds(StoreState::LOADED, offline_ids,
ItemActionStatus::STORE_ERROR);
}
return result;
}
} // anonymous namespace
// static
......@@ -635,53 +354,7 @@ OfflinePageMetadataStoreSQL::~OfflinePageMetadataStoreSQL() {
}
}
// TODO(fgorski): Remove this method once model is split into tasks.
// This method is only kept until the whole OfflinePageModelImpl is running
// implemented using TaskQueue. A separate initialize step will not be necessary
// after that.
void OfflinePageMetadataStoreSQL::Initialize(
const InitializeCallback& callback) {
Execute(base::BindOnce(&CheckDBLoadedSync), base::BindOnce(callback));
}
void OfflinePageMetadataStoreSQL::GetOfflinePages(
const LoadCallback& callback) {
Execute(base::BindOnce(&GetOfflinePagesSync),
base::BindOnce(&GetOfflinePagesResultWrapper, callback));
}
void OfflinePageMetadataStoreSQL::AddOfflinePage(
const OfflinePageItem& offline_page,
const AddCallback& callback) {
Execute(base::BindOnce(&AddOfflinePageSync, offline_page),
base::BindOnce(callback));
}
void OfflinePageMetadataStoreSQL::UpdateOfflinePages(
const std::vector<OfflinePageItem>& pages,
const UpdateCallback& callback) {
Execute(base::BindOnce(&UpdateOfflinePagesSync, pages),
base::BindOnce(callback));
}
void OfflinePageMetadataStoreSQL::RemoveOfflinePages(
const std::vector<int64_t>& offline_ids,
const UpdateCallback& callback) {
Execute(base::BindOnce(&RemoveOfflinePagesSync, offline_ids),
base::BindOnce(callback));
}
// No-op implementation. This database does not reset.
// TODO(dimich): Observe UMA and decide if this database has to be erased.
// Note is potentially contains user-saved data.
void OfflinePageMetadataStoreSQL::Reset(const ResetCallback& callback) {
bool success = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
base::Bind(callback, success));
return;
}
StoreState OfflinePageMetadataStoreSQL::state() const {
StoreState OfflinePageMetadataStoreSQL::GetStateForTesting() const {
return state_;
}
......
......@@ -17,7 +17,8 @@
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "components/offline_pages/core/offline_page_metadata_store.h"
#include "components/offline_pages/core/offline_page_item.h"
#include "components/offline_pages/core/offline_store_types.h"
namespace base {
class SequencedTaskRunner;
......@@ -28,8 +29,10 @@ class Connection;
}
namespace offline_pages {
// OfflinePageMetadataStoreSQL is an instance of OfflinePageMetadataStore
// which is implemented using a SQLite database.
typedef StoreUpdateResult<OfflinePageItem> OfflinePagesUpdateResult;
// OfflinePageMetadataStoreSQL keeps metadata for the offline pages in an SQLite
// database.
//
// This store has a history of schema updates in pretty much every release.
// Original schema was delivered in M52. Since then, the following changes
......@@ -61,8 +64,22 @@ namespace offline_pages {
// |UpgradeFrom54|.
// * Upgrade should use |UpgradeWithQuery| and simply specify SQL command to
// move data from old table (prefixed by temp_) to the new one.
class OfflinePageMetadataStoreSQL : public OfflinePageMetadataStore {
class OfflinePageMetadataStoreSQL {
public:
// This enum is used in an UMA histogram. Hence the entries here shouldn't
// be deleted or re-ordered and new ones should be added to the end.
enum LoadStatus {
LOAD_SUCCEEDED,
STORE_INIT_FAILED,
STORE_LOAD_FAILED,
DATA_PARSING_FAILED,
// NOTE: always keep this entry at the end.
LOAD_STATUS_COUNT
};
typedef base::RepeatingCallback<void(bool /* success */)> ResetCallback;
// Definition of the callback that is going to run the core of the command in
// the |Execute| method.
template <typename T>
......@@ -89,19 +106,7 @@ class OfflinePageMetadataStoreSQL : public OfflinePageMetadataStore {
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
const base::FilePath& database_dir);
~OfflinePageMetadataStoreSQL() override;
// Implementation methods.
void Initialize(const InitializeCallback& callback) override;
void GetOfflinePages(const LoadCallback& callback) override;
void AddOfflinePage(const OfflinePageItem& offline_page,
const AddCallback& callback) override;
void UpdateOfflinePages(const std::vector<OfflinePageItem>& pages,
const UpdateCallback& callback) override;
void RemoveOfflinePages(const std::vector<int64_t>& offline_ids,
const UpdateCallback& callback) override;
void Reset(const ResetCallback& callback) override;
StoreState state() const override;
~OfflinePageMetadataStoreSQL();
// Executes a |run_callback| on SQL store on the blocking thread, and posts
// its result back to calling thread through |result_callback|.
......@@ -153,6 +158,7 @@ class OfflinePageMetadataStoreSQL : public OfflinePageMetadataStore {
// Helper function used to force incorrect state for testing purposes.
void SetStateForTesting(StoreState state, bool reset_db);
StoreState GetStateForTesting() const;
private:
// Initializes database and calls callback.
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/offline_pages/core/offline_page_metadata_store.h"
#include "components/offline_pages/core/offline_page_metadata_store_sql.h"
#include <stdint.h>
......@@ -11,8 +11,10 @@
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/client_namespace_constants.h"
......@@ -24,6 +26,7 @@
#include "sql/connection.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace offline_pages {
......@@ -129,7 +132,7 @@ void BuildTestStoreWithSchemaFromM53(const base::FilePath& file) {
statement.BindString(7, kTestClientId2.id);
statement.BindCString(8, kTestURL);
statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII());
statement.BindInt64(10, base::Time::Now().ToInternalValue());
statement.BindInt64(10, store_utils::ToDatabaseTime(base::Time::Now()));
ASSERT_TRUE(statement.Run());
ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1));
ASSERT_FALSE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "title"));
......@@ -175,7 +178,7 @@ void BuildTestStoreWithSchemaFromM54(const base::FilePath& file) {
statement.BindString(7, kTestClientId2.id);
statement.BindCString(8, kTestURL);
statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII());
statement.BindInt64(10, base::Time::Now().ToInternalValue());
statement.BindInt64(10, store_utils::ToDatabaseTime(base::Time::Now()));
statement.BindString16(11, base::UTF8ToUTF16("Test title"));
ASSERT_TRUE(statement.Run());
ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1));
......@@ -222,7 +225,7 @@ void BuildTestStoreWithSchemaFromM55(const base::FilePath& file) {
statement.BindString(6, kTestClientId2.id);
statement.BindCString(7, kTestURL);
statement.BindString(8, base::FilePath(kFilePath).MaybeAsASCII());
statement.BindInt64(9, base::Time::Now().ToInternalValue());
statement.BindInt64(9, store_utils::ToDatabaseTime(base::Time::Now()));
statement.BindString16(10, base::UTF8ToUTF16("Test title"));
ASSERT_TRUE(statement.Run());
ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1));
......@@ -267,7 +270,7 @@ void BuildTestStoreWithSchemaFromM56(const base::FilePath& file) {
statement.BindString(6, kTestClientId2.id);
statement.BindCString(7, kTestURL);
statement.BindString(8, base::FilePath(kFilePath).MaybeAsASCII());
statement.BindInt64(9, base::Time::Now().ToInternalValue());
statement.BindInt64(9, store_utils::ToDatabaseTime(base::Time::Now()));
statement.BindString16(10, base::UTF8ToUTF16("Test title"));
statement.BindCString(11, kOriginalTestURL);
ASSERT_TRUE(statement.Run());
......@@ -459,232 +462,101 @@ void BuildTestStoreWithSchemaVersion1(const base::FilePath& file) {
InjectItemInM62Store(&connection, generator.CreateItem());
}
class OfflinePageMetadataStoreFactory {
public:
OfflinePageMetadataStore* BuildStore(const base::FilePath& file_path) {
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM52(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM52(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM53(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM53(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM54(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM54(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM55(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM55(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM56(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM56(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM57(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM57(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM61(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM61(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreM62(const base::FilePath& file_path) {
BuildTestStoreWithSchemaFromM62(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
OfflinePageMetadataStore* BuildStoreVersion1(
const base::FilePath& file_path) {
BuildTestStoreWithSchemaVersion1(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
// Create an offline page item from a SQL result. Expects complete rows with
// all columns present.
OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
int64_t id = statement->ColumnInt64(0);
base::Time creation_time =
store_utils::FromDatabaseTime(statement->ColumnInt64(1));
int64_t file_size = statement->ColumnInt64(2);
base::Time last_access_time =
store_utils::FromDatabaseTime(statement->ColumnInt64(3));
int access_count = statement->ColumnInt(4);
int64_t system_download_id = statement->ColumnInt64(5);
base::Time file_missing_time =
store_utils::FromDatabaseTime(statement->ColumnInt64(6));
int upgrade_attempt = statement->ColumnInt(7);
ClientId client_id(statement->ColumnString(8), statement->ColumnString(9));
GURL url(statement->ColumnString(10));
base::FilePath path(
store_utils::FromDatabaseFilePath(statement->ColumnString(11)));
base::string16 title = statement->ColumnString16(12);
GURL original_url(statement->ColumnString(13));
std::string request_origin = statement->ColumnString(14);
std::string digest = statement->ColumnString(15);
OfflinePageItem item(url, id, client_id, path, file_size, creation_time);
item.last_access_time = last_access_time;
item.access_count = access_count;
item.title = title;
item.original_url = original_url;
item.request_origin = request_origin;
item.system_download_id = system_download_id;
item.file_missing_time = file_missing_time;
item.upgrade_attempt = upgrade_attempt;
item.digest = digest;
return item;
}
std::vector<OfflinePageItem> GetOfflinePagesSync(sql::Connection* db) {
std::vector<OfflinePageItem> result;
if (!db)
return result;
const char kSql[] = "SELECT * FROM " OFFLINE_PAGES_TABLE_V1;
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
while (statement.Step())
result.push_back(MakeOfflinePageItem(&statement));
if (!statement.Succeeded()) {
result.clear();
}
};
enum CalledCallback { NONE, LOAD, ADD, UPDATE, REMOVE, RESET };
enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE };
return result;
}
class OfflinePageMetadataStoreTest : public testing::Test {
public:
OfflinePageMetadataStoreTest();
~OfflinePageMetadataStoreTest() override;
OfflinePageMetadataStoreTest()
: task_runner_(new base::TestMockTimeTaskRunner),
task_runner_handle_(task_runner_) {
EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
}
~OfflinePageMetadataStoreTest() override{};
protected:
void TearDown() override {
// Wait for all the pieces of the store to delete itself properly.
PumpLoop();
}
std::unique_ptr<OfflinePageMetadataStore> BuildStore();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithoutInit();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM52();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM53();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM54();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM55();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM56();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM57();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM61();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM62();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaVersion1();
void VerifyMetaVersions(int expected_current_version,
int expected_compatible_version);
void PumpLoop();
void FastForwardBy(base::TimeDelta time_delta);
void InitializeCallback(bool success);
void GetOfflinePagesCallback(std::vector<OfflinePageItem> offline_pages);
void AddCallback(ItemActionStatus status);
void UpdateCallback(CalledCallback called_callback,
std::unique_ptr<OfflinePagesUpdateResult> result);
void ResetCallback(bool success);
void ClearResults();
OfflinePageItem CheckThatStoreHasOneItem();
void CheckThatOfflinePageCanBeSaved(
std::unique_ptr<OfflinePageMetadataStore> store);
void CheckStoreItemsPostUpgradeFromVersion1();
std::unique_ptr<OfflinePageMetadataStoreSQL> BuildStore() {
auto store = std::make_unique<OfflinePageMetadataStoreSQL>(
base::ThreadTaskRunnerHandle::Get(), TempPath());
PumpLoop();
return store;
}
OfflinePagesUpdateResult* last_update_result() {
return last_update_result_.get();
void PumpLoop() { task_runner_->RunUntilIdle(); }
void FastForwardBy(base::TimeDelta delta) {
task_runner_->FastForwardBy(delta);
}
base::TestMockTimeTaskRunner* task_runner() const {
return task_runner_.get();
}
base::FilePath TempPath() const { return temp_directory_.GetPath(); }
protected:
CalledCallback last_called_callback_;
int get_callback_counter_;
Status last_status_;
std::unique_ptr<OfflinePagesUpdateResult> last_update_result_;
std::vector<OfflinePageItem> offline_pages_;
OfflinePageMetadataStoreFactory factory_;
base::ScopedTempDir temp_directory_;
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
};
OfflinePageMetadataStoreTest::OfflinePageMetadataStoreTest()
: last_called_callback_(NONE),
get_callback_counter_(0),
last_status_(STATUS_NONE),
task_runner_(new base::TestMockTimeTaskRunner),
task_runner_handle_(task_runner_) {
EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
}
OfflinePageMetadataStoreTest::~OfflinePageMetadataStoreTest() {}
void OfflinePageMetadataStoreTest::PumpLoop() {
task_runner_->RunUntilIdle();
}
void OfflinePageMetadataStoreTest::FastForwardBy(base::TimeDelta delta) {
task_runner_->FastForwardBy(delta);
}
void OfflinePageMetadataStoreTest::InitializeCallback(bool success) {
last_status_ = success ? STATUS_TRUE : STATUS_FALSE;
}
void OfflinePageMetadataStoreTest::GetOfflinePagesCallback(
std::vector<OfflinePageItem> offline_pages) {
last_called_callback_ = LOAD;
get_callback_counter_++;
offline_pages_.swap(offline_pages);
}
void OfflinePageMetadataStoreTest::AddCallback(ItemActionStatus status) {
last_called_callback_ = ADD;
last_status_ =
status == ItemActionStatus::SUCCESS ? STATUS_TRUE : STATUS_FALSE;
}
void OfflinePageMetadataStoreTest::UpdateCallback(
CalledCallback called_callback,
std::unique_ptr<OfflinePagesUpdateResult> result) {
last_called_callback_ = called_callback;
last_status_ = result->updated_items.size() > 0 ? STATUS_TRUE : STATUS_FALSE;
last_update_result_ = std::move(result);
}
void OfflinePageMetadataStoreTest::ResetCallback(bool success) {
last_called_callback_ = RESET;
last_status_ = success ? STATUS_TRUE : STATUS_FALSE;
}
void OfflinePageMetadataStoreTest::ClearResults() {
last_called_callback_ = NONE;
last_status_ = STATUS_NONE;
offline_pages_.clear();
last_update_result_.reset(nullptr);
}
OfflinePageItem OfflinePageMetadataStoreTest::CheckThatStoreHasOneItem() {
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
EXPECT_EQ(1U, offline_pages_.size());
return offline_pages_[0];
}
void OfflinePageMetadataStoreTest::CheckStoreItemsPostUpgradeFromVersion1() {
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
EXPECT_EQ(5U, offline_pages_.size());
// TODO(fgorski): Use persistent namespaces from the client policy controller
// once an appropriate method is available.
std::set<std::string> upgradeable_namespaces{
kAsyncNamespace, kDownloadNamespace, kBrowserActionsNamespace,
kNTPSuggestionsNamespace};
for (auto page : offline_pages_) {
if (upgradeable_namespaces.count(page.client_id.name_space) > 0)
EXPECT_EQ(5, page.upgrade_attempt);
else
EXPECT_EQ(0, page.upgrade_attempt);
OfflinePageItem CheckThatStoreHasOneItem(OfflinePageMetadataStoreSQL* store) {
std::vector<OfflinePageItem> pages = GetOfflinePages(store);
EXPECT_EQ(1U, pages.size());
return pages[0];
}
}
void OfflinePageMetadataStoreTest::CheckThatOfflinePageCanBeSaved(
std::unique_ptr<OfflinePageMetadataStore> store) {
size_t store_size = offline_pages_.size();
void CheckThatOfflinePageCanBeSaved(
std::unique_ptr<OfflinePageMetadataStoreSQL> store) {
size_t store_size = GetOfflinePages(store.get()).size();
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
offline_page.title = base::UTF8ToUTF16("a title");
......@@ -692,396 +564,217 @@ void OfflinePageMetadataStoreTest::CheckThatOfflinePageCanBeSaved(
offline_page.system_download_id = kTestSystemDownloadId;
offline_page.digest = kTestDigest;
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
EXPECT_EQ(ItemActionStatus::SUCCESS,
AddOfflinePage(store.get(), offline_page));
// Close the store first to ensure file lock is removed.
store.reset();
store = BuildStore();
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ASSERT_EQ(store_size + 1, offline_pages_.size());
if (store_size > 0 &&
offline_pages_[0].offline_id != offline_page.offline_id) {
std::swap(offline_pages_[0], offline_pages_[1]);
std::vector<OfflinePageItem> pages = GetOfflinePages(store.get());
ASSERT_EQ(store_size + 1, pages.size());
if (store_size > 0 && pages[0].offline_id != offline_page.offline_id) {
std::swap(pages[0], pages[1]);
}
EXPECT_EQ(offline_page, pages[0]);
}
EXPECT_EQ(offline_page, offline_pages_[0]);
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStore() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStore(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithoutInit() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStore(temp_directory_.GetPath()));
return store;
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM52() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM52(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM53() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM53(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM54() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM54(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
void VerifyMetaVersions() {
sql::Connection connection;
ASSERT_TRUE(connection.Open(temp_directory_.GetPath().Append(
FILE_PATH_LITERAL("OfflinePages.db"))));
ASSERT_TRUE(connection.is_open());
EXPECT_TRUE(sql::MetaTable::DoesTableExist(&connection));
sql::MetaTable meta_table;
EXPECT_TRUE(meta_table.Init(&connection, 1, 1));
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM55() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM55(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
EXPECT_EQ(2, meta_table.GetVersionNumber());
EXPECT_EQ(1, meta_table.GetCompatibleVersionNumber());
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM56() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM56(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
void LoadAndCheckStore() {
auto store = std::make_unique<OfflinePageMetadataStoreSQL>(
base::ThreadTaskRunnerHandle::Get(), TempPath());
OfflinePageItem item = CheckThatStoreHasOneItem(store.get());
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions();
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM57() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM57(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
template <typename T>
T ExecuteSync(OfflinePageMetadataStoreSQL* store,
base::OnceCallback<T(sql::Connection*)> run_callback) {
bool called = false;
T result;
auto result_callback = base::BindLambdaForTesting([&](T async_result) {
result = std::move(async_result);
called = true;
});
store->Execute<T>(std::move(run_callback), result_callback);
PumpLoop();
EXPECT_TRUE(called);
return result;
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM61() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM61(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
void GetOfflinePagesAsync(
OfflinePageMetadataStoreSQL* store,
base::OnceCallback<void(std::vector<OfflinePageItem>)> callback) {
auto run_callback = base::BindOnce(&GetOfflinePagesSync);
store->Execute<std::vector<OfflinePageItem>>(std::move(run_callback),
std::move(callback));
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM62() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreM62(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::BindRepeating(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(base::BindRepeating(
&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
std::vector<OfflinePageItem> GetOfflinePages(
OfflinePageMetadataStoreSQL* store) {
return ExecuteSync<std::vector<OfflinePageItem>>(
store, base::BindOnce(&GetOfflinePagesSync));
}
std::unique_ptr<OfflinePageMetadataStore>
OfflinePageMetadataStoreTest::BuildStoreWithSchemaVersion1() {
std::unique_ptr<OfflinePageMetadataStore> store(
factory_.BuildStoreVersion1(temp_directory_.GetPath()));
PumpLoop();
store->Initialize(
base::BindRepeating(&OfflinePageMetadataStoreTest::InitializeCallback,
base::Unretained(this)));
PumpLoop();
store->GetOfflinePages(base::BindRepeating(
&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
return store;
}
ItemActionStatus AddOfflinePage(OfflinePageMetadataStoreSQL* store,
const OfflinePageItem& item) {
auto result_callback = base::BindLambdaForTesting([&](sql::Connection* db) {
if (!db)
return ItemActionStatus::STORE_ERROR;
// Using 'INSERT OR FAIL' or 'INSERT OR ABORT' in the query below
// causes debug builds to DLOG.
const char kSql[] =
"INSERT OR IGNORE INTO " OFFLINE_PAGES_TABLE_V1
" (offline_id, online_url, client_namespace, client_id, "
"file_path, "
"file_size, creation_time, last_access_time, access_count, "
"title, original_url, request_origin, system_download_id, "
"file_missing_time, upgrade_attempt, digest)"
" VALUES "
" (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, item.offline_id);
statement.BindString(1, item.url.spec());
statement.BindString(2, item.client_id.name_space);
statement.BindString(3, item.client_id.id);
statement.BindString(4, store_utils::ToDatabaseFilePath(item.file_path));
statement.BindInt64(5, item.file_size);
statement.BindInt64(6, store_utils::ToDatabaseTime(item.creation_time));
statement.BindInt64(7,
store_utils::ToDatabaseTime(item.last_access_time));
statement.BindInt(8, item.access_count);
statement.BindString16(9, item.title);
statement.BindString(10, item.original_url.spec());
statement.BindString(11, item.request_origin);
statement.BindInt64(12, item.system_download_id);
statement.BindInt64(13,
store_utils::ToDatabaseTime(item.file_missing_time));
statement.BindInt(14, item.upgrade_attempt);
statement.BindString(15, item.digest);
void OfflinePageMetadataStoreTest::VerifyMetaVersions(
int expected_current_version,
int expected_compatible_version) {
sql::Connection connection;
ASSERT_TRUE(connection.Open(
temp_directory_.GetPath().Append(FILE_PATH_LITERAL("OfflinePages.db"))));
ASSERT_TRUE(connection.is_open());
EXPECT_TRUE(sql::MetaTable::DoesTableExist(&connection));
sql::MetaTable meta_table;
EXPECT_TRUE(meta_table.Init(&connection, 1, 1));
if (!statement.Run())
return ItemActionStatus::STORE_ERROR;
if (db->GetLastChangeCount() == 0)
return ItemActionStatus::ALREADY_EXISTS;
return ItemActionStatus::SUCCESS;
});
return ExecuteSync<ItemActionStatus>(store, result_callback);
}
EXPECT_EQ(expected_current_version, meta_table.GetVersionNumber());
EXPECT_EQ(expected_compatible_version,
meta_table.GetCompatibleVersionNumber());
}
base::ScopedTempDir temp_directory_;
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
};
// Loads empty store and makes sure that there are no offline pages stored in
// it.
TEST_F(OfflinePageMetadataStoreTest, LoadEmptyStore) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
EXPECT_EQ(0U, offline_pages_.size());
std::unique_ptr<OfflinePageMetadataStoreSQL> store(BuildStore());
EXPECT_EQ(0U, GetOfflinePages(store.get()).size());
}
TEST_F(OfflinePageMetadataStoreTest, GetOfflinePagesFromInvalidStore) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
OfflinePageMetadataStoreSQL* sql_store =
static_cast<OfflinePageMetadataStoreSQL*>(store.get());
std::unique_ptr<OfflinePageMetadataStoreSQL> store(BuildStore());
// Because execute method is self-healing this part of the test expects a
// positive results now.
sql_store->SetStateForTesting(StoreState::NOT_LOADED, false);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
EXPECT_EQ(StoreState::LOADED, store->state());
ClearResults();
sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
EXPECT_EQ(StoreState::FAILED_LOADING, store->state());
ClearResults();
sql_store->SetStateForTesting(StoreState::FAILED_RESET, false);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
EXPECT_EQ(StoreState::FAILED_RESET, store->state());
ClearResults();
sql_store->SetStateForTesting(StoreState::LOADED, true);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
ClearResults();
sql_store->SetStateForTesting(StoreState::NOT_LOADED, true);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
ClearResults();
sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
ClearResults();
sql_store->SetStateForTesting(StoreState::FAILED_RESET, false);
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0UL, offline_pages_.size());
}
store->SetStateForTesting(StoreState::NOT_LOADED, false);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
EXPECT_EQ(StoreState::LOADED, store->GetStateForTesting());
// Loads a store which has an outdated schema.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM52());
store->SetStateForTesting(StoreState::FAILED_LOADING, false);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
EXPECT_EQ(StoreState::FAILED_LOADING, store->GetStateForTesting());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
store->SetStateForTesting(StoreState::FAILED_RESET, false);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
EXPECT_EQ(StoreState::FAILED_RESET, store->GetStateForTesting());
store->SetStateForTesting(StoreState::LOADED, true);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
store->SetStateForTesting(StoreState::NOT_LOADED, true);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
store->SetStateForTesting(StoreState::FAILED_LOADING, false);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
store->SetStateForTesting(StoreState::FAILED_RESET, false);
EXPECT_EQ(0UL, GetOfflinePages(store.get()).size());
}
// Loads a store which has an outdated schema.
// This test case would crash if it's not handling correctly when we're loading
// These tests would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) {
BuildTestStoreWithSchemaFromM52(TempPath());
LoadAndCheckStore();
}
TEST_F(OfflinePageMetadataStoreTest, LoadVersion53Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM53());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM53(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from M54.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion54Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM54());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM54(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from M55.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion55Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM55());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM55(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from M56.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion56Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM56());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM56(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from M57.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion57Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM57());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM57(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from M61.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion61Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM61());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM61(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from M62.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion62Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM62());
OfflinePageItem item = CheckThatStoreHasOneItem();
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
BuildTestStoreWithSchemaFromM62(TempPath());
LoadAndCheckStore();
}
// Loads a string with schema from version 1 (as tracked by meta table).
TEST_F(OfflinePageMetadataStoreTest, LoadStoreWithMetaVersion1) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaVersion1());
BuildTestStoreWithSchemaVersion1(TempPath());
auto store = std::make_unique<OfflinePageMetadataStoreSQL>(
base::ThreadTaskRunnerHandle::Get(), TempPath());
std::vector<OfflinePageItem> pages = GetOfflinePages(store.get());
EXPECT_EQ(5U, pages.size());
// TODO(fgorski): Use persistent namespaces from the client policy controller
// once an appropriate method is available.
std::set<std::string> upgradeable_namespaces{
kAsyncNamespace, kDownloadNamespace, kBrowserActionsNamespace,
kNTPSuggestionsNamespace};
CheckStoreItemsPostUpgradeFromVersion1();
for (const OfflinePageItem& page : pages) {
if (upgradeable_namespaces.count(page.client_id.name_space) > 0)
EXPECT_EQ(5, page.upgrade_attempt);
else
EXPECT_EQ(0, page.upgrade_attempt);
}
CheckThatOfflinePageCanBeSaved(std::move(store));
VerifyMetaVersions(2, 1);
VerifyMetaVersions();
}
// Adds metadata of an offline page into a store and then opens the store
......@@ -1091,104 +784,28 @@ TEST_F(OfflinePageMetadataStoreTest, AddOfflinePage) {
}
TEST_F(OfflinePageMetadataStoreTest, AddSameOfflinePageTwice) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
std::unique_ptr<OfflinePageMetadataStoreSQL> store(BuildStore());
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
offline_page.title = base::UTF8ToUTF16("a title");
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_FALSE, last_status_);
}
// Tests removing offline page metadata from the store, for which it first adds
// metadata of an offline page.
TEST_F(OfflinePageMetadataStoreTest, RemoveOfflinePage) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// Add an offline page.
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
// Get all pages from the store.
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(1U, offline_pages_.size());
// Remove the offline page.
std::vector<int64_t> ids_to_remove;
ids_to_remove.push_back(offline_page.offline_id);
store->RemoveOfflinePages(
ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback,
base::Unretained(this), REMOVE));
PumpLoop();
EXPECT_EQ(REMOVE, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ASSERT_TRUE(last_update_result() != nullptr);
EXPECT_EQ(1UL, last_update_result()->item_statuses.size());
EXPECT_EQ(ItemActionStatus::SUCCESS,
last_update_result()->item_statuses.begin()->second);
EXPECT_EQ(1UL, last_update_result()->updated_items.size());
EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin()));
ClearResults();
AddOfflinePage(store.get(), offline_page));
// Get all pages from the store.
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0U, offline_pages_.size());
ClearResults();
// Close and reload the store.
store.reset();
store = BuildStore();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
EXPECT_EQ(0U, offline_pages_.size());
EXPECT_EQ(ItemActionStatus::ALREADY_EXISTS,
AddOfflinePage(store.get(), offline_page));
}
// Adds metadata of multiple offline pages into a store and removes some.
TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
std::unique_ptr<OfflinePageMetadataStoreSQL> store(BuildStore());
// Add an offline page.
OfflinePageItem offline_page_1(GURL(kTestURL), 12345LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
store->AddOfflinePage(offline_page_1,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
EXPECT_EQ(ItemActionStatus::SUCCESS,
AddOfflinePage(store.get(), offline_page_1));
// Add anther offline page.
base::FilePath file_path_2 =
......@@ -1199,227 +816,59 @@ TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
offline_page_2.original_url = GURL("https://example.com/bar");
offline_page_2.system_download_id = kTestSystemDownloadId;
offline_page_2.digest = kTestDigest;
store->AddOfflinePage(offline_page_2,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
// Get all pages from the store.
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(2U, offline_pages_.size());
// Remove the offline page.
std::vector<int64_t> ids_to_remove;
ids_to_remove.push_back(offline_page_1.offline_id);
store->RemoveOfflinePages(
ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback,
base::Unretained(this), REMOVE));
PumpLoop();
EXPECT_EQ(REMOVE, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ASSERT_TRUE(last_update_result() != nullptr);
EXPECT_EQ(1UL, last_update_result()->item_statuses.size());
EXPECT_EQ(ItemActionStatus::SUCCESS,
last_update_result()->item_statuses.begin()->second);
EXPECT_EQ(1UL, last_update_result()->updated_items.size());
EXPECT_EQ(offline_page_1, *(last_update_result()->updated_items.begin()));
AddOfflinePage(store.get(), offline_page_2));
ClearResults();
// Get all pages from the store.
std::vector<OfflinePageItem> pages = GetOfflinePages(store.get());
EXPECT_EQ(2U, pages.size());
// Close and reload the store.
store.reset();
store = BuildStore();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ASSERT_EQ(1U, offline_pages_.size());
EXPECT_EQ(offline_page_2, offline_pages_[0]);
}
// Tests updating offline page metadata from the store.
TEST_F(OfflinePageMetadataStoreTest, UpdateOfflinePage) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// First, adds a fresh page.
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
ASSERT_EQ(1U, offline_pages_.size());
EXPECT_EQ(offline_page, offline_pages_[0]);
// Then update some data.
offline_page.file_size = kFileSize + 1;
offline_page.access_count++;
offline_page.original_url = GURL("https://example.com/bar");
offline_page.request_origin = kTestRequestOrigin;
offline_page.upgrade_attempt = 1;
offline_page.digest = kTestDigest;
std::vector<OfflinePageItem> items_to_update;
items_to_update.push_back(offline_page);
store->UpdateOfflinePages(
items_to_update, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback,
base::Unretained(this), UPDATE));
PumpLoop();
EXPECT_EQ(UPDATE, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ASSERT_TRUE(last_update_result() != nullptr);
EXPECT_EQ(1UL, last_update_result()->item_statuses.size());
EXPECT_EQ(ItemActionStatus::SUCCESS,
last_update_result()->item_statuses.begin()->second);
EXPECT_EQ(1UL, last_update_result()->updated_items.size());
EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin()));
ClearResults();
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
ASSERT_EQ(1U, offline_pages_.size());
EXPECT_EQ(offline_page, offline_pages_[0]);
}
// In current implementation Reset is a no-op. No pages are erased.
// See bug 725122 for more info.
TEST_F(OfflinePageMetadataStoreTest, ResetStoreDoesNotErase) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// Add 2 offline pages.
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
OfflinePageItem offline_page2(GURL("http://test.com"), 5678LL, kTestClientId2,
base::FilePath(kFilePath), kFileSize);
store->AddOfflinePage(offline_page2,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(ADD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
// Get all pages from the store.
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(2U, offline_pages_.size());
store->Reset(base::Bind(&OfflinePageMetadataStoreTest::ResetCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(RESET, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ClearResults();
// Get all pages from the store.
store->GetOfflinePages(
base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
// Verify the store still loads with original content.
EXPECT_EQ(LOAD, last_called_callback_);
ASSERT_EQ(2U, offline_pages_.size());
}
TEST_F(OfflinePageMetadataStoreTest, ResetStore) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
store->Reset(base::Bind(&OfflinePageMetadataStoreTest::ResetCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(STATUS_TRUE, last_status_);
pages = GetOfflinePages(store.get());
ASSERT_EQ(2U, pages.size());
EXPECT_EQ(offline_page_2, pages[0]);
}
TEST_F(OfflinePageMetadataStoreTest, StoreCloses) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
std::unique_ptr<OfflinePageMetadataStoreSQL> store(BuildStore());
GetOfflinePages(store.get());
PumpLoop();
EXPECT_TRUE(task_runner()->HasPendingTask());
EXPECT_LT(base::TimeDelta(), task_runner()->NextPendingTaskDelay());
FastForwardBy(OfflinePageMetadataStoreSQL::kClosingDelay);
PumpLoop();
EXPECT_EQ(StoreState::NOT_LOADED, store->state());
ClearResults();
EXPECT_EQ(StoreState::NOT_LOADED, store->GetStateForTesting());
// Ensure that next call to the store will actually reinitialize it.
store->GetOfflinePages(base::BindRepeating(
&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(StoreState::LOADED, store->state());
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0U, offline_pages_.size());
EXPECT_EQ(0U, GetOfflinePages(store.get()).size());
EXPECT_EQ(StoreState::LOADED, store->GetStateForTesting());
}
TEST_F(OfflinePageMetadataStoreTest, MultiplePendingCalls) {
std::unique_ptr<OfflinePageMetadataStore> store(BuildStoreWithoutInit());
auto store = std::make_unique<OfflinePageMetadataStoreSQL>(
base::ThreadTaskRunnerHandle::Get(), TempPath());
EXPECT_FALSE(task_runner()->HasPendingTask());
EXPECT_EQ(StoreState::NOT_LOADED, store->state());
EXPECT_EQ(StoreState::NOT_LOADED, store->GetStateForTesting());
// First call flips the state to initializing.
store->GetOfflinePages(base::BindRepeating(
&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
EXPECT_EQ(StoreState::INITIALIZING, store->state());
// Subsequent calls should be pending until store is initialized.
store->GetOfflinePages(base::BindRepeating(
&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
store->GetOfflinePages(base::BindRepeating(
&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
base::Unretained(this)));
PumpLoop();
EXPECT_EQ(StoreState::LOADED, store->state());
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(0U, offline_pages_.size());
EXPECT_EQ(3, get_callback_counter_);
int callback_count = 0;
auto get_complete =
base::BindLambdaForTesting([&](std::vector<OfflinePageItem> pages) {
++callback_count;
EXPECT_TRUE(pages.empty());
});
GetOfflinePagesAsync(store.get(), get_complete);
EXPECT_EQ(StoreState::INITIALIZING, store->GetStateForTesting());
GetOfflinePagesAsync(store.get(), get_complete);
EXPECT_EQ(0U, GetOfflinePages(store.get()).size());
EXPECT_EQ(StoreState::LOADED, store->GetStateForTesting());
EXPECT_EQ(2, callback_count);
}
} // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment