/* * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "sqlite3sym.h" using namespace testing::ext; using namespace UnitTest::SQLiteTest; #define TEST_DIR "./sqlitecompresstest" #define TEST_DB (TEST_DIR "/test.db") #define TEST_PRESET_TABLE_COUNT 20 #define TEST_PRESET_DATA_COUNT 100 #define TEST_COMPRESS_META_TABLE (2) namespace Test { class SQLiteCompressTest : public testing::Test { public: static void SetUpTestCase(void); static void TearDownTestCase(void); void SetUp(); void TearDown(); static void UtSqliteLogPrint(const void *data, int err, const char *msg); static void UtCheckDb(const std::string &dbPath, int tableCount = TEST_COMPRESS_META_TABLE); static void UtBackupDatabase(sqlite3 *srcDb, sqlite3 *destDb); static void UtBackupCompressDatabase(sqlite3 *srcDb, sqlite3 *destDb); static bool IsSupportPageCompress(void); static void UtPresetDb(const std::string &dbFile, const std::string &vfsOption); static int UtQueryPresetDbResult(void *data, int argc, char **argv, char **azColName); static void UtCheckPresetDb(const std::string &dbPath, const std::string &vfsOption); static sqlite3 *db_; static int resCnt_; static const std::string &UT_DDL_CREATE_DEMO; static const std::string &UT_DML_INSERT_DEMO; static const std::string &UT_SQL_SELECT_META; static const std::string &UT_DDL_CREATE_PHONE; static const std::string &UT_PHONE_DESC; }; sqlite3 *SQLiteCompressTest::db_ = nullptr; int SQLiteCompressTest::resCnt_ = 0; const std::string &SQLiteCompressTest::UT_DDL_CREATE_DEMO = "CREATE TABLE demo(id INTEGER PRIMARY KEY, name TEXT);"; const std::string &SQLiteCompressTest::UT_DML_INSERT_DEMO = "INSERT INTO demo(id, name) VALUES(110, 'Call 110!');"; const std::string &SQLiteCompressTest::UT_SQL_SELECT_META = "SELECT COUNT(1) FROM sqlite_master;"; const std::string &SQLiteCompressTest::UT_DDL_CREATE_PHONE = "CREATE TABLE IF NOT EXISTS phone(id INTEGER PRIMARY KEY, name TEXT, brand TEXT, price REAL, type int, desc TEXT);"; const std::string &SQLiteCompressTest::UT_PHONE_DESC = "The phone is easy to use and popular. 優點(繁体)系统(简体)稳定"; void SQLiteCompressTest::UtSqliteLogPrint(const void *data, int err, const char *msg) { std::cout << "SQLiteCompressTest xLog err:" << err << ", msg:" << msg << std::endl; } void SQLiteCompressTest::UtCheckDb(const std::string &dbPath, int tableCount) { sqlite3 *tmpDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &tmpDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr), SQLITE_OK) << ", compress db:" << dbPath.c_str(); sqlite3_stmt *sqlStmt = nullptr; EXPECT_EQ(sqlite3_prepare_v2(tmpDb, UT_SQL_SELECT_META.c_str(), -1, &sqlStmt, nullptr), SQLITE_OK) << ", compress db:" << dbPath.c_str(); EXPECT_EQ(sqlite3_step(sqlStmt), SQLITE_ROW) << ", compress db:" << dbPath.c_str(); int count = sqlite3_column_int(sqlStmt, 0); EXPECT_EQ(count, tableCount) << ", compress db:" << dbPath.c_str(); sqlite3_finalize(sqlStmt); sqlite3_close_v2(tmpDb); } void SQLiteCompressTest::UtBackupDatabase(sqlite3 *srcDb, sqlite3 *destDb) { sqlite3_backup *back = nullptr; back = sqlite3_backup_init(destDb, "main", srcDb, "main"); EXPECT_TRUE(back != nullptr); EXPECT_EQ(sqlite3_backup_step(back, -1), SQLITE_DONE); sqlite3_backup_finish(back); } bool SQLiteCompressTest::IsSupportPageCompress(void) { #ifdef SQLITE_SUPPORT_PAGE_COMPRESS_TEST return true; #else return false; #endif } void SQLiteCompressTest::UtPresetDb(const std::string &dbFile, const std::string &vfsOption) { sqlite3 *db = NULL; EXPECT_EQ(sqlite3_open_v2(dbFile.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, (vfsOption.empty()? nullptr : vfsOption.c_str())), SQLITE_OK); if (vfsOption == "cksmvfs") { EXPECT_EQ(sqlite3_exec(db, "PRAGMA checksum_persist_enable=ON;", NULL, NULL, NULL), SQLITE_OK); } EXPECT_EQ(sqlite3_exec(db, "PRAGMA meta_double_write=enabled;", NULL, NULL, NULL), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL), SQLITE_OK); static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary" "(entryId INTEGER PRIMARY KEY, entryName Text, salary REAL, class INTEGER);"; EXPECT_EQ(sqlite3_exec(db, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_OK); std::string tmp = "CREATE TABLE test"; for (size_t i = 0; i < 10; i++) { // 10 means the count of tables std::string ddl = "CREATE TABLE test"; ddl += std::to_string(i); ddl += "(entryId INTEGER PRIMARY KEY, entryName Text, salary REAL, class INTEGER);"; EXPECT_EQ(sqlite3_exec(db, ddl.c_str(), NULL, NULL, NULL), SQLITE_OK); } static const char *UT_SQL_INSERT_DATA = "INSERT INTO salary(entryId, entryName, salary, class) VALUES(?,?,?,?);"; sqlite3_stmt *insertStmt = NULL; EXPECT_EQ(sqlite3_prepare_v2(db, UT_SQL_INSERT_DATA, -1, &insertStmt, NULL), SQLITE_OK); for (int i = 0; i < 1000; i++) { // 1000 means the total number of insert data sqlite3_bind_int(insertStmt, 1, i + 1); // 1 is the seq number of 1st field sqlite3_bind_text(insertStmt, 2, "salary-entry-name", -1, SQLITE_STATIC); // 2 is the seq number of 2nd field sqlite3_bind_double(insertStmt, 3, i); // 3 is the seq number of 3rd field sqlite3_bind_int(insertStmt, 4, i + 1); // 4 is the seq number of 4th field EXPECT_EQ(sqlite3_step(insertStmt), SQLITE_DONE); sqlite3_reset(insertStmt); } sqlite3_finalize(insertStmt); sqlite3_close(db); } int SQLiteCompressTest::UtQueryPresetDbResult(void *data, int argc, char **argv, char **azColName) { int type = *static_cast(data); EXPECT_EQ(argc, 1); if (type==0) { // Check tables std::string tableName = argv[0] ? argv[0] : nullptr; std::string expectTables[] = { "salary", "test0", "test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9" }; bool isExist = false; for (size_t i = 0; i < 11; i++) { // 11 is the number of array:expectTables if (expectTables[i] == tableName) { isExist = true; break; } } EXPECT_TRUE(isExist) << ", tableName:" << tableName; return SQLITE_OK; } resCnt_++; int entryId = atoi(argv[0]); EXPECT_TRUE(entryId > 0 && entryId < 1001) << ", entryId:" << entryId; // 1001 is the max id of entryId return SQLITE_OK; } void SQLiteCompressTest::UtCheckPresetDb(const std::string &dbFile, const std::string &vfsOption) { sqlite3 *db = NULL; EXPECT_EQ(sqlite3_open_v2(dbFile.c_str(), &db, SQLITE_OPEN_READONLY, (vfsOption.empty()? nullptr : vfsOption.c_str())), SQLITE_OK); static const char *UT_SELECT_ALL_TABLES = "SELECT tbl_name FROM sqlite_master;"; int type = 0; EXPECT_EQ(sqlite3_exec(db, UT_SELECT_ALL_TABLES, &UtQueryPresetDbResult, &type, nullptr), SQLITE_OK); type = 1; // 1 means query table: salary resCnt_ = 0; static const char *UT_SELECT_ALL_FROM_SALARY = "SELECT entryId FROM salary;"; EXPECT_EQ(sqlite3_exec(db, UT_SELECT_ALL_FROM_SALARY, &UtQueryPresetDbResult, &type, nullptr), SQLITE_OK); EXPECT_EQ(resCnt_, 1000); sqlite3_close(db); } void SQLiteCompressTest::SetUpTestCase(void) { Common::RemoveDir(TEST_DIR); Common::MakeDir(TEST_DIR); EXPECT_EQ(sqlite3_register_cksumvfs(NULL), SQLITE_OK); } void SQLiteCompressTest::TearDownTestCase(void) { EXPECT_EQ(sqlite3_unregister_cksumvfs(), SQLITE_OK); } void SQLiteCompressTest::SetUp(void) { std::string command = "rm -rf "; command += TEST_DIR "/*"; system(command.c_str()); sqlite3_config(SQLITE_CONFIG_LOG, &SQLiteCompressTest::UtSqliteLogPrint, NULL); EXPECT_EQ(sqlite3_open(TEST_DB, &db_), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db_, UT_DDL_CREATE_PHONE.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); for (int i = 0; i < TEST_PRESET_TABLE_COUNT; i++) { std::string ddl = "CREATE TABLE IF NOT EXISTS test"; ddl += std::to_string(i + 1); ddl += "(id INTEGER PRIMARY KEY, field1 INTEGER, field2 REAL, field3 TEXT, field4 BLOB, field5 TEXT);"; EXPECT_EQ(sqlite3_exec(db_, ddl.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); } std::vector phoneList = {"Huawei", "Samsung", "Apple", "Xiaomi", "Oppo", "Vivo", "Realme"}; for (int i = 0; i < TEST_PRESET_DATA_COUNT; i++) { std::string dml = "INSERT INTO phone(id, name, brand, price, type, desc) VALUES("; dml += std::to_string(i + 1) + ",'"; dml += std::to_string(i + 1) + " Martin''s Phone','"; dml += std::to_string(i + 1) + phoneList[i%phoneList.size()] + "',"; dml += std::to_string(i + 1.0) + ","; dml += std::to_string(i + 1) + ",'" + UT_PHONE_DESC + UT_PHONE_DESC + UT_PHONE_DESC + UT_PHONE_DESC + "');"; EXPECT_EQ(sqlite3_exec(db_, dml.c_str(), nullptr, nullptr, nullptr), SQLITE_OK) << sqlite3_errmsg(db_); } sqlite3_close(db_); EXPECT_EQ(sqlite3_open(TEST_DB, &db_), SQLITE_OK); } void SQLiteCompressTest::TearDown(void) { sqlite3_close(db_); db_ = nullptr; sqlite3_config(SQLITE_CONFIG_LOG, NULL, NULL); } /** * @tc.name: CompressTest001 * @tc.desc: Test to enable page compression on brand new db. * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest001, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2 * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/compresstest0010.db"; sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); sqlite3_close_v2(compDb); compDb = nullptr; UtCheckDb(dbPath1); /** * @tc.steps: step2. Create a brand new db while page compression enabled through uri * @tc.expected: step2. Execute successfully */ std::string dbFileUri = "file:"; dbFileUri += TEST_DIR "/compresstest0011.db"; dbFileUri += "?vfs=compressvfs"; EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &compDb), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); sqlite3_close(compDb); compDb = nullptr; UtCheckDb(TEST_DIR "/compresstest0011.db"); } /** * @tc.name: CompressTest002 * @tc.desc: Test to try enable page compression on none compress db * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest002, TestSize.Level0) { sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(TEST_DB, &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_WARNING); EXPECT_EQ(sqlite3_extended_errcode(compDb), SQLITE_WARNING_NOTCOMPRESSDB); sqlite3_close_v2(compDb); EXPECT_EQ(sqlite3_open_v2(TEST_DB, &compDb, SQLITE_OPEN_READONLY, "compressvfs"), SQLITE_WARNING); EXPECT_EQ(sqlite3_extended_errcode(compDb), SQLITE_WARNING_NOTCOMPRESSDB); sqlite3_close_v2(compDb); std::string dbFileUri = "file:"; dbFileUri += TEST_DB; dbFileUri += "?vfs=compressvfs"; EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &compDb), SQLITE_WARNING); EXPECT_EQ(sqlite3_extended_errcode(compDb), SQLITE_WARNING_NOTCOMPRESSDB); sqlite3_close_v2(compDb); } /** * @tc.name: CompressTest003 * @tc.desc: Test to backup db and enable page compression on dest db * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest003, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Compress db using Backup function:sqlite3_backup_step * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/compresstest0030.db"; sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); UtBackupDatabase(db_, compDb); sqlite3_close_v2(compDb); UtCheckDb(dbPath1); /** * @tc.steps: step2. Compress db using new Backup function:sqlite3_compressdb_backup * @tc.expected: step2. Execute successfully */ EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK); std::string dbPath2 = TEST_DIR "/restore0031.db"; EXPECT_EQ(sqlite3_compressdb_backup(compDb, dbPath2.c_str()), SQLITE_DONE); sqlite3_close_v2(compDb); UtCheckDb(dbPath2, TEST_PRESET_TABLE_COUNT + 1); } /** * @tc.name: CompressTest004 * @tc.desc: Test to create new db and enable page compression * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest004, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2 * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/compresstest0040.db"; sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); /** * @tc.steps: step2. Set meta double write enable through Pragma statement * @tc.expected: step2. Execute successfully */ EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK); /** * @tc.steps: step3. Set journal mode as WAL through Pragma statement * @tc.expected: step3. Execute successfully */ EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_PHONE.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); /** * @tc.steps: step4. Set WAL file persist * @tc.expected: step4. Execute successfully */ int code = 1; EXPECT_EQ(sqlite3_file_control(compDb, "main", SQLITE_FCNTL_PERSIST_WAL, &code), SQLITE_OK); sqlite3_close_v2(compDb); /** * @tc.steps: step5. Check result, files should exist * @tc.expected: step4. Execute successfully */ std::string wal = dbPath1 + "-walcompress"; std::string shm = dbPath1 + "-shmcompress"; std::string dwr = dbPath1 + "-dwr"; EXPECT_TRUE(Common::IsFileExist(wal.c_str())); EXPECT_TRUE(Common::IsFileExist(shm.c_str())); EXPECT_TRUE(Common::IsFileExist(dwr.c_str())); } /** * @tc.name: CompressTest005 * @tc.desc: Test to create new db and get db/wal/journal filename * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest005, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2 * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/compresstest0050.db"; sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK); /** * @tc.steps: step2. Try to get db/wal/journal filename * @tc.expected: step2. Execute successfully */ const char *db = sqlite3_db_filename(compDb, "main"); const char *wal = sqlite3_filename_wal(db); const char *journal = sqlite3_filename_journal(db); std::string str = db; int n = str.find("/compresstest0050.db"); EXPECT_TRUE(n != string::npos); EXPECT_TRUE(n==(str.size() - strlen("/compresstest0050.db"))); str = wal; n = str.find("/compresstest0050.db-walcompress"); EXPECT_TRUE(n != string::npos); EXPECT_TRUE(n==(str.size() - strlen("/compresstest0050.db-walcompress"))); str = journal; n = str.find("/compresstest0050.db-journalcompress"); EXPECT_TRUE(n != string::npos); EXPECT_TRUE(n==(str.size() - strlen("/compresstest0050.db-journalcompress"))); sqlite3_close_v2(compDb); } /** * @tc.name: CompressTest006 * @tc.desc: Test to create new db and open multi sqlite3 handler at the same time * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest006, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2 * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/compresstest0060.db"; sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); /** * @tc.steps: step2. Open multi sqlite3 which enable page compression at the same time * @tc.expected: step2. Execute successfully */ sqlite3 *compDb1 = nullptr; sqlite3 *compDb2 = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb1, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb2, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); sqlite3_close_v2(compDb2); sqlite3_close_v2(compDb1); sqlite3_close_v2(compDb); } /** * @tc.name: CompressTest007 * @tc.desc: Test to create brand new db * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest007, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create a brand new db while page compression enabled through sqlite3_open_v2 * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/compresstest007.db"; sqlite3 *compDb = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); int persistMode = 1; EXPECT_EQ(sqlite3_file_control(compDb, "main", SQLITE_FCNTL_PERSIST_WAL, &persistMode), SQLITE_OK); sqlite3_close_v2(compDb); /** * @tc.steps: step5. Check result, files should exist * @tc.expected: step4. Execute successfully */ std::string wal = dbPath1 + "-walcompress"; std::string shm = dbPath1 + "-shmcompress"; std::string dwr = dbPath1 + "-dwr"; std::string lock = dbPath1 + "-lockcompress"; EXPECT_TRUE(Common::IsFileExist(wal.c_str())); EXPECT_TRUE(Common::IsFileExist(shm.c_str())); EXPECT_TRUE(Common::IsFileExist(dwr.c_str())); EXPECT_TRUE(Common::IsFileExist(lock.c_str())); } /** * @tc.name: CompressTest008 * @tc.desc: Test to create brand new db disabled compression * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest008, TestSize.Level0) { /** * @tc.steps: step1. Create a brand new db while page compression disabled * @tc.expected: step1. Execute successfully */ std::string dbPath1 = TEST_DIR "/test008.db"; sqlite3 *db = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); int persistMode = 1; EXPECT_EQ(sqlite3_file_control(db, "main", SQLITE_FCNTL_PERSIST_WAL, &persistMode), SQLITE_OK); sqlite3_close_v2(db); /** * @tc.steps: step5. Check result, files should exist except lock file * @tc.expected: step4. Execute successfully */ std::string wal = dbPath1 + "-wal"; std::string shm = dbPath1 + "-shm"; std::string dwr = dbPath1 + "-dwr"; std::string lock = dbPath1 + "-lockcompress"; EXPECT_TRUE(Common::IsFileExist(wal.c_str())); EXPECT_TRUE(Common::IsFileExist(shm.c_str())); EXPECT_TRUE(Common::IsFileExist(dwr.c_str())); EXPECT_FALSE(Common::IsFileExist(lock.c_str())); } /** * @tc.name: CompressTest009 * @tc.desc: Test to open an non-cmopress db through vfs option:compress * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest009, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Open the exist db through vfs option:compressvfs using SQLITE_OPEN_READONLY * @tc.expected: step1. Execute successfully */ sqlite3 *db1 = nullptr; EXPECT_EQ(sqlite3_open_v2(TEST_DB, &db1, SQLITE_OPEN_READONLY, "compressvfs"), SQLITE_WARNING); // lock file not exist, return not a compress db EXPECT_EQ(sqlite3_extended_errcode(db1), SQLITE_WARNING_NOTCOMPRESSDB); sqlite3_close_v2(db1); } /** * @tc.name: CompressTest010 * @tc.desc: Test to insert data while transaction executing * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest010, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create a brand new db while page compression enabled * @tc.expected: step1. Execute successfully */ std::string dbPath = TEST_DIR "/compresstest010.db"; UtPresetDb(dbPath, "compressvfs"); /** * @tc.steps: step2. Open the db used to begin transaction, delete 5 entries * @tc.expected: step2. Execute successfully */ sqlite3 *db1 = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db1, SQLITE_OPEN_READWRITE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db1, "BEGIN;", nullptr, nullptr, nullptr), SQLITE_OK); // delete data from 996 ~ 1000 EXPECT_EQ(sqlite3_exec(db1, "DELETE FROM salary WHERE entryId > 995;", nullptr, nullptr, nullptr), SQLITE_OK); /** * @tc.steps: step3. Open another db used to insert data, before commit transaction * @tc.expected: step3. Execute successfully */ sqlite3 *db2 = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db2, SQLITE_OPEN_READWRITE, "compressvfs"), SQLITE_OK); static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary123" "(entryId INTEGER PRIMARY KEY, entryName Text, salary REAL, class INTEGER);"; EXPECT_EQ(sqlite3_exec(db2, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_BUSY); sqlite3_close_v2(db2); EXPECT_EQ(sqlite3_exec(db1, "COMMIT;", nullptr, nullptr, nullptr), SQLITE_OK); sqlite3_close_v2(db1); } /** * @tc.name: CompressTest011 * @tc.desc: Test to check lock file name * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest011, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Get lock file name from non-compress db connection * @tc.expected: step1. Execute successfully */ const char *dbName = sqlite3_db_filename(db_, "main"); const char *walName = sqlite3_filename_wal(dbName); const char *lockName = walName + strlen(walName) + 1; std::string expectLockFilenameSuffix = "/sqlitecompresstest/test.db"; std::string lockPathStr = lockName; EXPECT_TRUE(lockPathStr.find(expectLockFilenameSuffix) != std::string::npos); /** * @tc.steps: step2. Create a brand new db while page compression enabled, check lock filename * @tc.expected: step2. Execute successfully */ std::string dbPath = TEST_DIR "/compresstest011.db"; UtPresetDb(dbPath, "compressvfs"); sqlite3 *db1 = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db1, SQLITE_OPEN_READWRITE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(db1, UT_DDL_CREATE_PHONE.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); const char *dbName1 = sqlite3_db_filename(db1, "main"); const char *walName1 = sqlite3_filename_wal(dbName1); const char *lockName1 = walName1 + strlen(walName1) + 1; std::string expectLockFilenameSuffix1 = "/sqlitecompresstest/compresstest011.db-lockcompress"; lockPathStr = lockName1; EXPECT_TRUE(lockPathStr.find(expectLockFilenameSuffix1) != std::string::npos); sqlite3_close_v2(db1); } /** * @tc.name: CompressTest012 * @tc.desc: Test to check lock file name * @tc.type: FUNC */ HWTEST_F(SQLiteCompressTest, CompressTest012, TestSize.Level0) { if (!IsSupportPageCompress()) { GTEST_SKIP() << "Current testcase is not compatible"; } /** * @tc.steps: step1. Create brand new db as main db, and a compress db as slave * @tc.expected: step1. Execute successfully */ std::string dbPath = TEST_DIR "/test011.db"; UtPresetDb(dbPath, ""); sqlite3 *db = nullptr; EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK); std::string slavePath = TEST_DIR "/test011_slave.db"; sqlite3 *slaveDb = nullptr; EXPECT_EQ(sqlite3_open_v2(slavePath.c_str(), &slaveDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"), SQLITE_OK); EXPECT_EQ(sqlite3_exec(slaveDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(slaveDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(slaveDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); EXPECT_EQ(sqlite3_exec(slaveDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); int persistMode = 1; EXPECT_EQ(sqlite3_file_control(slaveDb, "main", SQLITE_FCNTL_PERSIST_WAL, &persistMode), SQLITE_OK); UtBackupDatabase(db, slaveDb); /** * @tc.steps: step2. Insert serveral data into slave db, then backup again * @tc.expected: step2. Execute successfully */ static const char *UT_INSERT_DATA = "INSERT INTO salary(entryId, entryName, salary, class) VALUES(?,?,?,?);"; sqlite3_stmt *insertStmt = NULL; EXPECT_EQ(sqlite3_prepare_v2(slaveDb, UT_INSERT_DATA, -1, &insertStmt, NULL), SQLITE_OK); for (int i = 0; i < 100; i++) { // 100 means the total number of insert data sqlite3_bind_int(insertStmt, 1, i + 20000); // 20000 is the begining of entryId to insert sqlite3_bind_text(insertStmt, 2, "salary-entry-name", -1, SQLITE_STATIC); // 2 is the seq number of 2nd field sqlite3_bind_double(insertStmt, 3, i); // 3 is the seq number of 3rd field sqlite3_bind_int(insertStmt, 4, i + 1); // 4 is the seq number of 4th field EXPECT_EQ(sqlite3_step(insertStmt), SQLITE_DONE); sqlite3_reset(insertStmt); } sqlite3_finalize(insertStmt); // Backup again, all data insert above should be covered UtBackupDatabase(db, slaveDb); sqlite3_close_v2(slaveDb); sqlite3_close_v2(db); UtCheckPresetDb(slavePath, "compressvfs"); } } // namespace Test