Commit 066d5d12 authored by David Maunder's avatar David Maunder Committed by Chromium LUCI CQ

Apply templates to PersistedStateDB database

By using templates the database is reusable for different protocol
buffers. One application is for chrome cart which in the experimental
code looked very similar to persisted_state_db. By using templates we
can avoid duplicating a lot of code.

Bug: 1154499
Change-Id: I65bdaa3142eede152db26cd5629001b815f3b493
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2570451Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarssid <ssid@chromium.org>
Reviewed-by: default avatarYue Zhang <yuezhanggg@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Commit-Queue: David Maunder <davidjm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836924}
parent 5df98182
...@@ -1977,6 +1977,7 @@ static_library("browser") { ...@@ -1977,6 +1977,7 @@ static_library("browser") {
"//chrome/browser/notifications/scheduler:factory", "//chrome/browser/notifications/scheduler:factory",
"//chrome/browser/notifications/scheduler/public", "//chrome/browser/notifications/scheduler/public",
"//chrome/browser/persisted_state_db:persisted_state_db", "//chrome/browser/persisted_state_db:persisted_state_db",
"//chrome/browser/persisted_state_db:persisted_state_db_content_proto",
"//chrome/browser/policy:path_parser", "//chrome/browser/policy:path_parser",
"//chrome/browser/privacy_budget", "//chrome/browser/privacy_budget",
"//chrome/browser/profiling_host", "//chrome/browser/profiling_host",
......
...@@ -7,11 +7,17 @@ import("//third_party/protobuf/proto_library.gni") ...@@ -7,11 +7,17 @@ import("//third_party/protobuf/proto_library.gni")
source_set("persisted_state_db") { source_set("persisted_state_db") {
sources = [ sources = [
"profile_proto_db.h",
"profile_proto_db_factory.cc",
"profile_proto_db_factory.h",
]
if (is_android) {
sources += [
"persisted_state_db.cc", "persisted_state_db.cc",
"persisted_state_db.h", "persisted_state_db.h",
"persisted_state_db_factory.cc",
"persisted_state_db_factory.h",
] ]
}
deps = [ deps = [
":persisted_state_db_content_proto", ":persisted_state_db_content_proto",
......
...@@ -4,194 +4,19 @@ ...@@ -4,194 +4,19 @@
#include "chrome/browser/persisted_state_db/persisted_state_db.h" #include "chrome/browser/persisted_state_db/persisted_state_db.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/leveldb_proto/public/proto_database_provider.h"
#include "third_party/leveldatabase/src/include/leveldb/options.h"
#if defined(OS_ANDROID)
#include "base/android/callback_android.h" #include "base/android/callback_android.h"
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_array.h" #include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_factory.h" #include "base/bind.h"
#include "base/callback_helpers.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h"
#include "chrome/browser/persisted_state_db/profile_proto_db_factory.h"
#include "chrome/browser/tab/jni_headers/LevelDBPersistedTabDataStorage_jni.h" #include "chrome/browser/tab/jni_headers/LevelDBPersistedTabDataStorage_jni.h"
#include "components/embedder_support/android/browser_context/browser_context_handle.h" #include "components/embedder_support/android/browser_context/browser_context_handle.h"
#endif // defined(OS_ANDROID)
namespace { namespace {
const char kPersistedStateDBFolder[] = "persisted_state_db";
leveldb::ReadOptions CreateReadOptions() {
leveldb::ReadOptions opts;
opts.fill_cache = false;
return opts;
}
bool DatabasePrefixFilter(const std::string& key_prefix,
const std::string& key) {
return base::StartsWith(key, key_prefix, base::CompareCase::SENSITIVE);
}
} // namespace
PersistedStateDB::~PersistedStateDB() = default;
void PersistedStateDB::LoadContent(const std::string& key,
LoadCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(base::BindOnce(
&PersistedStateDB::LoadContent, weak_ptr_factory_.GetWeakPtr(),
std::move(key), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), false, std::vector<KeyAndValue>()));
} else {
storage_database_->LoadEntriesWithFilter(
base::BindRepeating(&DatabasePrefixFilter, key), CreateReadOptions(),
/* target_prefix */ "",
base::BindOnce(&PersistedStateDB::OnLoadContent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
void PersistedStateDB::InsertContent(const std::string& key,
const std::vector<uint8_t>& value,
OperationCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(base::BindOnce(
&PersistedStateDB::InsertContent, weak_ptr_factory_.GetWeakPtr(),
std::move(key), std::move(value), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(std::move(callback), false));
} else {
auto contents_to_save = std::make_unique<ContentEntry>();
persisted_state_db::PersistedStateContentProto proto;
proto.set_key(key);
proto.set_content_data(value.data(), value.size());
contents_to_save->emplace_back(proto.key(), std::move(proto));
storage_database_->UpdateEntries(
std::move(contents_to_save),
std::make_unique<std::vector<std::string>>(),
base::BindOnce(&PersistedStateDB::OnOperationCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
void PersistedStateDB::DeleteContent(const std::string& key,
OperationCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(base::BindOnce(
&PersistedStateDB::DeleteContent, weak_ptr_factory_.GetWeakPtr(),
std::move(key), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(std::move(callback), false));
} else {
storage_database_->UpdateEntriesWithRemoveFilter(
std::make_unique<ContentEntry>(),
std::move(base::BindRepeating(&DatabasePrefixFilter, std::move(key))),
base::BindOnce(&PersistedStateDB::OnOperationCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
void PersistedStateDB::DeleteAllContent(OperationCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(
base::BindOnce(&PersistedStateDB::DeleteAllContent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(std::move(callback), false));
} else {
storage_database_->Destroy(std::move(callback));
}
}
PersistedStateDB::PersistedStateDB(
content::BrowserContext* browser_context,
leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
const base::FilePath& profile_directory)
: browser_context_(browser_context),
database_status_(base::nullopt),
storage_database_(
proto_database_provider
->GetDB<persisted_state_db::PersistedStateContentProto>(
leveldb_proto::ProtoDbType::PERSISTED_STATE_DATABASE,
profile_directory.AppendASCII(kPersistedStateDBFolder),
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}))) {
storage_database_->Init(
base::BindOnce(&PersistedStateDB::OnDatabaseInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
PersistedStateDB::PersistedStateDB(
std::unique_ptr<leveldb_proto::ProtoDatabase<
persisted_state_db::PersistedStateContentProto>> storage_database,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: database_status_(base::nullopt),
storage_database_(std::move(storage_database)) {
storage_database_->Init(
base::BindOnce(&PersistedStateDB::OnDatabaseInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
void PersistedStateDB::OnDatabaseInitialized(
leveldb_proto::Enums::InitStatus status) {
database_status_ =
base::make_optional<leveldb_proto::Enums::InitStatus>(status);
for (auto& deferred_operation : deferred_operations_) {
std::move(deferred_operation).Run();
}
deferred_operations_.clear();
}
void PersistedStateDB::OnLoadContent(
LoadCallback callback,
bool success,
std::unique_ptr<std::vector<persisted_state_db::PersistedStateContentProto>>
content) {
std::vector<KeyAndValue> results;
if (success) {
for (const auto& proto : *content) {
DCHECK(proto.has_key());
DCHECK(proto.has_content_data());
results.emplace_back(proto.key(),
std::vector<uint8_t>(proto.content_data().begin(),
proto.content_data().end()));
}
}
std::move(callback).Run(success, std::move(results));
}
void PersistedStateDB::OnOperationCommitted(OperationCallback callback,
bool success) {
std::move(callback).Run(success);
}
bool PersistedStateDB::InitStatusUnknown() const {
return database_status_ == base::nullopt;
}
bool PersistedStateDB::FailedToInit() const {
return database_status_.has_value() &&
database_status_.value() != leveldb_proto::Enums::InitStatus::kOK;
}
#if defined(OS_ANDROID)
namespace {
void OnUpdateCallback( void OnUpdateCallback(
const base::android::JavaRef<jobject>& joncomplete_for_testing, const base::android::JavaRef<jobject>& joncomplete_for_testing,
bool success) { bool success) {
...@@ -203,26 +28,41 @@ void OnUpdateCallback( ...@@ -203,26 +28,41 @@ void OnUpdateCallback(
base::android::RunRunnableAndroid(joncomplete_for_testing); base::android::RunRunnableAndroid(joncomplete_for_testing);
} }
void OnLoadCallback(const base::android::JavaRef<jobject>& jcallback, void OnLoadCallback(
const base::android::JavaRef<jobject>& jcallback,
bool success, bool success,
std::vector<PersistedStateDB::KeyAndValue> data) { std::vector<ProfileProtoDB<
persisted_state_db::PersistedStateContentProto>::KeyAndValue> data) {
if (!success) if (!success)
LOG(WARNING) << "There was an error loading from PersistedStateDB"; LOG(WARNING) << "There was an error loading from PersistedStateDB";
base::android::RunObjectCallbackAndroid( base::android::RunObjectCallbackAndroid(
jcallback, base::android::ToJavaByteArray( jcallback, base::android::ToJavaByteArray(
base::android::AttachCurrentThread(), base::android::AttachCurrentThread(),
data.empty() ? std::vector<uint8_t>() : data[0].second)); data.empty() ? "" : data[0].second.content_data()));
} }
} // namespace } // namespace
PersistedStateDB::PersistedStateDB(content::BrowserContext* browser_context)
: proto_db_(
ProfileProtoDBFactory<
persisted_state_db::PersistedStateContentProto>::GetInstance()
->GetForProfile(browser_context)) {}
PersistedStateDB::~PersistedStateDB() = default;
void PersistedStateDB::Save( void PersistedStateDB::Save(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jstring>& jkey, const base::android::JavaParamRef<jstring>& jkey,
const base::android::JavaParamRef<jbyteArray>& byte_array, const base::android::JavaParamRef<jbyteArray>& jbyte_array,
const base::android::JavaRef<jobject>& joncomplete_for_testing) { const base::android::JavaRef<jobject>& joncomplete_for_testing) {
std::vector<uint8_t> data; const std::string& key = base::android::ConvertJavaStringToUTF8(env, jkey);
base::android::JavaByteArrayToByteVector(env, byte_array, &data); std::string data;
InsertContent(base::android::ConvertJavaStringToUTF8(env, jkey), data, base::android::JavaByteArrayToString(env, jbyte_array, &data);
persisted_state_db::PersistedStateContentProto proto;
proto.set_key(key);
proto.set_content_data(data);
proto_db_->InsertContent(
key, proto,
base::BindOnce(&OnUpdateCallback, base::BindOnce(&OnUpdateCallback,
base::android::ScopedJavaGlobalRef<jobject>( base::android::ScopedJavaGlobalRef<jobject>(
joncomplete_for_testing))); joncomplete_for_testing)));
...@@ -231,7 +71,7 @@ void PersistedStateDB::Save( ...@@ -231,7 +71,7 @@ void PersistedStateDB::Save(
void PersistedStateDB::Load(JNIEnv* env, void PersistedStateDB::Load(JNIEnv* env,
const base::android::JavaParamRef<jstring>& jkey, const base::android::JavaParamRef<jstring>& jkey,
const base::android::JavaRef<jobject>& jcallback) { const base::android::JavaRef<jobject>& jcallback) {
LoadContent( proto_db_->LoadContentWithPrefix(
base::android::ConvertJavaStringToUTF8(env, jkey), base::android::ConvertJavaStringToUTF8(env, jkey),
base::BindOnce(&OnLoadCallback, base::BindOnce(&OnLoadCallback,
base::android::ScopedJavaGlobalRef<jobject>(jcallback))); base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
...@@ -241,24 +81,23 @@ void PersistedStateDB::Delete( ...@@ -241,24 +81,23 @@ void PersistedStateDB::Delete(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jstring>& jkey, const base::android::JavaParamRef<jstring>& jkey,
const base::android::JavaRef<jobject>& joncomplete_for_testing) { const base::android::JavaRef<jobject>& joncomplete_for_testing) {
DeleteContent(base::android::ConvertJavaStringToUTF8(env, jkey), proto_db_->DeleteContentWithPrefix(
base::android::ConvertJavaStringToUTF8(env, jkey),
base::BindOnce(&OnUpdateCallback, base::BindOnce(&OnUpdateCallback,
base::android::ScopedJavaGlobalRef<jobject>( base::android::ScopedJavaGlobalRef<jobject>(
joncomplete_for_testing))); joncomplete_for_testing)));
} }
void PersistedStateDB::Destroy(JNIEnv* env) { void PersistedStateDB::Destroy(JNIEnv* env) {
PersistedStateDBFactory::GetInstance()->Disassociate(browser_context_); proto_db_->Destroy();
} }
static void JNI_LevelDBPersistedTabDataStorage_Init( static void JNI_LevelDBPersistedTabDataStorage_Init(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& jprofile) { const base::android::JavaParamRef<jobject>& jprofile) {
PersistedStateDB* persisted_state_db =
PersistedStateDBFactory::GetInstance()->GetForProfile(
browser_context::BrowserContextFromJavaHandle(jprofile));
Java_LevelDBPersistedTabDataStorage_setNativePtr( Java_LevelDBPersistedTabDataStorage_setNativePtr(
env, obj, reinterpret_cast<intptr_t>(persisted_state_db)); env, obj,
reinterpret_cast<intptr_t>(new PersistedStateDB(
browser_context::BrowserContextFromJavaHandle(jprofile))));
} }
#endif // OS_ANDROID
...@@ -9,31 +9,21 @@ ...@@ -9,31 +9,21 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/android/scoped_java_ref.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "build/build_config.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h" #include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "components/leveldb_proto/public/proto_database.h" #include "components/leveldb_proto/public/proto_database.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
#include "build/build_config.h"
#endif // OS_ANDROID
namespace leveldb_proto {
class ProtoDatabaseProvider;
} // namespace leveldb_proto
namespace content { namespace content {
class BrowserContext; class BrowserContext;
} // namespace content } // namespace content
class PersistedStateDBFactory; template <typename T>
class PersistedStateDBFactoryTest; class ProfileProtoDB;
class PersistedStateDBTest;
// PersistedStateDB is leveldb backend store for NonCriticalPersistedTabData. // PersistedStateDB is leveldb backend store for NonCriticalPersistedTabData.
// NonCriticalPersistedTabData is an extension of TabState where data for // NonCriticalPersistedTabData is an extension of TabState where data for
...@@ -42,42 +32,12 @@ class PersistedStateDBTest; ...@@ -42,42 +32,12 @@ class PersistedStateDBTest;
// <NonCriticalPersistedTabData id>_<Tab id> // <NonCriticalPersistedTabData id>_<Tab id>
// NonCriticalPersistedTabData is stored in key/value pairs. // NonCriticalPersistedTabData is stored in key/value pairs.
class PersistedStateDB : public KeyedService { class PersistedStateDB {
public: public:
using KeyAndValue = std::pair<std::string, std::vector<uint8_t>>; explicit PersistedStateDB(content::BrowserContext* browser_context);
PersistedStateDB(const PersistedStateDB&) = delete;
// Callback when content is acquired PersistedStateDB& operator=(const PersistedStateDB&) = delete;
using LoadCallback = base::OnceCallback<void(bool, std::vector<KeyAndValue>)>; ~PersistedStateDB();
// Used for confirming an operation was completed successfully (e.g.
// insert, delete). This will be invoked on a different SequenceRunner
// to TabStateDB.
using OperationCallback = base::OnceCallback<void(bool)>;
// Entry in the database
using ContentEntry = leveldb_proto::ProtoDatabase<
persisted_state_db::PersistedStateContentProto>::KeyEntryVector;
~PersistedStateDB() override;
// Loads the content data for the key and passes them to the callback
void LoadContent(const std::string& key, LoadCallback callback);
// Inserts a value for a given key and passes the result (success/failure) to
// OperationCallback
void InsertContent(const std::string& key,
const std::vector<uint8_t>& value,
OperationCallback callback);
// Deletes content in the database, matching all keys which have a prefix
// that matches the key
void DeleteContent(const std::string& key, OperationCallback callback);
// Delete all content in the database
void DeleteAllContent(OperationCallback callback);
#if defined(OS_ANDROID)
// The following are callable from LevelDBPersistedTabDataStorage over JNI.
// Save byte array for key. // Save byte array for key.
void Save(JNIEnv* env, void Save(JNIEnv* env,
...@@ -98,62 +58,10 @@ class PersistedStateDB : public KeyedService { ...@@ -98,62 +58,10 @@ class PersistedStateDB : public KeyedService {
// Destroy PersistedStateDB object. // Destroy PersistedStateDB object.
void Destroy(JNIEnv* env); void Destroy(JNIEnv* env);
#endif // OS_ANDROID
private: private:
friend class ::PersistedStateDBTest; ProfileProtoDB<persisted_state_db::PersistedStateContentProto>* proto_db_;
friend class ::PersistedStateDBFactory;
friend class ::PersistedStateDBFactoryTest;
// Initializes the database
PersistedStateDB(
content::BrowserContext* browser_context,
leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
const base::FilePath& profile_directory);
// Used for tests
explicit PersistedStateDB(
std::unique_ptr<leveldb_proto::ProtoDatabase<
persisted_state_db::PersistedStateContentProto>> storage_database,
scoped_refptr<base::SequencedTaskRunner> task_runner);
// Passes back database status following database initialization
void OnDatabaseInitialized(leveldb_proto::Enums::InitStatus status);
// Callback when content is loaded
void OnLoadContent(
LoadCallback callback,
bool success,
std::unique_ptr<
std::vector<persisted_state_db::PersistedStateContentProto>> content);
// Callback when an operation (e.g. insert or delete) is called
void OnOperationCommitted(OperationCallback callback, bool success);
// Returns true if initialization status of database is not yet known
bool InitStatusUnknown() const;
// Returns true if the database failed to initialize
bool FailedToInit() const;
// Browser context associated with the PersistedStateDB
content::BrowserContext* browser_context_;
// Status of the database initialization.
base::Optional<leveldb_proto::Enums::InitStatus> database_status_;
// The database for storing content storage information.
std::unique_ptr<leveldb_proto::ProtoDatabase<
persisted_state_db::PersistedStateContentProto>>
storage_database_;
// Store operations until the database is initialized at which point
// deferred_operations_ is flushed and all operations are executed.
std::vector<base::OnceClosure> deferred_operations_;
base::WeakPtrFactory<PersistedStateDB> weak_ptr_factory_{this}; base::WeakPtrFactory<PersistedStateDB> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(PersistedStateDB);
}; };
#endif // CHROME_BROWSER_PERSISTED_STATE_DB_PERSISTED_STATE_DB_H_ #endif // CHROME_BROWSER_PERSISTED_STATE_DB_PERSISTED_STATE_DB_H_
// Copyright 2020 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.
#include "chrome/browser/persisted_state_db/persisted_state_db_factory.h"
#include "chrome/browser/persisted_state_db/persisted_state_db.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
namespace {
const char kPersistedStateDBFolder[] = "persisted_state_db";
} // namespace
// static
PersistedStateDBFactory* PersistedStateDBFactory::GetInstance() {
return base::Singleton<PersistedStateDBFactory>::get();
}
// static
PersistedStateDB* PersistedStateDBFactory::GetForProfile(
content::BrowserContext* context) {
// Incognito is currently not supported
if (context->IsOffTheRecord())
return nullptr;
return static_cast<PersistedStateDB*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}
PersistedStateDBFactory::PersistedStateDBFactory()
: BrowserContextKeyedServiceFactory(
"PersistedStateDBKeyedService",
BrowserContextDependencyManager::GetInstance()) {}
PersistedStateDBFactory::~PersistedStateDBFactory() = default;
KeyedService* PersistedStateDBFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
DCHECK(!context->IsOffTheRecord());
leveldb_proto::ProtoDatabaseProvider* proto_database_provider =
content::BrowserContext::GetDefaultStoragePartition(context)
->GetProtoDatabaseProvider();
base::FilePath tab_state_db_dir(
context->GetPath().AppendASCII(kPersistedStateDBFolder));
return new PersistedStateDB(context, proto_database_provider,
tab_state_db_dir);
}
// Copyright 2020 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 CHROME_BROWSER_PERSISTED_STATE_DB_PERSISTED_STATE_DB_FACTORY_H_
#define CHROME_BROWSER_PERSISTED_STATE_DB_PERSISTED_STATE_DB_FACTORY_H_
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
class KeyedService;
class PersistedStateDB;
// Factory to create on PersistedStateDB per profile. Incognito is currently
// not supported and the factory will return nullptr for an incognito profile.
class PersistedStateDBFactory : public BrowserContextKeyedServiceFactory {
public:
// Acquire instance of PersistedStateDBFactory
static PersistedStateDBFactory* GetInstance();
// Acquire PersistedStateDB - there is one per profile.
static PersistedStateDB* GetForProfile(content::BrowserContext* context);
// Call the parent Disassocaite which is a protected method
void Disassociate(content::BrowserContext* context) {
BrowserContextKeyedServiceFactory::Disassociate(context);
}
private:
friend struct base::DefaultSingletonTraits<PersistedStateDBFactory>;
PersistedStateDBFactory();
~PersistedStateDBFactory() override;
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
};
#endif // CHROME_BROWSER_PERSISTED_STATE_DB_PERSISTED_STATE_DB_FACTORY_H_
// Copyright 2020 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 CHROME_BROWSER_PERSISTED_STATE_DB_PROFILE_PROTO_DB_H_
#define CHROME_BROWSER_PERSISTED_STATE_DB_PROFILE_PROTO_DB_H_
#include <queue>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/leveldb_proto/public/proto_database.h"
#include "components/leveldb_proto/public/proto_database_provider.h"
#include "content/public/browser/browser_context.h"
#include "third_party/leveldatabase/src/include/leveldb/options.h"
class ProfileProtoDBTest;
template <typename T>
class ProfileProtoDBFactory;
// General purpose per profile, per proto key -> proto database where the
// template is the proto which is being stored. A ProfileProtoDB should be
// acquired using ProfileProtoDBFactory. ProfileProtoDB is a wrapper on top of
// leveldb_proto which:
// - Is specifically for databases which are per profile and per proto
// (leveldb_proto is a proto database which may or may not be per profile).
// - Provides a simplified interface for the use cases that surround
// ProfileProtoDB such as providing LoadContentWithPrefix instead of the
// more generic API in
// leveldb_proto which requires a filter to be passed in.
// - Is a KeyedService to support the per profile nature of the database.
template <typename T>
class ProfileProtoDB : public KeyedService {
public:
using KeyAndValue = std::pair<std::string, T>;
// Callback which is used when content is acquired.
using LoadCallback = base::OnceCallback<void(bool, std::vector<KeyAndValue>)>;
// Used for confirming an operation was completed successfully (e.g.
// insert, delete). This will be invoked on a different SequenceRunner
// to ProfileProtoDB.
using OperationCallback = base::OnceCallback<void(bool)>;
// Represents an entry in the database.
using ContentEntry = typename leveldb_proto::ProtoDatabase<T>::KeyEntryVector;
ProfileProtoDB(const ProfileProtoDB&) = delete;
ProfileProtoDB& operator=(const ProfileProtoDB&) = delete;
~ProfileProtoDB() override;
// Loads the content data matching a prefix for the key and passes them to the
// callback.
void LoadContentWithPrefix(const std::string& key_prefix,
LoadCallback callback);
// Inserts a value for a given key and passes the result (success/failure) to
// OperationCallback.
void InsertContent(const std::string& key,
const T& value,
OperationCallback callback);
// Deletes content in the database, matching all keys which have a prefix
// that matches the key.
void DeleteContentWithPrefix(const std::string& key_prefix,
OperationCallback callback);
// Delete all content in the database.
void DeleteAllContent(OperationCallback callback);
// Destroy the cached instance of the database (databases are cached per
// profile).
void Destroy() const;
private:
friend class ::ProfileProtoDBTest;
template <typename U>
friend class ::ProfileProtoDBFactory;
// Initializes the database.
ProfileProtoDB(content::BrowserContext* browser_context,
leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
const base::FilePath& database_dir,
leveldb_proto::ProtoDbType proto_db_type);
// Used for testing.
ProfileProtoDB(
std::unique_ptr<leveldb_proto::ProtoDatabase<T>> storage_database,
scoped_refptr<base::SequencedTaskRunner> task_runner);
// Passes back database status following database initialization.
void OnDatabaseInitialized(leveldb_proto::Enums::InitStatus status);
// Callback when content is loaded.
void OnLoadContent(LoadCallback callback,
bool success,
std::unique_ptr<std::vector<T>> content);
// Callback when an operation (e.g. insert or delete) is called.
void OnOperationCommitted(OperationCallback callback, bool success);
// Returns true if initialization status of database is not yet known.
bool InitStatusUnknown() const;
// Returns true if the database failed to initialize.
bool FailedToInit() const;
// Browser context associated with ProfileProtoDB (ProfileProtoDB are per
// profile).
content::BrowserContext* browser_context_;
// Status of the database initialization.
base::Optional<leveldb_proto::Enums::InitStatus> database_status_;
// The database for storing content storage information.
std::unique_ptr<leveldb_proto::ProtoDatabase<T>> storage_database_;
// Store operations until the database is initialized at which point
// |deferred_operations_| is flushed and all operations are executed.
std::vector<base::OnceClosure> deferred_operations_;
base::WeakPtrFactory<ProfileProtoDB> weak_ptr_factory_{this};
};
namespace {
leveldb::ReadOptions CreateReadOptions() {
leveldb::ReadOptions opts;
opts.fill_cache = false;
return opts;
}
bool DatabasePrefixFilter(const std::string& key_prefix,
const std::string& key) {
return base::StartsWith(key, key_prefix, base::CompareCase::SENSITIVE);
}
} // namespace
template <typename T>
ProfileProtoDB<T>::~ProfileProtoDB() = default;
template <typename T>
void ProfileProtoDB<T>::LoadContentWithPrefix(const std::string& key_prefix,
LoadCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(base::BindOnce(
&ProfileProtoDB::LoadContentWithPrefix, weak_ptr_factory_.GetWeakPtr(),
std::move(key_prefix), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), false, std::vector<KeyAndValue>()));
} else {
storage_database_->LoadEntriesWithFilter(
base::BindRepeating(&DatabasePrefixFilter, key_prefix),
CreateReadOptions(),
/* target_prefix */ "",
base::BindOnce(&ProfileProtoDB::OnLoadContent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
// Inserts a value for a given key and passes the result (success/failure) to
// OperationCallback.
template <typename T>
void ProfileProtoDB<T>::InsertContent(const std::string& key,
const T& value,
OperationCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(base::BindOnce(
&ProfileProtoDB::InsertContent, weak_ptr_factory_.GetWeakPtr(),
std::move(key), std::move(value), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(std::move(callback), false));
} else {
auto contents_to_save = std::make_unique<ContentEntry>();
contents_to_save->emplace_back(key, value);
storage_database_->UpdateEntries(
std::move(contents_to_save),
std::make_unique<std::vector<std::string>>(),
base::BindOnce(&ProfileProtoDB::OnOperationCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
// Deletes content in the database, matching all keys which have a prefix
// that matches the key.
template <typename T>
void ProfileProtoDB<T>::DeleteContentWithPrefix(const std::string& key_prefix,
OperationCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(
base::BindOnce(&ProfileProtoDB::DeleteContentWithPrefix,
weak_ptr_factory_.GetWeakPtr(), std::move(key_prefix),
std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(std::move(callback), false));
} else {
storage_database_->UpdateEntriesWithRemoveFilter(
std::make_unique<ContentEntry>(),
std::move(
base::BindRepeating(&DatabasePrefixFilter, std::move(key_prefix))),
base::BindOnce(&ProfileProtoDB::OnOperationCommitted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
// Delete all content in the database.
template <typename T>
void ProfileProtoDB<T>::DeleteAllContent(OperationCallback callback) {
if (InitStatusUnknown()) {
deferred_operations_.push_back(
base::BindOnce(&ProfileProtoDB::DeleteAllContent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} else if (FailedToInit()) {
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce(std::move(callback), false));
} else {
storage_database_->Destroy(std::move(callback));
}
}
template <typename T>
void ProfileProtoDB<T>::Destroy() const {
ProfileProtoDBFactory<T>::GetInstance()->Disassociate(browser_context_);
}
template <typename T>
ProfileProtoDB<T>::ProfileProtoDB(
content::BrowserContext* browser_context,
leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
const base::FilePath& database_dir,
leveldb_proto::ProtoDbType proto_db_type)
: browser_context_(browser_context),
database_status_(base::nullopt),
storage_database_(proto_database_provider->GetDB<T>(
proto_db_type,
database_dir,
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}))) {
static_assert(std::is_base_of<google::protobuf::MessageLite, T>::value,
"T must implement 'google::protobuf::MessageLite'");
storage_database_->Init(base::BindOnce(&ProfileProtoDB::OnDatabaseInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
// Used for tests.
template <typename T>
ProfileProtoDB<T>::ProfileProtoDB(
std::unique_ptr<leveldb_proto::ProtoDatabase<T>> storage_database,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: database_status_(base::nullopt),
storage_database_(std::move(storage_database)) {
static_assert(std::is_base_of<google::protobuf::MessageLite, T>::value,
"T must implement 'google::protobuf::MessageLite'");
storage_database_->Init(base::BindOnce(&ProfileProtoDB::OnDatabaseInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
// Passes back database status following database initialization.
template <typename T>
void ProfileProtoDB<T>::OnDatabaseInitialized(
leveldb_proto::Enums::InitStatus status) {
database_status_ =
base::make_optional<leveldb_proto::Enums::InitStatus>(status);
for (auto& deferred_operation : deferred_operations_) {
std::move(deferred_operation).Run();
}
deferred_operations_.clear();
}
// Callback when content is loaded.
template <typename T>
void ProfileProtoDB<T>::OnLoadContent(LoadCallback callback,
bool success,
std::unique_ptr<std::vector<T>> content) {
std::vector<KeyAndValue> results;
if (success) {
for (const auto& proto : *content) {
// TODO(crbug.com/1157881) relax requirement for proto to have a key field
// and return key value pairs OnLoadContent.
DCHECK(proto.has_key());
results.emplace_back(proto.key(), proto);
}
}
std::move(callback).Run(success, std::move(results));
}
// Callback when an operation (e.g. insert or delete) is called.
template <typename T>
void ProfileProtoDB<T>::OnOperationCommitted(OperationCallback callback,
bool success) {
std::move(callback).Run(success);
}
// Returns true if initialization status of database is not yet known.
template <typename T>
bool ProfileProtoDB<T>::InitStatusUnknown() const {
return database_status_ == base::nullopt;
}
// Returns true if the database failed to initialize.
template <typename T>
bool ProfileProtoDB<T>::FailedToInit() const {
return database_status_.has_value() &&
database_status_.value() != leveldb_proto::Enums::InitStatus::kOK;
}
#endif // CHROME_BROWSER_PERSISTED_STATE_DB_PROFILE_PROTO_DB_H_
// Copyright 2020 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.
#include "chrome/browser/persisted_state_db/profile_proto_db_factory.h"
#include "base/no_destructor.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h"
ProfileProtoDBFactory<persisted_state_db::PersistedStateContentProto>*
GetPersistedStateProfileProtoDBFactory() {
static base::NoDestructor<
ProfileProtoDBFactory<persisted_state_db::PersistedStateContentProto>>
instance;
return instance.get();
}
// Copyright 2020 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 CHROME_BROWSER_PERSISTED_STATE_DB_PROFILE_PROTO_DB_FACTORY_H_
#define CHROME_BROWSER_PERSISTED_STATE_DB_PROFILE_PROTO_DB_FACTORY_H_
#include "chrome/browser/persisted_state_db/profile_proto_db.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
namespace {
const char kPersistedStateDBFolder[] = "persisted_state_db";
} // namespace
ProfileProtoDBFactory<persisted_state_db::PersistedStateContentProto>*
GetPersistedStateProfileProtoDBFactory();
// Factory to create a ProtoDB per profile and per proto. Incognito is
// currently not supported and the factory will return nullptr for an incognito
// profile.
template <typename T>
class ProfileProtoDBFactory : public BrowserContextKeyedServiceFactory {
public:
// Acquire instance of ProfileProtoDBFactory.
static ProfileProtoDBFactory<T>* GetInstance();
// Acquire ProtoDB - there is one per profile.
static ProfileProtoDB<T>* GetForProfile(content::BrowserContext* context);
// Call the parent Disassociate which is a protected method.
void Disassociate(content::BrowserContext* context) {
BrowserContextKeyedServiceFactory::Disassociate(context);
}
private:
friend class base::NoDestructor<ProfileProtoDBFactory<T>>;
ProfileProtoDBFactory();
~ProfileProtoDBFactory() override;
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
};
// static
template <typename T>
ProfileProtoDBFactory<T>* ProfileProtoDBFactory<T>::GetInstance() {
static_assert(
std::is_base_of<persisted_state_db::PersistedStateContentProto, T>::
value /** subsequent supported templates will be ORed in here */,
"Provided template is not supported. To support implement a factory "
"method similar to GetPersistedStateProfileProtoDBFactory and add to "
"list of "
"supported templates");
return GetPersistedStateProfileProtoDBFactory();
}
// static
template <typename T>
ProfileProtoDB<T>* ProfileProtoDBFactory<T>::GetForProfile(
content::BrowserContext* context) {
// Incognito is currently not supported
if (context->IsOffTheRecord())
return nullptr;
return static_cast<ProfileProtoDB<T>*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}
template <typename T>
ProfileProtoDBFactory<T>::ProfileProtoDBFactory()
: BrowserContextKeyedServiceFactory(
"ProfileProtoDBFactory",
BrowserContextDependencyManager::GetInstance()) {}
template <typename T>
ProfileProtoDBFactory<T>::~ProfileProtoDBFactory() = default;
template <typename T>
KeyedService* ProfileProtoDBFactory<T>::BuildServiceInstanceFor(
content::BrowserContext* context) const {
DCHECK(!context->IsOffTheRecord());
leveldb_proto::ProtoDatabaseProvider* proto_database_provider =
content::BrowserContext::GetDefaultStoragePartition(context)
->GetProtoDatabaseProvider();
static_assert(
std::is_base_of<persisted_state_db::PersistedStateContentProto, T>::value,
"Provided template is not supported. To support add unique folder in the "
"below proto -> folder name mapping below this assert.");
// The following will become a proto -> dir and proto ->
// leveldb_proto::ProtoDbType mapping as more protos are added.
if (std::is_base_of<persisted_state_db::PersistedStateContentProto,
T>::value) {
return new ProfileProtoDB<T>(
context, proto_database_provider,
context->GetPath().AppendASCII(kPersistedStateDBFolder),
leveldb_proto::ProtoDbType::PERSISTED_STATE_DATABASE);
} else {
// Must add in leveldb_proto::ProtoDbType and database directory folder for
// new protos
DCHECK(false);
}
}
#endif // CHROME_BROWSER_PERSISTED_STATE_DB_PROFILE_PROTO_DB_FACTORY_H_
...@@ -2,18 +2,22 @@ ...@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/persisted_state_db/persisted_state_db_factory.h" #include "chrome/browser/persisted_state_db/profile_proto_db_factory.h"
#include <memory> #include <memory>
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
class PersistedStateDBFactoryTest : public testing::Test { class ProfileProtoDBFactoryTest : public testing::Test {
public: public:
PersistedStateDBFactoryTest() = default; ProfileProtoDBFactoryTest() = default;
ProfileProtoDBFactoryTest(const ProfileProtoDBFactoryTest&) = delete;
ProfileProtoDBFactoryTest& operator=(const ProfileProtoDBFactoryTest&) =
delete;
void SetUp() override { void SetUp() override {
ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
...@@ -37,22 +41,29 @@ class PersistedStateDBFactoryTest : public testing::Test { ...@@ -37,22 +41,29 @@ class PersistedStateDBFactoryTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_; content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfile> profile_; std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<TestingProfile> different_profile_; std::unique_ptr<TestingProfile> different_profile_;
DISALLOW_COPY_AND_ASSIGN(PersistedStateDBFactoryTest);
}; };
TEST_F(PersistedStateDBFactoryTest, TestIncognitoProfile) { TEST_F(ProfileProtoDBFactoryTest, TestIncognitoProfile) {
EXPECT_EQ(nullptr, PersistedStateDBFactory::GetInstance()->GetForProfile( EXPECT_EQ(nullptr,
profile()->GetPrimaryOTRProfile())); ProfileProtoDBFactory<
persisted_state_db::PersistedStateContentProto>::GetInstance()
->GetForProfile(profile()->GetPrimaryOTRProfile()));
} }
TEST_F(PersistedStateDBFactoryTest, TestSameProfile) { TEST_F(ProfileProtoDBFactoryTest, TestSameProfile) {
EXPECT_EQ(PersistedStateDBFactory::GetInstance()->GetForProfile(profile()), EXPECT_EQ(ProfileProtoDBFactory<
PersistedStateDBFactory::GetInstance()->GetForProfile(profile())); persisted_state_db::PersistedStateContentProto>::GetInstance()
->GetForProfile(profile()),
ProfileProtoDBFactory<
persisted_state_db::PersistedStateContentProto>::GetInstance()
->GetForProfile(profile()));
} }
TEST_F(PersistedStateDBFactoryTest, TestDifferentProfile) { TEST_F(ProfileProtoDBFactoryTest, TestDifferentProfile) {
EXPECT_NE(PersistedStateDBFactory::GetInstance()->GetForProfile( EXPECT_NE(ProfileProtoDBFactory<
different_profile()), persisted_state_db::PersistedStateContentProto>::GetInstance()
PersistedStateDBFactory::GetInstance()->GetForProfile(profile())); ->GetForProfile(different_profile()),
ProfileProtoDBFactory<
persisted_state_db::PersistedStateContentProto>::GetInstance()
->GetForProfile(profile()));
} }
// Copyright 2020 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.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package profile_proto_db;
// Proto used for testing purposes.
message ProfileProtoDBTestProto {
// A field
optional string key = 1;
// Another field
optional int32 b = 2;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/persisted_state_db/persisted_state_db.h" #include "chrome/browser/persisted_state_db/profile_proto_db.h"
#include <map> #include <map>
...@@ -14,41 +14,77 @@ ...@@ -14,41 +14,77 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "chrome/browser/persisted_state_db/profile_proto_db_test_proto.pb.h"
using testing::_; using testing::_;
namespace { namespace {
persisted_state_db::PersistedStateContentProto BuildProto(
const char* protoKey,
const std::vector<uint8_t> byteArray) {
persisted_state_db::PersistedStateContentProto proto;
proto.set_key(protoKey);
proto.set_content_data(byteArray.data(), byteArray.size());
return proto;
}
profile_proto_db::ProfileProtoDBTestProto BuildTestProto(const char* key,
const int32_t value) {
profile_proto_db::ProfileProtoDBTestProto proto;
proto.set_key(key);
proto.set_b(value);
return proto;
}
const char kMockKey[] = "key"; const char kMockKey[] = "key";
const char kMockKeyPrefix[] = "k"; const char kMockKeyPrefix[] = "k";
const std::vector<uint8_t> kMockValue = {0xfa, 0x5b, 0x4c, 0x12}; const std::vector<uint8_t> kMockValueArray = {0xfa, 0x5b, 0x4c, 0x12};
const std::vector<PersistedStateDB::KeyAndValue> kExpected = { const persisted_state_db::PersistedStateContentProto kMockValue =
{kMockKey, kMockValue}}; BuildProto(kMockKey, kMockValueArray);
const std::vector<PersistedStateDB::KeyAndValue> kEmptyExpected = {}; const std::vector<
ProfileProtoDB<persisted_state_db::PersistedStateContentProto>::KeyAndValue>
kExpected = {{kMockKey, kMockValue}};
const std::vector<
ProfileProtoDB<persisted_state_db::PersistedStateContentProto>::KeyAndValue>
kEmptyExpected = {};
const profile_proto_db::ProfileProtoDBTestProto kTestProto =
BuildTestProto(kMockKey, 42);
const std::vector<
ProfileProtoDB<profile_proto_db::ProfileProtoDBTestProto>::KeyAndValue>
kTestProtoExpected = {{kMockKey, kTestProto}};
} // namespace } // namespace
class PersistedStateDBTest : public testing::Test { class ProfileProtoDBTest : public testing::Test {
public: public:
PersistedStateDBTest() = default; ProfileProtoDBTest() = default;
ProfileProtoDBTest(const ProfileProtoDBTest&) = delete;
ProfileProtoDBTest& operator=(const ProfileProtoDBTest&) = delete;
// The following methods are specific to the database containing
// persisted_state_db::PersistedStateContentProto. There is one test which
// contains profile_proto_db::ProfileProtoDBTestProto to test the use case
// of multiple ProfileProtoDB databases running at the same time.
// Initialize the test database // Initialize the test database
void InitDatabase() { void InitPersistedStateDB() {
InitDatabaseWithoutCallback(); InitPersistedStateDBWithoutCallback();
MockInitCallback(content_db_, leveldb_proto::Enums::InitStatus::kOK); MockInitCallbackPersistedStateDB(content_db_,
leveldb_proto::Enums::InitStatus::kOK);
} }
void InitDatabaseWithoutCallback() { void InitPersistedStateDBWithoutCallback() {
auto storage_db = std::make_unique<leveldb_proto::test::FakeDB< auto storage_db = std::make_unique<leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>>(&content_db_storage_); persisted_state_db::PersistedStateContentProto>>(&content_db_storage_);
content_db_ = storage_db.get(); content_db_ = storage_db.get();
persisted_state_db_ = base::WrapUnique(new PersistedStateDB( persisted_state_db_ = base::WrapUnique(
new ProfileProtoDB<persisted_state_db::PersistedStateContentProto>(
std::move(storage_db), std::move(storage_db),
base::ThreadPool::CreateSequencedTaskRunner( base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}))); {base::MayBlock(), base::TaskPriority::USER_VISIBLE})));
} }
// Wait for all tasks to be cleared off the queue void MockInitCallbackPersistedStateDB(
void RunUntilIdle() { task_environment_.RunUntilIdle(); }
void MockInitCallback(
leveldb_proto::test::FakeDB< leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db, persisted_state_db::PersistedStateContentProto>* storage_db,
leveldb_proto::Enums::InitStatus status) { leveldb_proto::Enums::InitStatus status) {
...@@ -56,7 +92,7 @@ class PersistedStateDBTest : public testing::Test { ...@@ -56,7 +92,7 @@ class PersistedStateDBTest : public testing::Test {
RunUntilIdle(); RunUntilIdle();
} }
void MockInsertCallback( void MockInsertCallbackPersistedStateDB(
leveldb_proto::test::FakeDB< leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db, persisted_state_db::PersistedStateContentProto>* storage_db,
bool result) { bool result) {
...@@ -64,7 +100,7 @@ class PersistedStateDBTest : public testing::Test { ...@@ -64,7 +100,7 @@ class PersistedStateDBTest : public testing::Test {
RunUntilIdle(); RunUntilIdle();
} }
void MockLoadCallback( void MockLoadCallbackPersistedStateDB(
leveldb_proto::test::FakeDB< leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db, persisted_state_db::PersistedStateContentProto>* storage_db,
bool res) { bool res) {
...@@ -72,7 +108,7 @@ class PersistedStateDBTest : public testing::Test { ...@@ -72,7 +108,7 @@ class PersistedStateDBTest : public testing::Test {
RunUntilIdle(); RunUntilIdle();
} }
void MockDeleteCallback( void MockDeleteCallbackPersistedStateDB(
leveldb_proto::test::FakeDB< leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db, persisted_state_db::PersistedStateContentProto>* storage_db,
bool res) { bool res) {
...@@ -80,6 +116,23 @@ class PersistedStateDBTest : public testing::Test { ...@@ -80,6 +116,23 @@ class PersistedStateDBTest : public testing::Test {
RunUntilIdle(); RunUntilIdle();
} }
void GetEvaluationPersistedStateDB(
base::OnceClosure closure,
std::vector<ProfileProtoDB<
persisted_state_db::PersistedStateContentProto>::KeyAndValue>
expected,
bool result,
std::vector<ProfileProtoDB<
persisted_state_db::PersistedStateContentProto>::KeyAndValue> found) {
for (size_t i = 0; i < expected.size(); i++) {
EXPECT_EQ(found[i].first, expected[i].first);
EXPECT_EQ(found[i].second.content_data(),
expected[i].second.content_data());
}
std::move(closure).Run();
}
// Common to both databases
void OperationEvaluation(base::OnceClosure closure, void OperationEvaluation(base::OnceClosure closure,
bool expected_success, bool expected_success,
bool actual_success) { bool actual_success) {
...@@ -87,176 +140,248 @@ class PersistedStateDBTest : public testing::Test { ...@@ -87,176 +140,248 @@ class PersistedStateDBTest : public testing::Test {
std::move(closure).Run(); std::move(closure).Run();
} }
void GetEvaluation(base::OnceClosure closure, // Wait for all tasks to be cleared off the queue
std::vector<PersistedStateDB::KeyAndValue> expected, void RunUntilIdle() { task_environment_.RunUntilIdle(); }
// Specific to profile_proto_db::ProfileProtoDBTestProto database
void InitTestProtoDB() {
auto storage_db = std::make_unique<
leveldb_proto::test::FakeDB<profile_proto_db::ProfileProtoDBTestProto>>(
&test_content_db_storage_);
test_content_db_ = storage_db.get();
test_proto_db_ = base::WrapUnique(
new ProfileProtoDB<profile_proto_db::ProfileProtoDBTestProto>(
std::move(storage_db),
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})));
}
void GetTestEvaluationTestProtoDB(
base::OnceClosure closure,
std::vector<ProfileProtoDB<
profile_proto_db::ProfileProtoDBTestProto>::KeyAndValue> expected,
bool result, bool result,
std::vector<PersistedStateDB::KeyAndValue> found) { std::vector<ProfileProtoDB<
profile_proto_db::ProfileProtoDBTestProto>::KeyAndValue> found) {
for (size_t i = 0; i < expected.size(); i++) { for (size_t i = 0; i < expected.size(); i++) {
EXPECT_EQ(found[i].first, expected[i].first); EXPECT_EQ(found[i].first, expected[i].first);
EXPECT_EQ(found[i].second, expected[i].second); EXPECT_EQ(found[i].second.b(), expected[i].second.b());
} }
std::move(closure).Run(); std::move(closure).Run();
} }
PersistedStateDB* persisted_state_db() { return persisted_state_db_.get(); } // For persisted_state_db::PersistedStateContentProto database
ProfileProtoDB<persisted_state_db::PersistedStateContentProto>*
persisted_state_db() {
return persisted_state_db_.get();
}
leveldb_proto::test::FakeDB<persisted_state_db::PersistedStateContentProto>* leveldb_proto::test::FakeDB<persisted_state_db::PersistedStateContentProto>*
content_db() { content_db() {
return content_db_; return content_db_;
} }
std::vector<base::OnceClosure>& deferred_operations() { std::vector<base::OnceClosure>& deferred_operations() {
return persisted_state_db()->deferred_operations_; return persisted_state_db()->deferred_operations_;
} }
bool InitStatusUnknown() { return persisted_state_db()->InitStatusUnknown(); } bool InitStatusUnknown() { return persisted_state_db()->InitStatusUnknown(); }
bool FailedToInit() { return persisted_state_db()->FailedToInit(); } bool FailedToInit() { return persisted_state_db()->FailedToInit(); }
private:
base::test::TaskEnvironment task_environment_;
std::map<std::string, persisted_state_db::PersistedStateContentProto> std::map<std::string, persisted_state_db::PersistedStateContentProto>
content_db_storage_; content_db_storage_;
// For profile_proto_db::ProfileProtoDBTestProto database
ProfileProtoDB<profile_proto_db::ProfileProtoDBTestProto>* test_proto_db() {
return test_proto_db_.get();
}
leveldb_proto::test::FakeDB<profile_proto_db::ProfileProtoDBTestProto>*
test_content_db() {
return test_content_db_;
}
std::map<std::string, profile_proto_db::ProfileProtoDBTestProto>
test_content_db_storage_;
protected:
leveldb_proto::test::FakeDB<profile_proto_db::ProfileProtoDBTestProto>*
test_content_db_;
private:
base::test::TaskEnvironment task_environment_;
// For persisted_state_db::PersistedStateContentProto database
leveldb_proto::test::FakeDB<persisted_state_db::PersistedStateContentProto>* leveldb_proto::test::FakeDB<persisted_state_db::PersistedStateContentProto>*
content_db_; content_db_;
std::unique_ptr<PersistedStateDB> persisted_state_db_; std::unique_ptr<
ProfileProtoDB<persisted_state_db::PersistedStateContentProto>>
persisted_state_db_;
DISALLOW_COPY_AND_ASSIGN(PersistedStateDBTest); // For profile_proto_db::ProfileProtoDBTestProto database
std::unique_ptr<ProfileProtoDB<profile_proto_db::ProfileProtoDBTestProto>>
test_proto_db_;
}; };
TEST_F(PersistedStateDBTest, TestInit) { // Test an arbitrary proto - this ensures we can have two ProfilProtoDB
InitDatabase(); // databases running simultaneously.
TEST_F(ProfileProtoDBTest, TestArbitraryProto) {
InitTestProtoDB();
test_content_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
RunUntilIdle();
base::RunLoop run_loop[2];
test_proto_db()->InsertContent(
kMockKey, kTestProto,
base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
test_content_db()->UpdateCallback(true);
RunUntilIdle();
run_loop[0].Run();
test_proto_db()->LoadContentWithPrefix(
kMockKey,
base::BindOnce(&ProfileProtoDBTest::GetTestEvaluationTestProtoDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kTestProtoExpected));
test_content_db()->LoadCallback(true);
RunUntilIdle();
run_loop[1].Run();
}
TEST_F(ProfileProtoDBTest, TestInit) {
InitPersistedStateDB();
EXPECT_EQ(false, FailedToInit()); EXPECT_EQ(false, FailedToInit());
} }
TEST_F(PersistedStateDBTest, TestKeyInsertionSucceeded) { TEST_F(ProfileProtoDBTest, TestKeyInsertionSucceeded) {
InitDatabase(); InitPersistedStateDB();
base::RunLoop run_loop[2]; base::RunLoop run_loop[2];
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true)); base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallback(content_db(), true); MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run(); run_loop[0].Run();
persisted_state_db()->LoadContent( persisted_state_db()->LoadContentWithPrefix(
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, kMockKey,
base::Unretained(this), base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
run_loop[1].QuitClosure(), kExpected)); base::Unretained(this), run_loop[1].QuitClosure(),
MockLoadCallback(content_db(), true); kExpected));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run(); run_loop[1].Run();
} }
TEST_F(PersistedStateDBTest, TestKeyInsertionFailed) { TEST_F(ProfileProtoDBTest, TestKeyInsertionFailed) {
InitDatabase(); InitPersistedStateDB();
base::RunLoop run_loop[2]; base::RunLoop run_loop[2];
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), false)); base::Unretained(this), run_loop[0].QuitClosure(), false));
MockInsertCallback(content_db(), false); MockInsertCallbackPersistedStateDB(content_db(), false);
run_loop[0].Run(); run_loop[0].Run();
std::vector<PersistedStateDB::KeyAndValue> expected; persisted_state_db()->LoadContentWithPrefix(
persisted_state_db()->LoadContent( kMockKey,
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), base::Unretained(this), run_loop[1].QuitClosure(),
run_loop[1].QuitClosure(), expected)); kEmptyExpected));
MockLoadCallback(content_db(), true); MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run(); run_loop[1].Run();
} }
TEST_F(PersistedStateDBTest, TestKeyInsertionPrefix) { TEST_F(ProfileProtoDBTest, TestKeyInsertionPrefix) {
InitDatabase(); InitPersistedStateDB();
base::RunLoop run_loop[2]; base::RunLoop run_loop[2];
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true)); base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallback(content_db(), true); MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run(); run_loop[0].Run();
std::vector<PersistedStateDB::KeyAndValue> expected; persisted_state_db()->LoadContentWithPrefix(
expected.emplace_back(kMockKey, kMockValue); kMockKeyPrefix,
persisted_state_db()->LoadContent( base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
kMockKeyPrefix, base::BindOnce(&PersistedStateDBTest::GetEvaluation, base::Unretained(this), run_loop[1].QuitClosure(),
base::Unretained(this), kExpected));
run_loop[1].QuitClosure(), expected)); MockLoadCallbackPersistedStateDB(content_db(), true);
MockLoadCallback(content_db(), true);
run_loop[1].Run(); run_loop[1].Run();
} }
TEST_F(PersistedStateDBTest, TestDelete) { TEST_F(ProfileProtoDBTest, TestDelete) {
InitDatabase(); InitPersistedStateDB();
base::RunLoop run_loop[4]; base::RunLoop run_loop[4];
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true)); base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallback(content_db(), true); MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run(); run_loop[0].Run();
std::vector<PersistedStateDB::KeyAndValue> expected; persisted_state_db()->LoadContentWithPrefix(
expected.emplace_back(kMockKey, kMockValue); kMockKey,
persisted_state_db()->LoadContent( base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, base::Unretained(this), run_loop[1].QuitClosure(),
base::Unretained(this), kExpected));
run_loop[1].QuitClosure(), expected)); MockLoadCallbackPersistedStateDB(content_db(), true);
MockLoadCallback(content_db(), true);
run_loop[1].Run(); run_loop[1].Run();
persisted_state_db()->DeleteContent( persisted_state_db()->DeleteContentWithPrefix(
kMockKey, kMockKey,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), true)); base::Unretained(this), run_loop[2].QuitClosure(), true));
MockDeleteCallback(content_db(), true); MockDeleteCallbackPersistedStateDB(content_db(), true);
run_loop[2].Run(); run_loop[2].Run();
std::vector<PersistedStateDB::KeyAndValue> expected_after_delete; persisted_state_db()->LoadContentWithPrefix(
persisted_state_db()->LoadContent(
kMockKey, kMockKey,
base::BindOnce(&PersistedStateDBTest::GetEvaluation, base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[3].QuitClosure(), base::Unretained(this), run_loop[3].QuitClosure(),
expected_after_delete)); kEmptyExpected));
MockLoadCallback(content_db(), true); MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[3].Run(); run_loop[3].Run();
} }
TEST_F(PersistedStateDBTest, TestDeferredOperations) { TEST_F(ProfileProtoDBTest, TestDeferredOperations) {
InitDatabaseWithoutCallback(); InitPersistedStateDBWithoutCallback();
RunUntilIdle(); RunUntilIdle();
EXPECT_EQ(true, InitStatusUnknown()); EXPECT_EQ(true, InitStatusUnknown());
base::RunLoop run_loop[4]; base::RunLoop run_loop[4];
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true)); base::Unretained(this), run_loop[0].QuitClosure(), true));
persisted_state_db()->LoadContent( persisted_state_db()->LoadContentWithPrefix(
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, kMockKey,
base::Unretained(this), base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
run_loop[1].QuitClosure(), kExpected)); base::Unretained(this), run_loop[1].QuitClosure(),
kExpected));
EXPECT_EQ(2u, deferred_operations().size()); EXPECT_EQ(2u, deferred_operations().size());
content_db()->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK); content_db()->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
EXPECT_EQ(false, FailedToInit()); EXPECT_EQ(false, FailedToInit());
MockInsertCallback(content_db(), true); MockInsertCallbackPersistedStateDB(content_db(), true);
MockLoadCallback(content_db(), true); MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run(); run_loop[0].Run();
run_loop[1].Run(); run_loop[1].Run();
EXPECT_EQ(0u, deferred_operations().size()); EXPECT_EQ(0u, deferred_operations().size());
persisted_state_db()->DeleteContent( persisted_state_db()->DeleteContentWithPrefix(
kMockKey, kMockKey,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), true)); base::Unretained(this), run_loop[2].QuitClosure(), true));
EXPECT_EQ(0u, deferred_operations().size()); EXPECT_EQ(0u, deferred_operations().size());
MockDeleteCallback(content_db(), true); MockDeleteCallbackPersistedStateDB(content_db(), true);
persisted_state_db()->LoadContent( persisted_state_db()->LoadContentWithPrefix(
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, kMockKey,
base::Unretained(this), base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
run_loop[3].QuitClosure(), kEmptyExpected)); base::Unretained(this), run_loop[3].QuitClosure(),
kEmptyExpected));
EXPECT_EQ(0u, deferred_operations().size()); EXPECT_EQ(0u, deferred_operations().size());
MockLoadCallback(content_db(), true); MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[3].Run(); run_loop[3].Run();
} }
TEST_F(PersistedStateDBTest, TestInitializationFailure) { TEST_F(ProfileProtoDBTest, TestInitializationFailure) {
InitDatabaseWithoutCallback(); InitPersistedStateDBWithoutCallback();
RunUntilIdle(); RunUntilIdle();
EXPECT_EQ(true, InitStatusUnknown()); EXPECT_EQ(true, InitStatusUnknown());
base::RunLoop run_loop[6]; base::RunLoop run_loop[6];
...@@ -264,15 +389,16 @@ TEST_F(PersistedStateDBTest, TestInitializationFailure) { ...@@ -264,15 +389,16 @@ TEST_F(PersistedStateDBTest, TestInitializationFailure) {
// Do some operations before database status is known // Do some operations before database status is known
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), false)); base::Unretained(this), run_loop[0].QuitClosure(), false));
persisted_state_db()->LoadContent( persisted_state_db()->LoadContentWithPrefix(
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, kMockKey,
base::Unretained(this), base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
run_loop[1].QuitClosure(), kEmptyExpected)); base::Unretained(this), run_loop[1].QuitClosure(),
persisted_state_db()->DeleteContent( kEmptyExpected));
persisted_state_db()->DeleteContentWithPrefix(
kMockKey, kMockKey,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), false)); base::Unretained(this), run_loop[2].QuitClosure(), false));
EXPECT_EQ(3u, deferred_operations().size()); EXPECT_EQ(3u, deferred_operations().size());
...@@ -290,15 +416,16 @@ TEST_F(PersistedStateDBTest, TestInitializationFailure) { ...@@ -290,15 +416,16 @@ TEST_F(PersistedStateDBTest, TestInitializationFailure) {
// failed to initialize // failed to initialize
persisted_state_db()->InsertContent( persisted_state_db()->InsertContent(
kMockKey, kMockValue, kMockKey, kMockValue,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[3].QuitClosure(), false)); base::Unretained(this), run_loop[3].QuitClosure(), false));
persisted_state_db()->LoadContent( persisted_state_db()->LoadContentWithPrefix(
kMockKey, base::BindOnce(&PersistedStateDBTest::GetEvaluation, kMockKey,
base::Unretained(this), base::BindOnce(&ProfileProtoDBTest::GetEvaluationPersistedStateDB,
run_loop[4].QuitClosure(), kEmptyExpected)); base::Unretained(this), run_loop[4].QuitClosure(),
persisted_state_db()->DeleteContent( kEmptyExpected));
persisted_state_db()->DeleteContentWithPrefix(
kMockKey, kMockKey,
base::BindOnce(&PersistedStateDBTest::OperationEvaluation, base::BindOnce(&ProfileProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[5].QuitClosure(), false)); base::Unretained(this), run_loop[5].QuitClosure(), false));
// Operations should have returned immediately as database was initialization // Operations should have returned immediately as database was initialization
......
...@@ -54,7 +54,8 @@ ...@@ -54,7 +54,8 @@
#include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
#include "chrome/browser/permissions/last_tab_standing_tracker_factory.h" #include "chrome/browser/permissions/last_tab_standing_tracker_factory.h"
#include "chrome/browser/permissions/permission_auditing_service_factory.h" #include "chrome/browser/permissions/permission_auditing_service_factory.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_factory.h" #include "chrome/browser/persisted_state_db/persisted_state_db_content.pb.h"
#include "chrome/browser/persisted_state_db/profile_proto_db_factory.h"
#include "chrome/browser/plugins/plugin_prefs_factory.h" #include "chrome/browser/plugins/plugin_prefs_factory.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.h" #include "chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.h"
#include "chrome/browser/predictors/autocomplete_action_predictor_factory.h" #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h"
...@@ -343,7 +344,8 @@ void ChromeBrowserMainExtraPartsProfiles:: ...@@ -343,7 +344,8 @@ void ChromeBrowserMainExtraPartsProfiles::
#endif #endif
PasswordStoreFactory::GetInstance(); PasswordStoreFactory::GetInstance();
PermissionAuditingServiceFactory::GetInstance(); PermissionAuditingServiceFactory::GetInstance();
PersistedStateDBFactory::GetInstance(); ProfileProtoDBFactory<
persisted_state_db::PersistedStateContentProto>::GetInstance();
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
PinnedTabServiceFactory::GetInstance(); PinnedTabServiceFactory::GetInstance();
#endif #endif
......
...@@ -3610,8 +3610,8 @@ test("unit_tests") { ...@@ -3610,8 +3610,8 @@ test("unit_tests") {
"../browser/permissions/permission_context_base_feature_policy_unittest.cc", "../browser/permissions/permission_context_base_feature_policy_unittest.cc",
"../browser/permissions/prediction_based_permission_ui_selector_unittest.cc", "../browser/permissions/prediction_based_permission_ui_selector_unittest.cc",
"../browser/permissions/pref_notification_permission_ui_selector_unittest.cc", "../browser/permissions/pref_notification_permission_ui_selector_unittest.cc",
"../browser/persisted_state_db/persisted_state_db_factory_unittest.cc", "../browser/persisted_state_db/profile_proto_db_factory_unittest.cc",
"../browser/persisted_state_db/persisted_state_db_unittest.cc", "../browser/persisted_state_db/profile_proto_db_unittest.cc",
"../browser/plugins/pdf_iframe_navigation_throttle_unittest.cc", "../browser/plugins/pdf_iframe_navigation_throttle_unittest.cc",
"../browser/policy/boolean_disabling_policy_handler_unittest.cc", "../browser/policy/boolean_disabling_policy_handler_unittest.cc",
"../browser/policy/chrome_browser_policy_connector_unittest.cc", "../browser/policy/chrome_browser_policy_connector_unittest.cc",
...@@ -4148,6 +4148,7 @@ test("unit_tests") { ...@@ -4148,6 +4148,7 @@ test("unit_tests") {
deps = [ deps = [
":messaging_test_proto", ":messaging_test_proto",
":profile_proto_db_test_proto",
":test_support", ":test_support",
":test_support_unit", ":test_support_unit",
"//base:base_stack_sampling_profiler_test_util", "//base:base_stack_sampling_profiler_test_util",
...@@ -7726,3 +7727,8 @@ if (!is_android) { ...@@ -7726,3 +7727,8 @@ if (!is_android) {
proto_library("messaging_test_proto") { proto_library("messaging_test_proto") {
sources = [ "//chrome/browser/policy/messaging_layer/proto/test.proto" ] sources = [ "//chrome/browser/policy/messaging_layer/proto/test.proto" ]
} }
proto_library("profile_proto_db_test_proto") {
sources =
[ "../browser/persisted_state_db/profile_proto_db_test_proto.proto" ]
}
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