blob: 5a39f68cb36f3ba45199bf048fd7a02a3b4bd984 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/session_proto_db/session_proto_db.h"
#include <map>
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/task/thread_pool.h"
#include "components/leveldb_proto/testing/fake_db.h"
#include "components/session_proto_db/session_proto_db_test_proto.pb.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
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;
}
session_proto_db::SessionProtoDBTestProto BuildTestProto(const char* key,
const int32_t value) {
session_proto_db::SessionProtoDBTestProto proto;
proto.set_key(key);
proto.set_b(value);
return proto;
}
const char kMockKeyA[] = "A_key";
const char kMockKeyPrefixA[] = "A";
const std::vector<uint8_t> kMockValueArrayA = {0xfa, 0x5b, 0x4c, 0x12};
const persisted_state_db::PersistedStateContentProto kMockValueA =
BuildProto(kMockKeyA, kMockValueArrayA);
const std::vector<
SessionProtoDB<persisted_state_db::PersistedStateContentProto>::KeyAndValue>
kExpectedA = {{kMockKeyA, kMockValueA}};
const char kMockKeyB[] = "B_key";
const std::vector<uint8_t> kMockValueArrayB = {0x3c, 0x9f, 0x5e, 0x69};
const persisted_state_db::PersistedStateContentProto kMockValueB =
BuildProto(kMockKeyB, kMockValueArrayB);
const std::vector<
SessionProtoDB<persisted_state_db::PersistedStateContentProto>::KeyAndValue>
kExpectedB = {{kMockKeyB, kMockValueB}};
const std::vector<
SessionProtoDB<persisted_state_db::PersistedStateContentProto>::KeyAndValue>
kExpectedAB = {{kMockKeyA, kMockValueA}, {kMockKeyB, kMockValueB}};
const std::vector<
SessionProtoDB<persisted_state_db::PersistedStateContentProto>::KeyAndValue>
kEmptyExpected = {};
const session_proto_db::SessionProtoDBTestProto kTestProto =
BuildTestProto(kMockKeyA, 42);
const std::vector<
SessionProtoDB<session_proto_db::SessionProtoDBTestProto>::KeyAndValue>
kTestProtoExpected = {{kMockKeyA, kTestProto}};
const char kSPTDTab1Key[] = "1_SPTD";
const persisted_state_db::PersistedStateContentProto kSPTDTab1Value =
BuildProto(kSPTDTab1Key, {0x5b, 0x2c});
const char kSPTDTab2Key[] = "2_SPTD";
const persisted_state_db::PersistedStateContentProto kSPTDTab2Value =
BuildProto(kSPTDTab2Key, {0xfe, 0xab});
const char kSPTDTab3Key[] = "3_SPTD";
const persisted_state_db::PersistedStateContentProto kSPTDTab3Value =
BuildProto(kSPTDTab3Key, {0x0a, 0x1b});
const char kMPTDTab1Key[] = "1_MPTD";
const persisted_state_db::PersistedStateContentProto kMPTDTab1Value =
BuildProto(kMPTDTab1Key, {0xaa, 0x3b});
const char kMatchingDataIdForMaintenance[] = "SPTD";
const char kNonMatchingDataIdForMaintenance[] = "asdf";
} // namespace
class SessionProtoDBTest : public testing::Test {
public:
SessionProtoDBTest() = default;
SessionProtoDBTest(const SessionProtoDBTest&) = delete;
SessionProtoDBTest& operator=(const SessionProtoDBTest&) = delete;
// The following methods are specific to the database containing
// persisted_state_db::PersistedStateContentProto. There is one test which
// contains session_proto_db::SessionProtoDBTestProto to test the use case
// of multiple SessionProtoDB databases running at the same time.
// Initialize the test database
void InitPersistedStateDB() {
InitPersistedStateDBWithoutCallback();
MockInitCallbackPersistedStateDB(content_db_,
leveldb_proto::Enums::InitStatus::kOK);
}
void InitPersistedStateDBWithoutCallback() {
auto storage_db = std::make_unique<leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>>(&content_db_storage_);
content_db_ = storage_db.get();
persisted_state_db_ = base::WrapUnique(
new SessionProtoDB<persisted_state_db::PersistedStateContentProto>(
std::move(storage_db),
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}),
content::GetUIThreadTaskRunner({})));
}
void MockInitCallbackPersistedStateDB(
leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db,
leveldb_proto::Enums::InitStatus status) {
storage_db->InitStatusCallback(status);
RunUntilIdle();
}
void MockInsertCallbackPersistedStateDB(
leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db,
bool result) {
storage_db->UpdateCallback(result);
RunUntilIdle();
}
void MockLoadCallbackPersistedStateDB(
leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db,
bool res) {
storage_db->LoadCallback(res);
RunUntilIdle();
}
void MockDeleteCallbackPersistedStateDB(
leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>* storage_db,
bool res) {
storage_db->UpdateCallback(res);
RunUntilIdle();
}
void GetEvaluationPersistedStateDB(
base::OnceClosure closure,
std::vector<SessionProtoDB<
persisted_state_db::PersistedStateContentProto>::KeyAndValue>
expected,
bool result,
std::vector<SessionProtoDB<
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();
}
void GetEmptyEvaluationPersistedStateDB(
base::OnceClosure closure,
bool result,
std::vector<SessionProtoDB<
persisted_state_db::PersistedStateContentProto>::KeyAndValue> found) {
EXPECT_TRUE(result);
EXPECT_EQ(found.size(), 0U);
std::move(closure).Run();
}
// Common to both databases
void OperationEvaluation(base::OnceClosure closure,
bool expected_success,
bool actual_success) {
EXPECT_EQ(expected_success, actual_success);
std::move(closure).Run();
}
// Wait for all tasks to be cleared off the queue
void RunUntilIdle() { task_environment_.RunUntilIdle(); }
// Specific to session_proto_db::SessionProtoDBTestProto database
void InitTestProtoDB() {
auto storage_db = std::make_unique<
leveldb_proto::test::FakeDB<session_proto_db::SessionProtoDBTestProto>>(
&test_content_db_storage_);
test_content_db_ = storage_db.get();
test_proto_db_ = base::WrapUnique(
new SessionProtoDB<session_proto_db::SessionProtoDBTestProto>(
std::move(storage_db),
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}),
content::GetUIThreadTaskRunner({})));
}
void GetTestEvaluationTestProtoDB(
base::OnceClosure closure,
std::vector<SessionProtoDB<
session_proto_db::SessionProtoDBTestProto>::KeyAndValue> expected,
bool result,
std::vector<SessionProtoDB<
session_proto_db::SessionProtoDBTestProto>::KeyAndValue> found) {
for (size_t i = 0; i < expected.size(); i++) {
EXPECT_EQ(found[i].first, expected[i].first);
EXPECT_EQ(found[i].second.b(), expected[i].second.b());
}
std::move(closure).Run();
}
void InsertContentAndVerify(
const std::string& key,
const persisted_state_db::PersistedStateContentProto& value) {
InsertContent(key, value);
VerifyContent(key, value);
}
void InsertContent(
const std::string& key,
const persisted_state_db::PersistedStateContentProto& value) {
base::RunLoop wait_for_insert;
persisted_state_db()->InsertContent(
key, value,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), wait_for_insert.QuitClosure(),
true));
MockInsertCallbackPersistedStateDB(content_db(), true);
wait_for_insert.Run();
}
void VerifyContent(
const std::string& key,
const persisted_state_db::PersistedStateContentProto& value) {
base::RunLoop wait_for_load;
persisted_state_db()->LoadContentWithPrefix(
key,
base::BindOnce(
&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), wait_for_load.QuitClosure(),
std::vector<SessionProtoDB<
persisted_state_db::PersistedStateContentProto>::KeyAndValue>(
{{key, value}})));
MockLoadCallbackPersistedStateDB(content_db(), true);
wait_for_load.Run();
}
void VerifyContentEmpty(const std::string& key) {
base::RunLoop wait_for_load;
persisted_state_db()->LoadContentWithPrefix(
key,
base::BindOnce(&SessionProtoDBTest::GetEmptyEvaluationPersistedStateDB,
base::Unretained(this), wait_for_load.QuitClosure()));
MockLoadCallbackPersistedStateDB(content_db(), true);
wait_for_load.Run();
}
void PerformMaintenance(const std::vector<std::string>& keys_to_keep,
const std::string& data_id) {
base::RunLoop wait_for_maintenance;
persisted_state_db()->PerformMaintenance(
keys_to_keep, data_id,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this),
wait_for_maintenance.QuitClosure(), true));
MockLoadCallbackPersistedStateDB(content_db(), true);
MockInsertCallbackPersistedStateDB(content_db(), true);
wait_for_maintenance.Run();
}
// For persisted_state_db::PersistedStateContentProto database
SessionProtoDB<persisted_state_db::PersistedStateContentProto>*
persisted_state_db() {
return persisted_state_db_.get();
}
leveldb_proto::test::FakeDB<persisted_state_db::PersistedStateContentProto>*
content_db() {
return content_db_;
}
std::vector<base::OnceClosure>& deferred_operations() {
return persisted_state_db()->deferred_operations_;
}
bool InitStatusUnknown() { return persisted_state_db()->InitStatusUnknown(); }
bool FailedToInit() { return persisted_state_db()->FailedToInit(); }
std::map<std::string, persisted_state_db::PersistedStateContentProto>
content_db_storage_;
// For session_proto_db::SessionProtoDBTestProto database
SessionProtoDB<session_proto_db::SessionProtoDBTestProto>* test_proto_db() {
return test_proto_db_.get();
}
leveldb_proto::test::FakeDB<session_proto_db::SessionProtoDBTestProto>*
test_content_db() {
return test_content_db_;
}
std::map<std::string, session_proto_db::SessionProtoDBTestProto>
test_content_db_storage_;
protected:
raw_ptr<
leveldb_proto::test::FakeDB<session_proto_db::SessionProtoDBTestProto>>
test_content_db_;
private:
content::BrowserTaskEnvironment task_environment_;
// For persisted_state_db::PersistedStateContentProto database
raw_ptr<leveldb_proto::test::FakeDB<
persisted_state_db::PersistedStateContentProto>>
content_db_;
std::unique_ptr<
SessionProtoDB<persisted_state_db::PersistedStateContentProto>>
persisted_state_db_;
// For session_proto_db::SessionProtoDBTestProto database
std::unique_ptr<SessionProtoDB<session_proto_db::SessionProtoDBTestProto>>
test_proto_db_;
};
// Test an arbitrary proto - this ensures we can have two ProfilProtoDB
// databases running simultaneously.
TEST_F(SessionProtoDBTest, TestArbitraryProto) {
InitTestProtoDB();
test_content_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
RunUntilIdle();
base::RunLoop run_loop[2];
test_proto_db()->InsertContent(
kMockKeyA, kTestProto,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
test_content_db()->UpdateCallback(true);
RunUntilIdle();
run_loop[0].Run();
test_proto_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetTestEvaluationTestProtoDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kTestProtoExpected));
test_content_db()->LoadCallback(true);
RunUntilIdle();
run_loop[1].Run();
}
TEST_F(SessionProtoDBTest, TestInit) {
InitPersistedStateDB();
EXPECT_EQ(false, FailedToInit());
}
TEST_F(SessionProtoDBTest, TestKeyInsertionSucceeded) {
InitPersistedStateDB();
base::RunLoop run_loop[2];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kExpectedA));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
}
TEST_F(SessionProtoDBTest, TestKeyInsertionFailed) {
InitPersistedStateDB();
base::RunLoop run_loop[2];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), false));
MockInsertCallbackPersistedStateDB(content_db(), false);
run_loop[0].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kEmptyExpected));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
}
TEST_F(SessionProtoDBTest, TestKeyInsertionPrefix) {
InitPersistedStateDB();
base::RunLoop run_loop[2];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyPrefixA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kExpectedA));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
}
TEST_F(SessionProtoDBTest, TestLoadOneEntry) {
InitPersistedStateDB();
base::RunLoop run_loop[4];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
persisted_state_db()->InsertContent(
kMockKeyB, kMockValueB,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[1].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
persisted_state_db()->LoadOneEntry(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[2].QuitClosure(),
kExpectedA));
content_db()->GetCallback(true);
run_loop[2].Run();
persisted_state_db()->LoadOneEntry(
kMockKeyB,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[3].QuitClosure(),
kExpectedB));
content_db()->GetCallback(true);
run_loop[3].Run();
}
TEST_F(SessionProtoDBTest, TestLoadAllEntries) {
InitPersistedStateDB();
base::RunLoop run_loop[3];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
persisted_state_db()->InsertContent(
kMockKeyB, kMockValueB,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[1].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
persisted_state_db()->LoadAllEntries(base::BindOnce(
&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[2].QuitClosure(), kExpectedAB));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[2].Run();
}
TEST_F(SessionProtoDBTest, TestDeleteWithPrefix) {
InitPersistedStateDB();
base::RunLoop run_loop[4];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kExpectedA));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
persisted_state_db()->DeleteContentWithPrefix(
kMockKeyPrefixA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), true));
MockDeleteCallbackPersistedStateDB(content_db(), true);
run_loop[2].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[3].QuitClosure(),
kEmptyExpected));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[3].Run();
}
TEST_F(SessionProtoDBTest, TestDeleteOneEntry) {
InitPersistedStateDB();
base::RunLoop run_loop[6];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
MockInsertCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kExpectedA));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[1].Run();
persisted_state_db()->DeleteOneEntry(
kMockKeyPrefixA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), false));
MockDeleteCallbackPersistedStateDB(content_db(), false);
run_loop[2].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[3].QuitClosure(),
kExpectedA));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[3].Run();
persisted_state_db()->DeleteOneEntry(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[4].QuitClosure(), true));
MockDeleteCallbackPersistedStateDB(content_db(), true);
run_loop[4].Run();
persisted_state_db()->LoadContentWithPrefix(
kMockKeyPrefixA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[5].QuitClosure(),
kEmptyExpected));
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[5].Run();
}
TEST_F(SessionProtoDBTest, TestDeferredOperations) {
InitPersistedStateDBWithoutCallback();
RunUntilIdle();
EXPECT_EQ(true, InitStatusUnknown());
base::RunLoop run_loop[4];
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), true));
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kExpectedA));
EXPECT_EQ(2u, deferred_operations().size());
content_db()->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
EXPECT_EQ(false, FailedToInit());
MockInsertCallbackPersistedStateDB(content_db(), true);
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[0].Run();
run_loop[1].Run();
EXPECT_EQ(0u, deferred_operations().size());
persisted_state_db()->DeleteContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), true));
EXPECT_EQ(0u, deferred_operations().size());
MockDeleteCallbackPersistedStateDB(content_db(), true);
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[3].QuitClosure(),
kEmptyExpected));
EXPECT_EQ(0u, deferred_operations().size());
MockLoadCallbackPersistedStateDB(content_db(), true);
run_loop[3].Run();
}
TEST_F(SessionProtoDBTest, TestInitializationFailure) {
InitPersistedStateDBWithoutCallback();
RunUntilIdle();
EXPECT_EQ(true, InitStatusUnknown());
base::RunLoop run_loop[6];
// Do some operations before database status is known
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[0].QuitClosure(), false));
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[1].QuitClosure(),
kEmptyExpected));
persisted_state_db()->DeleteContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[2].QuitClosure(), false));
EXPECT_EQ(3u, deferred_operations().size());
// Error initializing database
content_db()->InitStatusCallback(leveldb_proto::Enums::InitStatus::kError);
EXPECT_EQ(true, FailedToInit());
for (int i = 0; i < 3; i++) {
run_loop[i].Run();
}
// Check deferred_operations is flushed
EXPECT_EQ(0u, deferred_operations().size());
// More operations should just return false/null as the database
// failed to initialize
persisted_state_db()->InsertContent(
kMockKeyA, kMockValueA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[3].QuitClosure(), false));
persisted_state_db()->LoadContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::GetEvaluationPersistedStateDB,
base::Unretained(this), run_loop[4].QuitClosure(),
kEmptyExpected));
persisted_state_db()->DeleteContentWithPrefix(
kMockKeyA,
base::BindOnce(&SessionProtoDBTest::OperationEvaluation,
base::Unretained(this), run_loop[5].QuitClosure(), false));
// Operations should have returned immediately as database was initialization
// resulted in an error
EXPECT_EQ(0u, deferred_operations().size());
for (int i = 3; i < 6; i++) {
run_loop[i].Run();
}
}
TEST_F(SessionProtoDBTest, TestMaintenanceKeepSomeKeys) {
InitPersistedStateDB();
InsertContentAndVerify(kSPTDTab1Key, kSPTDTab1Value);
InsertContentAndVerify(kSPTDTab2Key, kSPTDTab2Value);
InsertContentAndVerify(kSPTDTab3Key, kSPTDTab3Value);
InsertContentAndVerify(kMPTDTab1Key, kMPTDTab1Value);
PerformMaintenance(std::vector<std::string>{kSPTDTab1Key, kSPTDTab3Key},
kMatchingDataIdForMaintenance);
VerifyContent(kSPTDTab1Key, kSPTDTab1Value);
VerifyContent(kSPTDTab3Key, kSPTDTab3Value);
VerifyContent(kMPTDTab1Key, kMPTDTab1Value);
VerifyContentEmpty(kSPTDTab2Key);
}
TEST_F(SessionProtoDBTest, TestMaintenanceKeepNoKeys) {
InitPersistedStateDB();
InsertContentAndVerify(kSPTDTab1Key, kSPTDTab1Value);
InsertContentAndVerify(kSPTDTab2Key, kSPTDTab2Value);
InsertContentAndVerify(kSPTDTab3Key, kSPTDTab3Value);
InsertContentAndVerify(kMPTDTab1Key, kMPTDTab1Value);
PerformMaintenance(std::vector<std::string>{}, kMatchingDataIdForMaintenance);
VerifyContent(kMPTDTab1Key, kMPTDTab1Value);
VerifyContentEmpty(kSPTDTab1Key);
VerifyContentEmpty(kSPTDTab2Key);
VerifyContentEmpty(kSPTDTab3Key);
}
TEST_F(SessionProtoDBTest, TestMaintenanceNonMatchingDataId) {
InitPersistedStateDB();
InsertContentAndVerify(kSPTDTab1Key, kSPTDTab1Value);
InsertContentAndVerify(kSPTDTab2Key, kSPTDTab2Value);
InsertContentAndVerify(kSPTDTab3Key, kSPTDTab3Value);
InsertContentAndVerify(kMPTDTab1Key, kMPTDTab1Value);
PerformMaintenance(std::vector<std::string>{kSPTDTab1Key, kSPTDTab3Key},
kNonMatchingDataIdForMaintenance);
VerifyContent(kSPTDTab1Key, kSPTDTab1Value);
VerifyContent(kSPTDTab2Key, kSPTDTab2Value);
VerifyContent(kSPTDTab3Key, kSPTDTab3Value);
VerifyContent(kMPTDTab1Key, kMPTDTab1Value);
}