blob: 60a99bb5c4f3a595ff0a541a38eda792ca24f04a [file] [log] [blame]
// 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 "content/browser/indexed_db/scopes/leveldb_scopes_test_utils.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/test/bind_test_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "content/browser/indexed_db/leveldb/leveldb_env.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/leveldb_chrome.h"
#include "third_party/leveldatabase/src/include/leveldb/comparator.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
namespace content {
constexpr const size_t LevelDBScopesTestBase::kWriteBatchSizeForTesting;
LevelDBScopesTestBase::LevelDBScopesTestBase() = default;
LevelDBScopesTestBase::~LevelDBScopesTestBase() = default;
void LevelDBScopesTestBase::SetUp() {
large_string_.assign(kWriteBatchSizeForTesting + 1, 'e');
if (!leveldb_factory_)
leveldb_factory_ = indexed_db::LevelDBFactory::Get();
}
void LevelDBScopesTestBase::TearDown() {
if (leveldb_) {
base::RunLoop loop;
if (leveldb_->RequestDestruction(loop.QuitClosure(),
base::SequencedTaskRunnerHandle::Get())) {
leveldb_.reset();
loop.Run();
}
leveldb_.reset();
if (temp_directory_.IsValid()) {
leveldb_factory_->DestroyLevelDB(temp_directory_.GetPath());
ASSERT_TRUE(temp_directory_.Delete());
}
}
}
void LevelDBScopesTestBase::SetUpRealDatabase() {
if (leveldb_)
TearDown();
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
leveldb::Status status;
std::tie(leveldb_, status, std::ignore) = leveldb_factory_->OpenLevelDBState(
temp_directory_.GetPath(), leveldb::BytewiseComparator(), true);
ASSERT_TRUE(status.ok()) << status.ToString();
ASSERT_TRUE(leveldb_);
}
void LevelDBScopesTestBase::SetUpBreakableDB(
base::OnceCallback<void(leveldb::Status)>* callback) {
if (leveldb_)
TearDown();
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
leveldb_env::Options options = indexed_db::GetLevelDBOptions(
LevelDBEnv::Get(), leveldb::BytewiseComparator(),
/*create_if_missing=*/true,
leveldb_env::WriteBufferSize(
base::SysInfo::AmountOfTotalDiskSpace(temp_directory_.GetPath())),
/*paranoid_checks=*/true);
leveldb::Status status;
indexed_db::FakeLevelDBFactory factory;
std::unique_ptr<leveldb::DB> temp_real_db;
std::tie(temp_real_db, status) =
factory.OpenDB(options, temp_directory_.GetPath().AsUTF8Unsafe());
ASSERT_TRUE(status.ok());
ASSERT_TRUE(temp_real_db);
std::unique_ptr<leveldb::DB> db;
std::tie(db, *callback) = indexed_db::FakeLevelDBFactory::CreateBreakableDB(
std::move(temp_real_db));
ASSERT_TRUE(db);
leveldb_ = LevelDBState::CreateForDiskDB(
leveldb::BytewiseComparator(), std::move(db), temp_directory_.GetPath());
}
void LevelDBScopesTestBase::SetUpFlakyDB(
std::queue<indexed_db::FakeLevelDBFactory::FlakePoint> flake_points) {
if (leveldb_)
TearDown();
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
leveldb::Status status;
indexed_db::FakeLevelDBFactory fake_factory;
leveldb_env::Options options = indexed_db::GetLevelDBOptions(
LevelDBEnv::Get(), leveldb::BytewiseComparator(),
/*create_if_missing=*/true,
leveldb_env::WriteBufferSize(
base::SysInfo::AmountOfTotalDiskSpace(temp_directory_.GetPath())),
/*paranoid_checks=*/true);
std::unique_ptr<leveldb::DB> temp_db;
std::tie(temp_db, status) =
fake_factory.OpenDB(options, temp_directory_.GetPath().AsUTF8Unsafe());
ASSERT_TRUE(status.ok());
ASSERT_TRUE(temp_db);
std::unique_ptr<leveldb::DB> flaky_db =
indexed_db::FakeLevelDBFactory::CreateFlakyDB(std::move(temp_db),
std::move(flake_points));
fake_factory.EnqueueNextOpenDBResult(std::move(flaky_db),
leveldb::Status::OK());
std::tie(leveldb_, status, std::ignore) = fake_factory.OpenLevelDBState(
temp_directory_.GetPath(), leveldb::BytewiseComparator(), true);
ASSERT_TRUE(status.ok());
ASSERT_TRUE(leveldb_);
}
void LevelDBScopesTestBase::WriteScopesMetadata(int64_t scope_number,
bool ignore_cleanup_tasks) {
value_buffer_.clear();
auto key = scopes_encoder_.ScopeMetadataKey(metadata_prefix_, scope_number);
metadata_buffer_.set_ignore_cleanup_tasks(ignore_cleanup_tasks);
metadata_buffer_.SerializeToString(&value_buffer_);
leveldb::Status s =
leveldb_->db()->Put(leveldb::WriteOptions(), key, value_buffer_);
ASSERT_TRUE(s.ok());
metadata_buffer_.Clear();
}
void LevelDBScopesTestBase::WriteUndoTask(int64_t scope_number,
int64_t sequence_number) {
value_buffer_.clear();
auto key = scopes_encoder_.UndoTaskKey(metadata_prefix_, scope_number,
sequence_number);
undo_task_buffer_.SerializeToString(&value_buffer_);
leveldb::Status s =
leveldb_->db()->Put(leveldb::WriteOptions(), key, value_buffer_);
ASSERT_TRUE(s.ok());
undo_task_buffer_.Clear();
}
void LevelDBScopesTestBase::WriteCleanupTask(int64_t scope_number,
int64_t sequence_number) {
value_buffer_.clear();
auto key = scopes_encoder_.CleanupTaskKey(metadata_prefix_, scope_number,
sequence_number);
cleanup_task_buffer_.SerializeToString(&value_buffer_);
leveldb::Status s =
leveldb_->db()->Put(leveldb::WriteOptions(), key, value_buffer_);
ASSERT_TRUE(s.ok());
cleanup_task_buffer_.Clear();
}
void LevelDBScopesTestBase::WriteLargeValue(const std::string& key) {
leveldb::Status s =
leveldb_->db()->Put(leveldb::WriteOptions(), key, large_string_);
ASSERT_TRUE(s.ok());
}
leveldb::Status LevelDBScopesTestBase::LoadAt(const std::string& key) {
return leveldb_->db()->Get(leveldb::ReadOptions(), key, &value_buffer_);
}
leveldb::Status LevelDBScopesTestBase::LoadScopeMetadata(int64_t scope_number) {
auto key = scopes_encoder_.ScopeMetadataKey(metadata_prefix_, scope_number);
return leveldb_->db()->Get(leveldb::ReadOptions(), key, &value_buffer_);
}
leveldb::Status LevelDBScopesTestBase::LoadUndoTask(int64_t scope_number,
int64_t sequence_number) {
auto key = scopes_encoder_.UndoTaskKey(metadata_prefix_, scope_number,
sequence_number);
return leveldb_->db()->Get(leveldb::ReadOptions(), key, &value_buffer_);
}
leveldb::Status LevelDBScopesTestBase::LoadCleanupTask(
int64_t scope_number,
int64_t sequence_number) {
auto key = scopes_encoder_.CleanupTaskKey(metadata_prefix_, scope_number,
sequence_number);
return leveldb_->db()->Get(leveldb::ReadOptions(), key, &value_buffer_);
}
bool LevelDBScopesTestBase::IsPrefixedRangeEmptyInDB(leveldb::Slice key) {
std::unique_ptr<leveldb::Iterator> it =
base::WrapUnique(leveldb_->db()->NewIterator(leveldb::ReadOptions()));
it->Seek(key);
if (it->Valid() && it->key().starts_with(key))
return false;
return true;
}
bool LevelDBScopesTestBase::IsScopeCleanedUp(int64_t scope_number) {
return IsPrefixedRangeEmptyInDB(
scopes_encoder_.TasksKeyPrefix(metadata_prefix_, scope_number)) &&
IsPrefixedRangeEmptyInDB(
scopes_encoder_.TasksKeyPrefix(metadata_prefix_, scope_number));
}
bool LevelDBScopesTestBase::ScopeDataExistsOnDisk() {
return !IsPrefixedRangeEmptyInDB(
scopes_encoder_.ScopeMetadataPrefix(metadata_prefix_)) ||
!IsPrefixedRangeEmptyInDB(
scopes_encoder_.TasksKeyPrefix(metadata_prefix_));
}
ScopesLockManager::ScopeLockRequest
LevelDBScopesTestBase::CreateSimpleSharedLock() {
return {0,
{simple_lock_begin_, simple_lock_end_},
ScopesLockManager::LockType::kShared};
}
ScopesLockManager::ScopeLockRequest
LevelDBScopesTestBase::CreateSimpleExclusiveLock() {
return {0,
{simple_lock_begin_, simple_lock_end_},
ScopesLockManager::LockType::kExclusive};
}
ScopesLockManager::ScopeLockRequest LevelDBScopesTestBase::CreateSharedLock(
int i) {
return {0,
{base::StringPrintf("%010d", i * 2),
base::StringPrintf("%010d", i * 2 + 1)},
ScopesLockManager::LockType::kShared};
}
ScopesLockManager::ScopeLockRequest LevelDBScopesTestBase::CreateExclusiveLock(
int i) {
return {0,
{base::StringPrintf("%010d", i * 2),
base::StringPrintf("%010d", i * 2 + 1)},
ScopesLockManager::LockType::kExclusive};
}
} // namespace content