| // Copyright 2019 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 "components/leveldb_proto/internal/proto_database_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/task/thread_pool/thread_pool_instance.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/task_environment.h" |
| #include "base/threading/thread.h" |
| #include "components/leveldb_proto/internal/leveldb_proto_feature_list.h" |
| #include "components/leveldb_proto/internal/shared_proto_database_provider.h" |
| #include "components/leveldb_proto/public/proto_database_provider.h" |
| #include "components/leveldb_proto/testing/proto/test_db.pb.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace leveldb_proto { |
| |
| namespace { |
| |
| const std::string kDefaultClientName = "client"; |
| const std::string kDefaultClientName2 = "client_2"; |
| |
| // Example struct defined by clients that can be used instead of protos. |
| struct ClientStruct { |
| public: |
| ClientStruct() {} |
| ClientStruct(ClientStruct&& other) { |
| id_ = std::move(other.id_); |
| data_ = std::move(other.data_); |
| } |
| ~ClientStruct() = default; |
| |
| // The methods below are convenience methods to have a similar API as protocol |
| // buffers for the test framework. This is NOT required for uses of client |
| // structs. |
| std::string id() const { return id_; } |
| std::string data() const { return data_; } |
| |
| std::string id_; |
| std::string data_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ClientStruct); |
| }; |
| |
| void CreateData(const std::string& key, |
| const std::string& data, |
| TestProto* proto) { |
| // Ensure the DB key, the id-field and data-field are all unique values. |
| proto->set_id(key + key); |
| proto->set_data(key + key + key); |
| } |
| |
| void CreateData(const std::string& key, |
| const std::string& data, |
| ClientStruct* as_struct) { |
| // Ensure the DB key, the id-field and data-field are all unique values. |
| as_struct->id_ = key + key; |
| as_struct->data_ = key + key + key; |
| } |
| |
| void DataToProto(ClientStruct* data, TestProto* proto) { |
| proto->mutable_id()->swap(data->id_); |
| proto->mutable_data()->swap(data->data_); |
| } |
| |
| void ProtoToData(TestProto* proto, ClientStruct* data) { |
| proto->mutable_id()->swap(data->id_); |
| proto->mutable_data()->swap(data->data_); |
| } |
| |
| } // namespace |
| |
| // Class used to shortcut the Init method so it returns a specified InitStatus. |
| class TestSharedProtoDatabase : public SharedProtoDatabase { |
| public: |
| TestSharedProtoDatabase(const std::string& client_db_id, |
| const base::FilePath& db_dir, |
| Enums::InitStatus use_status) |
| : SharedProtoDatabase::SharedProtoDatabase(client_db_id, db_dir) { |
| use_status_ = use_status; |
| } |
| |
| void Init( |
| bool create_if_missing, |
| const std::string& client_db_id, |
| SharedClientInitCallback callback, |
| scoped_refptr<base::SequencedTaskRunner> callback_task_runner) override { |
| init_status_ = use_status_; |
| |
| CheckCorruptionAndRunInitCallback(client_db_id, std::move(callback), |
| std::move(callback_task_runner), |
| use_status_); |
| } |
| |
| private: |
| ~TestSharedProtoDatabase() override {} |
| |
| Enums::InitStatus use_status_; |
| }; |
| |
| class TestSharedProtoDatabaseClient : public SharedProtoDatabaseClient { |
| public: |
| using SharedProtoDatabaseClient::set_migration_status; |
| using SharedProtoDatabaseClient::SharedProtoDatabaseClient; |
| |
| TestSharedProtoDatabaseClient(scoped_refptr<SharedProtoDatabase> shared_db) |
| : SharedProtoDatabaseClient::SharedProtoDatabaseClient( |
| nullptr, |
| ProtoDbType::TEST_DATABASE1, |
| shared_db) {} |
| |
| void UpdateClientInitMetadata( |
| SharedDBMetadataProto::MigrationStatus migration_status) override { |
| set_migration_status(migration_status); |
| } |
| }; |
| |
| class TestProtoDatabaseProvider : public ProtoDatabaseProvider { |
| public: |
| TestProtoDatabaseProvider(const base::FilePath& profile_dir) |
| : ProtoDatabaseProvider(profile_dir) {} |
| TestProtoDatabaseProvider(const base::FilePath& profile_dir, |
| const scoped_refptr<SharedProtoDatabase>& shared_db) |
| : ProtoDatabaseProvider(profile_dir) { |
| shared_db_ = shared_db; |
| } |
| |
| void GetSharedDBInstance( |
| ProtoDatabaseProvider::GetSharedDBInstanceCallback callback, |
| scoped_refptr<base::SequencedTaskRunner> callback_task_runner) override { |
| callback_task_runner->PostTask( |
| FROM_HERE, base::BindOnce(std::move(callback), shared_db_)); |
| } |
| |
| private: |
| scoped_refptr<SharedProtoDatabase> shared_db_; |
| }; |
| |
| class TestSharedProtoDatabaseProvider : public SharedProtoDatabaseProvider { |
| public: |
| TestSharedProtoDatabaseProvider( |
| const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, |
| base::WeakPtr<ProtoDatabaseProvider> provider_weak_ptr) |
| : SharedProtoDatabaseProvider(std::move(client_task_runner), |
| std::move(provider_weak_ptr)) {} |
| }; |
| |
| template <typename T> |
| class ProtoDatabaseImplTest : public testing::Test { |
| public: |
| void SetUp() override { |
| temp_dir_ = std::make_unique<base::ScopedTempDir>(); |
| ASSERT_TRUE(temp_dir_->CreateUniqueTempDir()); |
| shared_db_temp_dir_ = std::make_unique<base::ScopedTempDir>(); |
| ASSERT_TRUE(shared_db_temp_dir_->CreateUniqueTempDir()); |
| test_thread_ = std::make_unique<base::Thread>("test_thread"); |
| ASSERT_TRUE(test_thread_->Start()); |
| shared_db_ = base::WrapRefCounted(new SharedProtoDatabase( |
| kDefaultClientName, shared_db_temp_dir_->GetPath())); |
| } |
| |
| void SetUpExperimentParams(std::map<std::string, std::string> params) { |
| scoped_feature_list_.InitAndEnableFeatureWithParameters( |
| kProtoDBSharedMigration, params); |
| } |
| |
| std::unique_ptr<ProtoDatabaseImpl<TestProto, T>> CreateDBImpl( |
| ProtoDbType db_type, |
| const base::FilePath& db_dir, |
| const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| std::unique_ptr<SharedProtoDatabaseProvider> db_provider) { |
| return std::make_unique<ProtoDatabaseImpl<TestProto, T>>( |
| db_type, db_dir, task_runner, std::move(db_provider)); |
| } |
| |
| void GetDbAndWait(ProtoDatabaseProvider* db_provider, ProtoDbType db_type) { |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| auto db = db_provider->GetDB<TestProto, T>(db_type, temp_dir.GetPath(), |
| GetTestThreadTaskRunner()); |
| |
| base::RunLoop run_init; |
| |
| // Initialize a database, it should succeed. |
| db->Init(base::BindOnce( |
| [](base::OnceClosure closure, Enums::InitStatus status) { |
| std::move(closure).Run(); |
| EXPECT_TRUE(status == Enums::InitStatus::kOK); |
| }, |
| run_init.QuitClosure())); |
| |
| run_init.Run(); |
| } |
| |
| std::unique_ptr<TestProtoDatabaseProvider> CreateProviderNoSharedDB() { |
| // Create a test provider with a test shared DB that will return invalid |
| // operation when a client is requested, level_db returns invalid operation |
| // when a database doesn't exist. |
| return CreateProviderWithTestSharedDB(Enums::InitStatus::kInvalidOperation); |
| } |
| |
| std::unique_ptr<TestProtoDatabaseProvider> CreateProviderWithSharedDB() { |
| return std::make_unique<TestProtoDatabaseProvider>( |
| shared_db_temp_dir_->GetPath(), shared_db_); |
| } |
| |
| std::unique_ptr<TestProtoDatabaseProvider> CreateProviderWithTestSharedDB( |
| Enums::InitStatus shared_client_init_status) { |
| auto test_shared_db = base::WrapRefCounted(new TestSharedProtoDatabase( |
| kDefaultClientName, shared_db_temp_dir_->GetPath(), |
| shared_client_init_status)); |
| |
| return std::make_unique<TestProtoDatabaseProvider>( |
| shared_db_temp_dir_->GetPath(), test_shared_db); |
| } |
| |
| std::unique_ptr<TestSharedProtoDatabaseProvider> CreateSharedProvider( |
| TestProtoDatabaseProvider* db_provider) { |
| return std::make_unique<TestSharedProtoDatabaseProvider>( |
| base::SequencedTaskRunnerHandle::Get(), |
| db_provider->weak_factory_.GetWeakPtr()); |
| } |
| |
| // Uses ProtoDatabaseImpl's 3 parameter Init to bypass the check that gets |
| // |use_shared_db|'s value. |
| void InitDBImpl(ProtoDatabaseImpl<TestProto, T>* db_impl, |
| const std::string& client_name, |
| bool use_shared_db, |
| Callbacks::InitStatusCallback callback) { |
| db_impl->InitInternal(client_name, CreateSimpleOptions(), use_shared_db, |
| std::move(callback)); |
| } |
| |
| void InitDBImplAndWait(ProtoDatabaseImpl<TestProto, T>* db_impl, |
| const std::string& client_name, |
| bool use_shared_db, |
| Enums::InitStatus expect_status) { |
| base::RunLoop init_loop; |
| InitDBImpl( |
| db_impl, client_name, use_shared_db, |
| base::BindOnce( |
| [](base::OnceClosure closure, Enums::InitStatus expect_status, |
| Enums::InitStatus status) { |
| ASSERT_EQ(status, expect_status); |
| std::move(closure).Run(); |
| }, |
| init_loop.QuitClosure(), expect_status)); |
| init_loop.Run(); |
| } |
| |
| std::unique_ptr<TestSharedProtoDatabaseClient> GetSharedClient() { |
| return std::make_unique<TestSharedProtoDatabaseClient>(shared_db_); |
| } |
| |
| void CallOnGetSharedDBClientAndWait( |
| std::unique_ptr<UniqueProtoDatabase> unique_db, |
| Enums::InitStatus unique_db_status, |
| bool use_shared_db, |
| std::unique_ptr<SharedProtoDatabaseClient> shared_db_client, |
| Enums::InitStatus shared_db_status, |
| Enums::InitStatus expect_status) { |
| base::RunLoop init_loop; |
| |
| scoped_refptr<ProtoDatabaseSelector> selector(new ProtoDatabaseSelector( |
| ProtoDbType::TEST_DATABASE1, GetTestThreadTaskRunner(), nullptr)); |
| |
| selector->OnGetSharedDBClient( |
| std::move(unique_db), unique_db_status, use_shared_db, |
| base::BindOnce( |
| [](base::OnceClosure closure, Enums::InitStatus expect_status, |
| Enums::InitStatus status) { |
| ASSERT_EQ(status, expect_status); |
| std::move(closure).Run(); |
| }, |
| init_loop.QuitClosure(), expect_status), |
| std::move(shared_db_client), shared_db_status); |
| |
| init_loop.Run(); |
| |
| // If the process succeeded then check that the selector has a database set. |
| if (expect_status == Enums::InitStatus::kOK) { |
| ASSERT_NE(selector->db_, nullptr); |
| } |
| } |
| |
| // Just uses each entry's key to fill out the id/data fields in TestProto as |
| // well. |
| void AddDataToDBImpl(ProtoDatabaseImpl<TestProto, T>* db_impl, |
| std::vector<std::string>* entry_keys) { |
| auto data_set = std::make_unique<std::vector<std::pair<std::string, T>>>(); |
| for (const auto& key : *entry_keys) { |
| T data; |
| CreateData(key, key, &data); |
| data_set->emplace_back(key, std::move(data)); |
| } |
| |
| base::RunLoop data_loop; |
| db_impl->UpdateEntries(std::move(data_set), |
| std::make_unique<std::vector<std::string>>(), |
| base::BindOnce( |
| [](base::OnceClosure closure, bool success) { |
| ASSERT_TRUE(success); |
| std::move(closure).Run(); |
| }, |
| data_loop.QuitClosure())); |
| data_loop.Run(); |
| } |
| |
| void VerifyDataInDBImpl(ProtoDatabaseImpl<TestProto, T>* db_impl, |
| std::vector<std::string>* entry_keys) { |
| base::RunLoop load_loop; |
| db_impl->LoadKeysAndEntries(base::BindOnce( |
| [](base::OnceClosure closure, std::vector<std::string>* entry_keys, |
| bool success, |
| std::unique_ptr<std::map<std::string, T>> keys_entries) { |
| ASSERT_TRUE(success); |
| ASSERT_EQ(entry_keys->size(), keys_entries->size()); |
| |
| for (const auto& key : *entry_keys) { |
| auto search = keys_entries->find(key); |
| ASSERT_TRUE(search != keys_entries->end()); |
| // CreateData above uses double key as id and triple key as data. |
| ASSERT_EQ(key + key, search->second.id()); |
| ASSERT_EQ(key + key + key, search->second.data()); |
| } |
| std::move(closure).Run(); |
| }, |
| load_loop.QuitClosure(), entry_keys)); |
| load_loop.Run(); |
| } |
| |
| void UpdateClientMetadata( |
| SharedDBMetadataProto::MigrationStatus migration_status) { |
| base::RunLoop init_wait; |
| auto client = shared_db_->GetClientForTesting( |
| ProtoDbType::TEST_DATABASE1, /*create_if_missing=*/true, |
| base::BindOnce( |
| [](base::OnceClosure closure, Enums::InitStatus status, |
| SharedDBMetadataProto::MigrationStatus migration_status) { |
| EXPECT_EQ(Enums::kOK, status); |
| std::move(closure).Run(); |
| }, |
| init_wait.QuitClosure())); |
| init_wait.Run(); |
| |
| base::RunLoop wait_loop; |
| shared_db_->UpdateClientMetadataAsync( |
| client->client_db_id(), migration_status, |
| base::BindOnce( |
| [](base::OnceClosure closure, bool success) { |
| EXPECT_TRUE(success); |
| std::move(closure).Run(); |
| }, |
| wait_loop.QuitClosure())); |
| wait_loop.Run(); |
| } |
| |
| SharedDBMetadataProto::MigrationStatus GetClientMigrationStatus() { |
| SharedDBMetadataProto::MigrationStatus migration_status; |
| base::RunLoop init_wait; |
| auto client = shared_db_->GetClientForTesting( |
| ProtoDbType::TEST_DATABASE1, /*create_if_missing=*/true, |
| base::BindOnce( |
| [](base::OnceClosure closure, |
| SharedDBMetadataProto::MigrationStatus* output, |
| Enums::InitStatus status, |
| SharedDBMetadataProto::MigrationStatus migration_status) { |
| EXPECT_EQ(Enums::kOK, status); |
| *output = migration_status; |
| std::move(closure).Run(); |
| }, |
| init_wait.QuitClosure(), &migration_status)); |
| init_wait.Run(); |
| |
| return migration_status; |
| } |
| |
| scoped_refptr<base::SequencedTaskRunner> GetTestThreadTaskRunner() { |
| return test_thread_->task_runner(); |
| } |
| |
| base::FilePath temp_dir() { return temp_dir_->GetPath(); } |
| |
| private: |
| std::unique_ptr<base::ScopedTempDir> temp_dir_; |
| std::unique_ptr<base::ScopedTempDir> shared_db_temp_dir_; |
| base::test::TaskEnvironment task_environment_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| // Shared database. |
| std::unique_ptr<base::Thread> test_thread_; |
| std::unique_ptr<base::Thread> shared_db_thread_; |
| scoped_refptr<SharedProtoDatabase> shared_db_; |
| }; |
| |
| using ProtoDatabaseImplTestConfig = testing::Types<TestProto, ClientStruct>; |
| TYPED_TEST_SUITE(ProtoDatabaseImplTest, ProtoDatabaseImplTestConfig); |
| |
| TYPED_TEST(ProtoDatabaseImplTest, FailsBothDatabases) { |
| auto db_provider = this->CreateProviderNoSharedDB(); |
| auto shared_db_provider = this->CreateSharedProvider(db_provider.get()); |
| auto db_impl = |
| this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider.get())); |
| this->InitDBImplAndWait(db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kError); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) { |
| auto unique_db = |
| std::make_unique<UniqueProtoDatabase>(this->GetTestThreadTaskRunner()); |
| |
| // If a shared DB is requested, and it fails to open for any reason then we |
| // return a failure, the shared DB is opened using create_if_missing = true, |
| // so we shouldn't get a missing DB. |
| this->CallOnGetSharedDBClientAndWait( |
| std::move(unique_db), // Unique DB opens fine. |
| Enums::InitStatus::kOK, |
| true, // We should be using a shared DB. |
| nullptr, // Shared DB failed to open. |
| Enums::InitStatus::kError, // Shared DB had an IO error. |
| Enums::InitStatus::kError); // Then the DB impl should return an error. |
| |
| this->CallOnGetSharedDBClientAndWait( |
| std::move(unique_db), // Unique DB opens fine. |
| Enums::InitStatus::kOK, |
| true, // We should be using a shared DB. |
| nullptr, // Shared DB failed to open. |
| Enums::InitStatus::kInvalidOperation, // Shared DB doesn't exist. |
| Enums::InitStatus::kError); // Then the DB impl should return an error. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, |
| SucceedsWithShared_UseShared_HasSharedDB_UniqueNotFound) { |
| auto shared_db_client = this->GetSharedClient(); |
| |
| // Migration status is not attempted. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED); |
| |
| // If we request a shared DB, the unique DB fails to open because it doesn't |
| // exist and a migration hasn't been attempted then we return the shared DB |
| // and we set the migration status to migrated to shared. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kInvalidOperation, // Unique DB doesn't exist. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kOK); // Then the DB impl should return the shared DB. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, |
| Fails_UseShared_HasSharedDB_UniqueHadIOError) { |
| auto shared_db_client = this->GetSharedClient(); |
| |
| // Migration status is not attempted. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED); |
| |
| // If we request a shared DB, the unique DB fails to open because of an IO |
| // error and a migration hasn't been attempted then we throw an error, as the |
| // unique DB could contain data yet to be migrated. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kError, // Unique DB had an IO error. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kError); // Then the DB impl should return an error. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, |
| SuccedsWithShared_UseShared_HasSharedDB_DataWasMigratedToShared) { |
| auto shared_db_client = this->GetSharedClient(); |
| |
| // Database has been migrated to Shared. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL); |
| |
| // If we request a shared DB, the unique DB fails to open for any reason and |
| // the data has been migrated to the shared DB then we can return the shared |
| // DB safely. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kInvalidOperation, // Unique DB doesn't exist. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kOK); // Then the DB impl should use the shared DB. |
| |
| shared_db_client = this->GetSharedClient(); |
| |
| // Data has been migrated to Shared, Unique DB still exists and should be |
| // removed. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED); |
| |
| // This second scenario occurs when the unique DB is marked to be deleted, but |
| // it fails to open, we should also return the unique DB without throwing an |
| // error. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kError, // Unique DB had an IO error. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kOK); // Then the DB impl should use the shared DB. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, |
| Fails_UseShared_HasSharedDB_DataWasMigratedToUnique) { |
| auto shared_db_client = this->GetSharedClient(); |
| |
| // Database has been migrated to Unique. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL); |
| |
| // If we request a shared DB, the unique DB fails to open for any reason and |
| // the data has been migrated to the unique DB then we throw an error, as the |
| // unique database may contain data. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kInvalidOperation, // Unique DB doesn't exist. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kError); // Then the DB impl should throw an error. |
| |
| shared_db_client = this->GetSharedClient(); |
| |
| // Data has been migrated to Unique, but data still exists in Shared DB that |
| // should be removed. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED); |
| |
| // This second scenario occurs when the Shared DB still contains data, we |
| // should still throw an error. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kError, // Unique DB had an IO error. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kError); // Then the DB impl should throw an error. |
| } |
| |
| TYPED_TEST( |
| ProtoDatabaseImplTest, |
| SucceedsWithShared_DontUseShared_HasSharedDB_DataWasMigratedToShared) { |
| auto shared_db_client = this->GetSharedClient(); |
| |
| // Database has been migrated to Shared. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL); |
| |
| // If we request a unique DB, the unique DB fails to open for any reason and |
| // the data has been migrated to the shared DB then we use the Shared DB. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kInvalidOperation, // Unique DB doesn't exist. |
| false, // We should be using a unique DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kOK); // Then the DB impl should use the shared DB. |
| |
| shared_db_client = this->GetSharedClient(); |
| |
| // Data has been migrated to Shared, but the Unique DB still exists and needs |
| // to be deleted. |
| shared_db_client->set_migration_status( |
| SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED); |
| |
| // This second scenario occurs when the unique database is marked to be |
| // deleted, we should still use the shared DB. |
| this->CallOnGetSharedDBClientAndWait( |
| nullptr, // Unique DB fails to open. |
| Enums::InitStatus::kError, // Unique DB had an IO error. |
| true, // We should be using a shared DB. |
| std::move(shared_db_client), // Shared DB opens fine. |
| Enums::InitStatus::kOK, |
| Enums::InitStatus::kOK); // Then the DB impl should use the shared DB. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, |
| SucceedsWithUnique_DontUseShared_SharedDBNotFound) { |
| auto unique_db = |
| std::make_unique<UniqueProtoDatabase>(this->GetTestThreadTaskRunner()); |
| |
| // If the shared DB client fails to open because it doesn't exist then we can |
| // return the unique DB safely. |
| this->CallOnGetSharedDBClientAndWait( |
| std::move(unique_db), // Unique DB opens fine. |
| Enums::InitStatus::kOK, |
| false, // We should be using a unique DB. |
| nullptr, // Shared DB failed to open. |
| Enums::InitStatus::kInvalidOperation, // Shared DB doesn't exist. |
| Enums::InitStatus::kOK); // Then the DB impl should return the unique DB. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Fails_DontUseShared_SharedDBFailed) { |
| auto unique_db = |
| std::make_unique<UniqueProtoDatabase>(this->GetTestThreadTaskRunner()); |
| |
| // If the shared DB client fails to open because of an IO error then we |
| // shouldn't return a database, as the shared DB could contain data not yet |
| // migrated. |
| this->CallOnGetSharedDBClientAndWait( |
| std::move(unique_db), // Unique DB opens fine. |
| Enums::InitStatus::kOK, |
| false, // We should be using a unique DB. |
| nullptr, // Shared DB failed to open. |
| Enums::InitStatus::kError, // Shared DB had an IO error. |
| Enums::InitStatus::kError); // Then the DB impl should return an error. |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB_NoUniqueDB) { |
| auto db_provider = this->CreateProviderNoSharedDB(); |
| auto db_impl = |
| this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider.get())); |
| this->InitDBImplAndWait(db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kError); |
| } |
| |
| // Migration tests: |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_EmptyDBs_UniqueToShared) { |
| // First we create a unique DB so our second pass has a unique DB available. |
| auto db_provider_noshared = this->CreateProviderNoSharedDB(); |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_noshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| // Kill the DB impl so it doesn't have a lock on the DB anymore. |
| unique_db_impl.reset(); |
| // DB impl posts a task to destroy its database, so we wait for that task to |
| // complete. |
| base::RunLoop destroy_loop; |
| this->GetTestThreadTaskRunner()->PostTask(FROM_HERE, |
| destroy_loop.QuitClosure()); |
| destroy_loop.Run(); |
| |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_EmptyDBs_SharedToUnique) { |
| // First we create a unique DB so our second pass has a unique DB available. |
| auto db_provider = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = |
| this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| |
| // As the unique DB doesn't exist then the DB impl sets the migration status |
| // to migrated to shared. |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| |
| auto unique_db_impl = |
| this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_UniqueToShared) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| |
| // First we create a unique DB so our second pass has a unique DB available. |
| auto db_provider_noshared = this->CreateProviderNoSharedDB(); |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_noshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(unique_db_impl.get(), data_set.get()); |
| // Kill the DB impl so it doesn't have a lock on the DB anymore. |
| unique_db_impl.reset(); |
| // DB impl posts a task to destroy its database, so we wait for that task to |
| // complete. |
| base::RunLoop destroy_loop; |
| this->GetTestThreadTaskRunner()->PostTask(FROM_HERE, |
| destroy_loop.QuitClosure()); |
| destroy_loop.Run(); |
| |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| this->VerifyDataInDBImpl(shared_db_impl.get(), data_set.get()); |
| |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_SharedToUnique) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| |
| // First we create a shared DB so our second pass has a shared DB available. |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(shared_db_impl.get(), data_set.get()); |
| |
| // As the unique DB doesn't exist then the DB impl sets the migration status |
| // to migrated to shared. |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| this->VerifyDataInDBImpl(unique_db_impl.get(), data_set.get()); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_UniqueToShared_UniqueObsolete) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| |
| // First we create a unique DB so our second pass has a unique DB available. |
| auto db_provider_noshared = this->CreateProviderNoSharedDB(); |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_noshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(unique_db_impl.get(), data_set.get()); |
| // Kill the DB impl so it doesn't have a lock on the DB anymore. |
| unique_db_impl.reset(); |
| |
| this->UpdateClientMetadata( |
| SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED); |
| |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| |
| // Unique DB should be deleted in migration. So, shared DB should be clean. |
| data_set->clear(); |
| this->VerifyDataInDBImpl(shared_db_impl.get(), data_set.get()); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_UniqueToShared_SharedObsolete) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| |
| // First we create a shared DB so our second pass has a shared DB available. |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(shared_db_impl.get(), data_set.get()); |
| |
| // As there's no unique DB, the DB impl is going to set the state to migrated |
| // to shared. |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| |
| // Force create an unique DB, which was deleted by migration. |
| auto db_provider_noshared = this->CreateProviderNoSharedDB(); |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_noshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| unique_db_impl.reset(); |
| |
| this->UpdateClientMetadata( |
| SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED); |
| |
| shared_db_impl.reset(); |
| db_provider_withshared = this->CreateProviderWithSharedDB(); |
| |
| auto shared_db_impl1 = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl1.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| |
| // Shared DB should be deleted in migration. So, shared DB should be clean. |
| data_set->clear(); |
| this->VerifyDataInDBImpl(shared_db_impl1.get(), data_set.get()); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_SharedToUnique_SharedObsolete) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| |
| // First we create a shared DB so our second pass has a shared DB available. |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(shared_db_impl.get(), data_set.get()); |
| |
| // As there's no Unique DB, the DB impl changes the migration status to |
| // migrated to shared. |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| |
| this->UpdateClientMetadata( |
| SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED); |
| |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| |
| // Shared DB should be deleted in migration. So, unique DB should be clean. |
| data_set->clear(); |
| this->VerifyDataInDBImpl(unique_db_impl.get(), data_set.get()); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, Migration_SharedToUnique_UniqueObsolete) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| |
| // First we create a shared DB so our second pass has a shared DB available. |
| auto db_provider_noshared = this->CreateProviderNoSharedDB(); |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_noshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(unique_db_impl.get(), data_set.get()); |
| |
| this->UpdateClientMetadata( |
| SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED); |
| |
| unique_db_impl.reset(); |
| |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| |
| // Unique DB should be deleted in migration. So, unique DB should be clean. |
| data_set->clear(); |
| this->VerifyDataInDBImpl(shared_db_impl.get(), data_set.get()); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, InMemoryDatabaseDoesNoMigration) { |
| auto data_set = std::make_unique<std::vector<std::string>>(); |
| data_set->emplace_back("entry1"); |
| data_set->emplace_back("entry2"); |
| data_set->emplace_back("entry3"); |
| auto db_provider_withshared = this->CreateProviderWithSharedDB(); |
| |
| // First we create a shared DB so our second pass has a shared DB available. |
| auto shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| this->AddDataToDBImpl(shared_db_impl.get(), data_set.get()); |
| |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| shared_db_impl.reset(); |
| |
| // Open in memory database (unique db). This should not migrate the data from |
| // shared db. |
| auto unique_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, base::FilePath(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false, |
| Enums::InitStatus::kOK); |
| |
| auto empty_data = std::make_unique<std::vector<std::string>>(); |
| this->VerifyDataInDBImpl(unique_db_impl.get(), empty_data.get()); |
| unique_db_impl.reset(); |
| |
| // Open shared db again to check the old data is present. |
| shared_db_impl = this->CreateDBImpl( |
| ProtoDbType::TEST_DATABASE1, this->temp_dir(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider_withshared.get())); |
| this->InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kOK); |
| this->VerifyDataInDBImpl(shared_db_impl.get(), data_set.get()); |
| EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, |
| this->GetClientMigrationStatus()); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, DestroyShouldWorkWhenUniqueInitFailed) { |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| auto db_provider = this->CreateProviderNoSharedDB(); |
| auto shared_db_provider = this->CreateSharedProvider(db_provider.get()); |
| auto db_impl = |
| this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir.GetPath(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider.get())); |
| |
| // Try to initialize a db and fail. |
| this->InitDBImplAndWait(db_impl.get(), kDefaultClientName, true, |
| Enums::InitStatus::kError); |
| |
| base::RunLoop run_destroy; |
| |
| // Call destroy on the db, it should destroy the db directory. |
| db_impl->Destroy(base::BindOnce( |
| [](base::OnceClosure closure, bool success) { |
| std::move(closure).Run(); |
| EXPECT_TRUE(success); |
| }, |
| run_destroy.QuitClosure())); |
| |
| run_destroy.Run(); |
| |
| // Verify the db is actually destroyed. |
| EXPECT_FALSE(base::PathExists(temp_dir.GetPath())); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, InitWithOptions) { |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| EXPECT_TRUE(base::IsDirectoryEmpty(temp_dir.GetPath())); |
| |
| auto db_provider = this->CreateProviderNoSharedDB(); |
| auto db_impl = |
| this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir.GetPath(), |
| this->GetTestThreadTaskRunner(), |
| this->CreateSharedProvider(db_provider.get())); |
| |
| base::RunLoop run_init; |
| auto options = CreateSimpleOptions(); |
| options.create_if_missing = false; |
| |
| // Initialize database with unique DB arguments, it should fail because we |
| // specified create_if_missing = false and there's no shared DB. |
| db_impl->Init( |
| options, |
| base::BindOnce( |
| [](base::OnceClosure closure, Enums::InitStatus expect_status, |
| Enums::InitStatus status) { |
| ASSERT_EQ(status, expect_status); |
| std::move(closure).Run(); |
| }, |
| run_init.QuitClosure(), Enums::InitStatus::kError)); |
| |
| run_init.Run(); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, InitUniqueTwiceShouldSucceed) { |
| base::ScopedTempDir temp_dir_profile; |
| ASSERT_TRUE(temp_dir_profile.CreateUniqueTempDir()); |
| |
| // Both databases will be opened as unique. |
| auto experiment_params = std::map<std::string, std::string>{ |
| {"migrate_TestDatabase1", "false"}, {"migrate_TestDatabase2", "false"}}; |
| this->SetUpExperimentParams(experiment_params); |
| |
| auto db_provider = |
| std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath()); |
| |
| // Initialize a database, it should succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1); |
| // Initialize a second database, it should also succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, InitUniqueThenSharedShouldSucceed) { |
| base::ScopedTempDir temp_dir_profile; |
| ASSERT_TRUE(temp_dir_profile.CreateUniqueTempDir()); |
| |
| // First database will open as unique, second DB will open as shared. |
| auto experiment_params = std::map<std::string, std::string>{ |
| {"migrate_TestDatabase1", "false"}, {"migrate_TestDatabase2", "true"}}; |
| this->SetUpExperimentParams(experiment_params); |
| |
| auto db_provider = |
| std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath()); |
| |
| // Initialize a database, it should succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1); |
| // Initialize a second database, it should also succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, InitSharedThenUniqueShouldSucceed) { |
| base::ScopedTempDir temp_dir_profile; |
| ASSERT_TRUE(temp_dir_profile.CreateUniqueTempDir()); |
| |
| // First database will open as shared, second DB will open as unique. |
| auto experiment_params = std::map<std::string, std::string>{ |
| {"migrate_TestDatabase1", "true"}, {"migrate_TestDatabase2", "false"}}; |
| this->SetUpExperimentParams(experiment_params); |
| |
| auto db_provider = |
| std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath()); |
| |
| // Initialize a database, it should succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1); |
| // Initialize a second database, it should also succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2); |
| } |
| |
| TYPED_TEST(ProtoDatabaseImplTest, InitSharedTwiceShouldSucceed) { |
| base::ScopedTempDir temp_dir_profile; |
| ASSERT_TRUE(temp_dir_profile.CreateUniqueTempDir()); |
| |
| // Both databases will open as shared. |
| auto experiment_params = std::map<std::string, std::string>{ |
| {"migrate_TestDatabase1", "true"}, {"migrate_TestDatabase2", "true"}}; |
| this->SetUpExperimentParams(experiment_params); |
| |
| auto db_provider = |
| std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath()); |
| |
| // Initialize a database, it should succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1); |
| // Initialize a second database, it should also succeed. |
| this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2); |
| } |
| |
| } // namespace leveldb_proto |