| // 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{ |
| |
| enumclassOpenVariant{ |
| kInMemory=1, |
| kOnDiskExclusiveJournal=2, |
| kOnDiskNonExclusiveJournal=3, |
| kOnDiskExclusiveWal=4, |
| }; |
| |
| }// namespace |
| |
| // We use the parameter to run all tests with WAL mode on and off. |
| classDatabaseOptionsTest:public testing::TestWithParam<OpenVariant>{ |
| public: |
| DatabaseOptionsTest()=default; |
| ~DatabaseOptionsTest() override=default; |
| |
| voidSetUp() override{ |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| db_path_= temp_dir_.GetPath().AppendASCII("database_test.sqlite"); |
| } |
| |
| OpenVariant open_variant()const{returnGetParam();} |
| |
| // The options below interact with all other options. These tests ensure that |
| // all combinations work. |
| bool exclusive_locking()const{ |
| returnGetParam()!=OpenVariant::kOnDiskNonExclusiveJournal; |
| } |
| bool wal_mode()const{ |
| returnGetParam()==OpenVariant::kOnDiskExclusiveWal; |
| } |
| |
| voidOpenDatabase(Database& db){ |
| switch(open_variant()){ |
| caseOpenVariant::kOnDiskExclusiveJournal: |
| ASSERT_TRUE(db.Open(db_path_)); |
| break; |
| |
| caseOpenVariant::kOnDiskNonExclusiveJournal: |
| ASSERT_TRUE(db.Open(db_path_)); |
| break; |
| |
| caseOpenVariant::kOnDiskExclusiveWal: |
| ASSERT_TRUE(db.Open(db_path_)); |
| break; |
| |
| caseOpenVariant::kInMemory: |
| ASSERT_TRUE(db.OpenInMemory()); |
| break; |
| } |
| } |
| |
| // Runs a rolled back transaction, followed by a committed transaction. |
| voidRunTransactions(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 |