
DatabaseOptions is getting too large for the "explicit out of line constructor for complex types" presubmit. Adding a constructor to it prevents it from being an aggregate type, which is how most of the callers currently use it. This Cl makes DatabaseOptions members private and adds builder-type setters for each member. It also updates all callers, and adds an out of line constructor. A future improvement could be to add a passkey to the setters for discouraged options. Bug: None Change-Id: I63562f43c8b290247878d194039487b240e958c2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6216099 Reviewed-by: Gabriel Charette <gab@chromium.org> Reviewed-by: Greg Thompson <grt@chromium.org> Owners-Override: Gabriel Charette <gab@chromium.org> Commit-Queue: Anthony Vallée-Dubois <anthonyvd@chromium.org> Cr-Commit-Position: refs/heads/main@{#1414974}
283 lines
8.9 KiB
C++
283 lines
8.9 KiB
C++
// Copyright 2022 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <optional>
|
|
|
|
#include "base/files/file_path.h"
|
|
#include "base/files/scoped_temp_dir.h"
|
|
#include "sql/database.h"
|
|
#include "sql/statement.h"
|
|
#include "sql/test/scoped_error_expecter.h"
|
|
#include "sql/test/test_helpers.h"
|
|
#include "sql/transaction.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/sqlite/sqlite3.h"
|
|
|
|
namespace sql {
|
|
|
|
namespace {
|
|
|
|
enum class OpenVariant {
|
|
kInMemory = 1,
|
|
kOnDiskExclusiveJournal = 2,
|
|
kOnDiskNonExclusiveJournal = 3,
|
|
kOnDiskExclusiveWal = 4,
|
|
};
|
|
|
|
} // namespace
|
|
|
|
// We use the parameter to run all tests with WAL mode on and off.
|
|
class DatabaseOptionsTest : public testing::TestWithParam<OpenVariant> {
|
|
public:
|
|
DatabaseOptionsTest() = default;
|
|
~DatabaseOptionsTest() override = default;
|
|
|
|
void SetUp() override {
|
|
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
|
|
db_path_ = temp_dir_.GetPath().AppendASCII("database_test.sqlite");
|
|
}
|
|
|
|
OpenVariant open_variant() const { return GetParam(); }
|
|
|
|
// The options below interact with all other options. These tests ensure that
|
|
// all combinations work.
|
|
bool exclusive_locking() const {
|
|
return GetParam() != OpenVariant::kOnDiskNonExclusiveJournal;
|
|
}
|
|
bool wal_mode() const {
|
|
return GetParam() == OpenVariant::kOnDiskExclusiveWal;
|
|
}
|
|
|
|
void OpenDatabase(Database& db) {
|
|
switch (open_variant()) {
|
|
case OpenVariant::kOnDiskExclusiveJournal:
|
|
ASSERT_TRUE(db.Open(db_path_));
|
|
break;
|
|
|
|
case OpenVariant::kOnDiskNonExclusiveJournal:
|
|
ASSERT_TRUE(db.Open(db_path_));
|
|
break;
|
|
|
|
case OpenVariant::kOnDiskExclusiveWal:
|
|
ASSERT_TRUE(db.Open(db_path_));
|
|
break;
|
|
|
|
case OpenVariant::kInMemory:
|
|
ASSERT_TRUE(db.OpenInMemory());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Runs a rolled back transaction, followed by a committed transaction.
|
|
void RunTransactions(Database& db) {
|
|
{
|
|
Transaction rolled_back(&db);
|
|
ASSERT_TRUE(rolled_back.Begin());
|
|
ASSERT_TRUE(db.Execute("CREATE TABLE rows(id PRIMARY KEY NOT NULL)"));
|
|
rolled_back.Rollback();
|
|
}
|
|
{
|
|
Transaction committed(&db);
|
|
ASSERT_TRUE(committed.Begin());
|
|
ASSERT_TRUE(db.Execute("CREATE TABLE rows(id PRIMARY KEY NOT NULL)"));
|
|
ASSERT_TRUE(committed.Commit());
|
|
}
|
|
}
|
|
|
|
protected:
|
|
base::ScopedTempDir temp_dir_;
|
|
base::FilePath db_path_;
|
|
};
|
|
|
|
TEST_P(DatabaseOptionsTest, FlushToDisk_FalseByDefault) {
|
|
DatabaseOptions options = DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode());
|
|
EXPECT_FALSE(options.flush_to_media_) << "Invalid test assumption";
|
|
|
|
Database db(options, test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
EXPECT_EQ("0", sql::test::ExecuteWithResult(&db, "PRAGMA fullfsync"));
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, FlushToDisk_True) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_flush_to_media(true),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
EXPECT_EQ("1", sql::test::ExecuteWithResult(&db, "PRAGMA fullfsync"));
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, FlushToDisk_False_DoesNotCrash) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_flush_to_media(false),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
EXPECT_EQ("0", sql::test::ExecuteWithResult(&db, "PRAGMA fullfsync"))
|
|
<< "Invalid test setup";
|
|
RunTransactions(db);
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, FlushToDisk_True_DoesNotCrash) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_flush_to_media(true),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
EXPECT_EQ("1", sql::test::ExecuteWithResult(&db, "PRAGMA fullfsync"))
|
|
<< "Invalid test setup";
|
|
RunTransactions(db);
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, PageSize_Default) {
|
|
static_assert(DatabaseOptions::kDefaultPageSize == 4096,
|
|
"The page size numbers in this test file need to change");
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_page_size(4096),
|
|
test::kTestTag);
|
|
|
|
OpenDatabase(db);
|
|
EXPECT_EQ("4096", sql::test::ExecuteWithResult(&db, "PRAGMA page_size"));
|
|
|
|
RunTransactions(db);
|
|
if (open_variant() != OpenVariant::kInMemory) {
|
|
db.Close();
|
|
EXPECT_EQ(4096, sql::test::ReadDatabasePageSize(db_path_).value_or(-1));
|
|
}
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, PageSize_Large) {
|
|
static_assert(DatabaseOptions::kDefaultPageSize < 16384,
|
|
"The page size numbers in this test file need to change");
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_page_size(16384),
|
|
test::kTestTag);
|
|
|
|
OpenDatabase(db);
|
|
EXPECT_EQ("16384", sql::test::ExecuteWithResult(&db, "PRAGMA page_size"));
|
|
|
|
RunTransactions(db);
|
|
if (open_variant() != OpenVariant::kInMemory) {
|
|
db.Close();
|
|
EXPECT_EQ(16384, sql::test::ReadDatabasePageSize(db_path_).value_or(-1));
|
|
}
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, PageSize_Small) {
|
|
static_assert(DatabaseOptions::kDefaultPageSize > 1024,
|
|
"The page size numbers in this test file need to change");
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_page_size(1024),
|
|
test::kTestTag);
|
|
|
|
OpenDatabase(db);
|
|
EXPECT_EQ("1024", sql::test::ExecuteWithResult(&db, "PRAGMA page_size"));
|
|
|
|
RunTransactions(db);
|
|
if (open_variant() != OpenVariant::kInMemory) {
|
|
db.Close();
|
|
EXPECT_EQ(1024, sql::test::ReadDatabasePageSize(db_path_).value_or(-1));
|
|
}
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, CacheSize_Legacy) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_cache_size(0),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
EXPECT_EQ("-2000", sql::test::ExecuteWithResult(&db, "PRAGMA cache_size"));
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, CacheSize_Small) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_cache_size(16),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
EXPECT_EQ("16", sql::test::ExecuteWithResult(&db, "PRAGMA cache_size"));
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, CacheSize_Large) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_cache_size(1000),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
EXPECT_EQ("1000", sql::test::ExecuteWithResult(&db, "PRAGMA cache_size"));
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, EnableViewsDiscouraged_FalseByDefault) {
|
|
DatabaseOptions options = DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode());
|
|
EXPECT_FALSE(options.enable_views_discouraged_) << "Invalid test assumption";
|
|
|
|
Database db(options, test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
// sqlite3_db_config() currently only disables querying views. Schema
|
|
// operations on views are still allowed.
|
|
ASSERT_TRUE(db.Execute("CREATE VIEW view(id) AS SELECT 1"));
|
|
|
|
{
|
|
sql::test::ScopedErrorExpecter expecter;
|
|
expecter.ExpectError(SQLITE_ERROR);
|
|
Statement select_from_view(db.GetUniqueStatement("SELECT id FROM view"));
|
|
EXPECT_FALSE(select_from_view.is_valid());
|
|
EXPECT_TRUE(expecter.SawExpectedErrors());
|
|
}
|
|
|
|
// sqlite3_db_config() currently only disables querying views. Schema
|
|
// operations on views are still allowed.
|
|
EXPECT_TRUE(db.Execute("DROP VIEW IF EXISTS view"));
|
|
}
|
|
|
|
TEST_P(DatabaseOptionsTest, EnableViewsDiscouraged_True) {
|
|
Database db(DatabaseOptions()
|
|
.set_exclusive_locking(exclusive_locking())
|
|
.set_wal_mode(wal_mode())
|
|
.set_enable_views_discouraged(true),
|
|
test::kTestTag);
|
|
OpenDatabase(db);
|
|
|
|
ASSERT_TRUE(db.Execute("CREATE VIEW view(id) AS SELECT 1"));
|
|
|
|
Statement select_from_view(db.GetUniqueStatement("SELECT id FROM view"));
|
|
ASSERT_TRUE(select_from_view.is_valid());
|
|
EXPECT_TRUE(select_from_view.Step());
|
|
EXPECT_EQ(1, select_from_view.ColumnInt64(0));
|
|
|
|
EXPECT_TRUE(db.Execute("DROP VIEW IF EXISTS view"));
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
,
|
|
DatabaseOptionsTest,
|
|
testing::Values(OpenVariant::kInMemory,
|
|
OpenVariant::kOnDiskExclusiveJournal,
|
|
OpenVariant::kOnDiskNonExclusiveJournal,
|
|
OpenVariant::kOnDiskExclusiveWal));
|
|
|
|
} // namespace sql
|