• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <gtest/gtest.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 
19 #include <chrono>
20 #include <cstdio>
21 #include <fstream>
22 #include <random>
23 #include <string>
24 #include <unistd.h>
25 #include <sstream>
26 #include <vector>
27 
28 #include "common.h"
29 #include "sqlite3sym.h"
30 
31 using namespace testing::ext;
32 using namespace UnitTest::SQLiteTest;
33 
34 #define TEST_DIR "./sqlitecompresstest"
35 #define TEST_DB (TEST_DIR "/test.db")
36 #define TEST_PRESET_TABLE_COUNT 20
37 #define TEST_PRESET_DATA_COUNT 100
38 #define TEST_COMPRESS_META_TABLE (2)
39 
40 namespace Test {
41 class SQLiteCompressTest : public testing::Test {
42 public:
43     static void SetUpTestCase(void);
44     static void TearDownTestCase(void);
45     void SetUp();
46     void TearDown();
47 
48     static void UtSqliteLogPrint(const void *data, int err, const char *msg);
49     static void UtCheckDb(const std::string &dbPath, int tableCount = TEST_COMPRESS_META_TABLE);
50     static void UtBackupDatabase(sqlite3 *srcDb, sqlite3 *destDb);
51     static void UtBackupCompressDatabase(sqlite3 *srcDb, sqlite3 *destDb);
52     static bool IsSupportPageCompress(void);
53     static void UtPresetDb(const std::string &dbFile, const std::string &vfsOption);
54     static int UtQueryPresetDbResult(void *data, int argc, char **argv, char **azColName);
55     static void UtCheckPresetDb(const std::string &dbPath, const std::string &vfsOption);
56 
57     static sqlite3 *db_;
58     static int resCnt_;
59     static const std::string &UT_DDL_CREATE_DEMO;
60     static const std::string &UT_DML_INSERT_DEMO;
61     static const std::string &UT_SQL_SELECT_META;
62     static const std::string &UT_DDL_CREATE_PHONE;
63     static const std::string &UT_PHONE_DESC;
64 };
65 
66 sqlite3 *SQLiteCompressTest::db_ = nullptr;
67 int SQLiteCompressTest::resCnt_ = 0;
68 const std::string &SQLiteCompressTest::UT_DDL_CREATE_DEMO = "CREATE TABLE demo(id INTEGER PRIMARY KEY, name TEXT);";
69 const std::string &SQLiteCompressTest::UT_DML_INSERT_DEMO = "INSERT INTO demo(id, name) VALUES(110, 'Call 110!');";
70 const std::string &SQLiteCompressTest::UT_SQL_SELECT_META = "SELECT COUNT(1) FROM sqlite_master;";
71 const std::string &SQLiteCompressTest::UT_DDL_CREATE_PHONE =
72     "CREATE TABLE IF NOT EXISTS phone(id INTEGER PRIMARY KEY, name TEXT, brand TEXT, price REAL, type int, desc TEXT);";
73 const std::string &SQLiteCompressTest::UT_PHONE_DESC = "The phone is easy to use and popular. 優點(繁体)系统(简体)稳定";
74 
UtSqliteLogPrint(const void * data,int err,const char * msg)75 void SQLiteCompressTest::UtSqliteLogPrint(const void *data, int err, const char *msg)
76 {
77     std::cout << "SQLiteCompressTest xLog err:" << err << ", msg:" << msg << std::endl;
78 }
79 
UtCheckDb(const std::string & dbPath,int tableCount)80 void SQLiteCompressTest::UtCheckDb(const std::string &dbPath, int tableCount)
81 {
82     sqlite3 *tmpDb = nullptr;
83     EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &tmpDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr),
84         SQLITE_OK) << ", compress db:" << dbPath.c_str();
85     sqlite3_stmt *sqlStmt = nullptr;
86     EXPECT_EQ(sqlite3_prepare_v2(tmpDb, UT_SQL_SELECT_META.c_str(), -1, &sqlStmt, nullptr),
87         SQLITE_OK) << ", compress db:" << dbPath.c_str();
88     EXPECT_EQ(sqlite3_step(sqlStmt), SQLITE_ROW) << ", compress db:" << dbPath.c_str();
89     int count = sqlite3_column_int(sqlStmt, 0);
90     EXPECT_EQ(count, tableCount) << ", compress db:" << dbPath.c_str();
91     sqlite3_finalize(sqlStmt);
92     sqlite3_close_v2(tmpDb);
93 }
94 
UtBackupDatabase(sqlite3 * srcDb,sqlite3 * destDb)95 void SQLiteCompressTest::UtBackupDatabase(sqlite3 *srcDb, sqlite3 *destDb)
96 {
97     sqlite3_backup *back = nullptr;
98     back = sqlite3_backup_init(destDb, "main", srcDb, "main");
99     EXPECT_TRUE(back != nullptr);
100     EXPECT_EQ(sqlite3_backup_step(back, -1), SQLITE_DONE);
101     sqlite3_backup_finish(back);
102 }
103 
IsSupportPageCompress(void)104 bool SQLiteCompressTest::IsSupportPageCompress(void)
105 {
106 #ifdef SQLITE_SUPPORT_PAGE_COMPRESS_TEST
107     return true;
108 #else
109     return false;
110 #endif
111 }
112 
UtPresetDb(const std::string & dbFile,const std::string & vfsOption)113 void SQLiteCompressTest::UtPresetDb(const std::string &dbFile, const std::string &vfsOption)
114 {
115     sqlite3 *db = NULL;
116     EXPECT_EQ(sqlite3_open_v2(dbFile.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
117         (vfsOption.empty()? nullptr : vfsOption.c_str())), SQLITE_OK);
118     if (vfsOption == "cksmvfs") {
119         EXPECT_EQ(sqlite3_exec(db, "PRAGMA checksum_persist_enable=ON;", NULL, NULL, NULL), SQLITE_OK);
120     }
121     EXPECT_EQ(sqlite3_exec(db, "PRAGMA meta_double_write=enabled;", NULL, NULL, NULL), SQLITE_OK);
122     EXPECT_EQ(sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL), SQLITE_OK);
123     static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary"
124         "(entryId INTEGER PRIMARY KEY, entryName Text, salary REAL, class INTEGER);";
125     EXPECT_EQ(sqlite3_exec(db, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_OK);
126     std::string tmp = "CREATE TABLE test";
127     for (size_t i = 0; i < 10; i++) {  // 10 means the count of tables
128         std::string ddl = "CREATE TABLE test";
129         ddl += std::to_string(i);
130         ddl += "(entryId INTEGER PRIMARY KEY, entryName Text, salary REAL, class INTEGER);";
131         EXPECT_EQ(sqlite3_exec(db, ddl.c_str(), NULL, NULL, NULL), SQLITE_OK);
132     }
133     static const char *UT_SQL_INSERT_DATA = "INSERT INTO salary(entryId, entryName, salary, class) VALUES(?,?,?,?);";
134     sqlite3_stmt *insertStmt = NULL;
135     EXPECT_EQ(sqlite3_prepare_v2(db, UT_SQL_INSERT_DATA, -1, &insertStmt, NULL), SQLITE_OK);
136     for (int i = 0; i < 1000; i++) {  // 1000 means the total number of insert data
137         sqlite3_bind_int(insertStmt, 1, i + 1);  // 1 is the seq number of 1st field
138         sqlite3_bind_text(insertStmt, 2, "salary-entry-name", -1, SQLITE_STATIC);  // 2 is the seq number of 2nd field
139         sqlite3_bind_double(insertStmt, 3, i);  // 3 is the seq number of 3rd field
140         sqlite3_bind_int(insertStmt, 4, i + 1);  // 4 is the seq number of 4th field
141         EXPECT_EQ(sqlite3_step(insertStmt), SQLITE_DONE);
142         sqlite3_reset(insertStmt);
143     }
144     sqlite3_finalize(insertStmt);
145     sqlite3_close(db);
146 }
147 
UtQueryPresetDbResult(void * data,int argc,char ** argv,char ** azColName)148 int SQLiteCompressTest::UtQueryPresetDbResult(void *data, int argc, char **argv, char **azColName)
149 {
150     int type = *static_cast<int *>(data);
151     EXPECT_EQ(argc, 1);
152     if (type==0) { // Check tables
153         std::string tableName = argv[0] ? argv[0] : nullptr;
154         std::string expectTables[] = { "salary", "test0", "test1", "test2", "test3", "test4",
155             "test5", "test6", "test7", "test8", "test9" };
156         bool isExist = false;
157         for (size_t i = 0; i < 11; i++) {  // 11 is the number of array:expectTables
158             if (expectTables[i] == tableName) {
159                 isExist = true;
160                 break;
161             }
162         }
163         EXPECT_TRUE(isExist) << ", tableName:" << tableName;
164         return SQLITE_OK;
165     }
166 
167     resCnt_++;
168     int entryId = atoi(argv[0]);
169     EXPECT_TRUE(entryId > 0 && entryId < 1001) << ", entryId:" << entryId;  // 1001 is the max id of entryId
170     return SQLITE_OK;
171 }
172 
UtCheckPresetDb(const std::string & dbFile,const std::string & vfsOption)173 void SQLiteCompressTest::UtCheckPresetDb(const std::string &dbFile, const std::string &vfsOption)
174 {
175     sqlite3 *db = NULL;
176     EXPECT_EQ(sqlite3_open_v2(dbFile.c_str(), &db, SQLITE_OPEN_READONLY,
177         (vfsOption.empty()? nullptr : vfsOption.c_str())), SQLITE_OK);
178     static const char *UT_SELECT_ALL_TABLES = "SELECT tbl_name FROM sqlite_master;";
179     int type = 0;
180     EXPECT_EQ(sqlite3_exec(db, UT_SELECT_ALL_TABLES, &UtQueryPresetDbResult, &type, nullptr), SQLITE_OK);
181     type = 1;  // 1 means query table: salary
182     resCnt_ = 0;
183     static const char *UT_SELECT_ALL_FROM_SALARY = "SELECT entryId FROM salary;";
184     EXPECT_EQ(sqlite3_exec(db, UT_SELECT_ALL_FROM_SALARY, &UtQueryPresetDbResult, &type, nullptr), SQLITE_OK);
185     EXPECT_EQ(resCnt_, 1000);
186     sqlite3_close(db);
187 }
188 
SetUpTestCase(void)189 void SQLiteCompressTest::SetUpTestCase(void)
190 {
191     Common::RemoveDir(TEST_DIR);
192     Common::MakeDir(TEST_DIR);
193     EXPECT_EQ(sqlite3_register_cksumvfs(NULL), SQLITE_OK);
194 }
195 
TearDownTestCase(void)196 void SQLiteCompressTest::TearDownTestCase(void)
197 {
198     EXPECT_EQ(sqlite3_unregister_cksumvfs(), SQLITE_OK);
199 }
200 
SetUp(void)201 void SQLiteCompressTest::SetUp(void)
202 {
203     std::string command = "rm -rf ";
204     command += TEST_DIR "/*";
205     system(command.c_str());
206     sqlite3_config(SQLITE_CONFIG_LOG, &SQLiteCompressTest::UtSqliteLogPrint, NULL);
207     EXPECT_EQ(sqlite3_open(TEST_DB, &db_), SQLITE_OK);
208     EXPECT_EQ(sqlite3_exec(db_, UT_DDL_CREATE_PHONE.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
209     for (int i = 0; i < TEST_PRESET_TABLE_COUNT; i++) {
210         std::string ddl = "CREATE TABLE IF NOT EXISTS test";
211         ddl += std::to_string(i + 1);
212         ddl += "(id INTEGER PRIMARY KEY, field1 INTEGER, field2 REAL, field3 TEXT, field4 BLOB, field5 TEXT);";
213         EXPECT_EQ(sqlite3_exec(db_, ddl.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
214     }
215     std::vector<std::string> phoneList = {"Huawei", "Samsung", "Apple", "Xiaomi", "Oppo", "Vivo", "Realme"};
216     for (int i = 0; i < TEST_PRESET_DATA_COUNT; i++) {
217         std::string dml = "INSERT INTO phone(id, name, brand, price, type, desc) VALUES(";
218         dml += std::to_string(i + 1) + ",'";
219         dml += std::to_string(i + 1) + " Martin''s Phone','";
220         dml += std::to_string(i + 1) + phoneList[i%phoneList.size()] + "',";
221         dml += std::to_string(i + 1.0) + ",";
222         dml += std::to_string(i + 1) + ",'" + UT_PHONE_DESC + UT_PHONE_DESC + UT_PHONE_DESC + UT_PHONE_DESC + "');";
223         EXPECT_EQ(sqlite3_exec(db_, dml.c_str(), nullptr, nullptr, nullptr), SQLITE_OK) << sqlite3_errmsg(db_);
224     }
225     sqlite3_close(db_);
226     EXPECT_EQ(sqlite3_open(TEST_DB, &db_), SQLITE_OK);
227 }
228 
TearDown(void)229 void SQLiteCompressTest::TearDown(void)
230 {
231     sqlite3_close(db_);
232     db_ = nullptr;
233     sqlite3_config(SQLITE_CONFIG_LOG, NULL, NULL);
234 }
235 
236 /**
237  * @tc.name: CompressTest001
238  * @tc.desc: Test to enable page compression on brand new db.
239  * @tc.type: FUNC
240  */
241 HWTEST_F(SQLiteCompressTest, CompressTest001, TestSize.Level0)
242 {
243     if (!IsSupportPageCompress()) {
244         GTEST_SKIP() << "Current testcase is not compatible";
245     }
246     /**
247      * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2
248      * @tc.expected: step1. Execute successfully
249      */
250     std::string dbPath1 = TEST_DIR "/compresstest0010.db";
251     sqlite3 *compDb = nullptr;
252     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
253         SQLITE_OK);
254     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
255     EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
256     sqlite3_close_v2(compDb);
257     compDb = nullptr;
258     UtCheckDb(dbPath1);
259     /**
260      * @tc.steps: step2. Create a brand new db while page compression enabled through uri
261      * @tc.expected: step2. Execute successfully
262      */
263     std::string dbFileUri = "file:";
264     dbFileUri += TEST_DIR "/compresstest0011.db";
265     dbFileUri += "?vfs=compressvfs";
266     EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &compDb), SQLITE_OK);
267     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
268     EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
269     sqlite3_close(compDb);
270     compDb = nullptr;
271     UtCheckDb(TEST_DIR "/compresstest0011.db");
272 }
273 
274 /**
275  * @tc.name: CompressTest002
276  * @tc.desc: Test to try enable page compression on none compress db
277  * @tc.type: FUNC
278  */
279 HWTEST_F(SQLiteCompressTest, CompressTest002, TestSize.Level0)
280 {
281     sqlite3 *compDb = nullptr;
282     EXPECT_EQ(sqlite3_open_v2(TEST_DB, &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
283         SQLITE_WARNING);
284     EXPECT_EQ(sqlite3_extended_errcode(compDb), SQLITE_WARNING_NOTCOMPRESSDB);
285     sqlite3_close_v2(compDb);
286 
287     EXPECT_EQ(sqlite3_open_v2(TEST_DB, &compDb, SQLITE_OPEN_READONLY, "compressvfs"), SQLITE_WARNING);
288     EXPECT_EQ(sqlite3_extended_errcode(compDb), SQLITE_WARNING_NOTCOMPRESSDB);
289     sqlite3_close_v2(compDb);
290 
291     std::string dbFileUri = "file:";
292     dbFileUri += TEST_DB;
293     dbFileUri += "?vfs=compressvfs";
294     EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &compDb), SQLITE_WARNING);
295     EXPECT_EQ(sqlite3_extended_errcode(compDb), SQLITE_WARNING_NOTCOMPRESSDB);
296     sqlite3_close_v2(compDb);
297 }
298 
299 /**
300  * @tc.name: CompressTest003
301  * @tc.desc: Test to backup db and enable page compression on dest db
302  * @tc.type: FUNC
303  */
304 HWTEST_F(SQLiteCompressTest, CompressTest003, TestSize.Level0)
305 {
306     if (!IsSupportPageCompress()) {
307         GTEST_SKIP() << "Current testcase is not compatible";
308     }
309     /**
310      * @tc.steps: step1. Compress db using Backup function:sqlite3_backup_step
311      * @tc.expected: step1. Execute successfully
312      */
313     std::string dbPath1 = TEST_DIR "/compresstest0030.db";
314     sqlite3 *compDb = nullptr;
315     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
316         SQLITE_OK);
317     UtBackupDatabase(db_, compDb);
318     sqlite3_close_v2(compDb);
319     UtCheckDb(dbPath1);
320 
321     /**
322      * @tc.steps: step2. Compress db using new Backup function:sqlite3_compressdb_backup
323      * @tc.expected: step2. Execute successfully
324      */
325     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
326     std::string dbPath2 = TEST_DIR "/restore0031.db";
327     EXPECT_EQ(sqlite3_compressdb_backup(compDb, dbPath2.c_str()), SQLITE_DONE);
328     sqlite3_close_v2(compDb);
329     UtCheckDb(dbPath2, TEST_PRESET_TABLE_COUNT + 1);
330 }
331 
332 /**
333  * @tc.name: CompressTest004
334  * @tc.desc: Test to create new db and enable page compression
335  * @tc.type: FUNC
336  */
337 HWTEST_F(SQLiteCompressTest, CompressTest004, TestSize.Level0)
338 {
339     if (!IsSupportPageCompress()) {
340         GTEST_SKIP() << "Current testcase is not compatible";
341     }
342     /**
343      * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2
344      * @tc.expected: step1. Execute successfully
345      */
346     std::string dbPath1 = TEST_DIR "/compresstest0040.db";
347     sqlite3 *compDb = nullptr;
348     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
349         SQLITE_OK);
350     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
351     EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
352     /**
353      * @tc.steps: step2. Set meta double write enable through Pragma statement
354      * @tc.expected: step2. Execute successfully
355      */
356     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK);
357     /**
358      * @tc.steps: step3. Set journal mode as WAL through Pragma statement
359      * @tc.expected: step3. Execute successfully
360      */
361     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK);
362     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_PHONE.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
363     /**
364      * @tc.steps: step4. Set WAL file persist
365      * @tc.expected: step4. Execute successfully
366      */
367     int code = 1;
368     EXPECT_EQ(sqlite3_file_control(compDb, "main", SQLITE_FCNTL_PERSIST_WAL, &code), SQLITE_OK);
369     sqlite3_close_v2(compDb);
370     /**
371      * @tc.steps: step5. Check result, files should exist
372      * @tc.expected: step4. Execute successfully
373      */
374     std::string wal = dbPath1 + "-walcompress";
375     std::string shm = dbPath1 + "-shmcompress";
376     std::string dwr = dbPath1 + "-dwr";
377     EXPECT_TRUE(Common::IsFileExist(wal.c_str()));
378     EXPECT_TRUE(Common::IsFileExist(shm.c_str()));
379     EXPECT_TRUE(Common::IsFileExist(dwr.c_str()));
380 }
381 
382 /**
383  * @tc.name: CompressTest005
384  * @tc.desc: Test to create new db and get db/wal/journal filename
385  * @tc.type: FUNC
386  */
387 HWTEST_F(SQLiteCompressTest, CompressTest005, TestSize.Level0)
388 {
389     if (!IsSupportPageCompress()) {
390         GTEST_SKIP() << "Current testcase is not compatible";
391     }
392     /**
393      * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2
394      * @tc.expected: step1. Execute successfully
395      */
396     std::string dbPath1 = TEST_DIR "/compresstest0050.db";
397     sqlite3 *compDb = nullptr;
398     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
399         SQLITE_OK);
400     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
401     EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
402     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK);
403     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK);
404     /**
405      * @tc.steps: step2. Try to get db/wal/journal filename
406      * @tc.expected: step2. Execute successfully
407      */
408     const char *db = sqlite3_db_filename(compDb, "main");
409     const char *wal = sqlite3_filename_wal(db);
410     const char *journal = sqlite3_filename_journal(db);
411     std::string str = db;
412     int n = str.find("/compresstest0050.db");
413     EXPECT_TRUE(n != string::npos);
414     EXPECT_TRUE(n==(str.size() - strlen("/compresstest0050.db")));
415     str = wal;
416     n = str.find("/compresstest0050.db-walcompress");
417     EXPECT_TRUE(n != string::npos);
418     EXPECT_TRUE(n==(str.size() - strlen("/compresstest0050.db-walcompress")));
419     str = journal;
420     n = str.find("/compresstest0050.db-journalcompress");
421     EXPECT_TRUE(n != string::npos);
422     EXPECT_TRUE(n==(str.size() - strlen("/compresstest0050.db-journalcompress")));
423     sqlite3_close_v2(compDb);
424 }
425 
426 /**
427  * @tc.name: CompressTest006
428  * @tc.desc: Test to create new db and open multi sqlite3 handler at the same time
429  * @tc.type: FUNC
430  */
431 HWTEST_F(SQLiteCompressTest, CompressTest006, TestSize.Level0)
432 {
433     if (!IsSupportPageCompress()) {
434         GTEST_SKIP() << "Current testcase is not compatible";
435     }
436     /**
437      * @tc.steps: step1. Create a brand new db while page compression enabled with sqlite3_open_v2
438      * @tc.expected: step1. Execute successfully
439      */
440     std::string dbPath1 = TEST_DIR "/compresstest0060.db";
441     sqlite3 *compDb = nullptr;
442     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
443         SQLITE_OK);
444     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK);
445     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK);
446     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
447     EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
448     /**
449      * @tc.steps: step2. Open multi sqlite3 which enable page compression at the same time
450      * @tc.expected: step2. Execute successfully
451      */
452     sqlite3 *compDb1 = nullptr;
453     sqlite3 *compDb2 = nullptr;
454     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb1, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
455         SQLITE_OK);
456     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb2, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
457         SQLITE_OK);
458     sqlite3_close_v2(compDb2);
459     sqlite3_close_v2(compDb1);
460     sqlite3_close_v2(compDb);
461 }
462 
463 /**
464  * @tc.name: CompressTest007
465  * @tc.desc: Test to create brand new db
466  * @tc.type: FUNC
467  */
468 HWTEST_F(SQLiteCompressTest, CompressTest007, TestSize.Level0)
469 {
470     if (!IsSupportPageCompress()) {
471         GTEST_SKIP() << "Current testcase is not compatible";
472     }
473     /**
474      * @tc.steps: step1. Create a brand new db while page compression enabled through sqlite3_open_v2
475      * @tc.expected: step1. Execute successfully
476      */
477     std::string dbPath1 = TEST_DIR "/compresstest007.db";
478     sqlite3 *compDb = nullptr;
479     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &compDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
480         SQLITE_OK);
481     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK);
482     EXPECT_EQ(sqlite3_exec(compDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK);
483     EXPECT_EQ(sqlite3_exec(compDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
484     EXPECT_EQ(sqlite3_exec(compDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
485     int persistMode = 1;
486     EXPECT_EQ(sqlite3_file_control(compDb, "main", SQLITE_FCNTL_PERSIST_WAL, &persistMode), SQLITE_OK);
487     sqlite3_close_v2(compDb);
488     /**
489      * @tc.steps: step5. Check result, files should exist
490      * @tc.expected: step4. Execute successfully
491      */
492     std::string wal = dbPath1 + "-walcompress";
493     std::string shm = dbPath1 + "-shmcompress";
494     std::string dwr = dbPath1 + "-dwr";
495     std::string lock = dbPath1 + "-lockcompress";
496     EXPECT_TRUE(Common::IsFileExist(wal.c_str()));
497     EXPECT_TRUE(Common::IsFileExist(shm.c_str()));
498     EXPECT_TRUE(Common::IsFileExist(dwr.c_str()));
499     EXPECT_TRUE(Common::IsFileExist(lock.c_str()));
500 }
501 
502 /**
503  * @tc.name: CompressTest008
504  * @tc.desc: Test to create brand new db disabled compression
505  * @tc.type: FUNC
506  */
507 HWTEST_F(SQLiteCompressTest, CompressTest008, TestSize.Level0)
508 {
509     /**
510      * @tc.steps: step1. Create a brand new db while page compression disabled
511      * @tc.expected: step1. Execute successfully
512      */
513     std::string dbPath1 = TEST_DIR "/test008.db";
514     sqlite3 *db = nullptr;
515     EXPECT_EQ(sqlite3_open_v2(dbPath1.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr),
516         SQLITE_OK);
517     EXPECT_EQ(sqlite3_exec(db, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK);
518     EXPECT_EQ(sqlite3_exec(db, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK);
519     EXPECT_EQ(sqlite3_exec(db, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
520     EXPECT_EQ(sqlite3_exec(db, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
521     int persistMode = 1;
522     EXPECT_EQ(sqlite3_file_control(db, "main", SQLITE_FCNTL_PERSIST_WAL, &persistMode), SQLITE_OK);
523     sqlite3_close_v2(db);
524     /**
525      * @tc.steps: step5. Check result, files should exist except lock file
526      * @tc.expected: step4. Execute successfully
527      */
528     std::string wal = dbPath1 + "-wal";
529     std::string shm = dbPath1 + "-shm";
530     std::string dwr = dbPath1 + "-dwr";
531     std::string lock = dbPath1 + "-lockcompress";
532     EXPECT_TRUE(Common::IsFileExist(wal.c_str()));
533     EXPECT_TRUE(Common::IsFileExist(shm.c_str()));
534     EXPECT_TRUE(Common::IsFileExist(dwr.c_str()));
535     EXPECT_FALSE(Common::IsFileExist(lock.c_str()));
536 }
537 
538 /**
539  * @tc.name: CompressTest009
540  * @tc.desc: Test to open an non-cmopress db through vfs option:compress
541  * @tc.type: FUNC
542  */
543 HWTEST_F(SQLiteCompressTest, CompressTest009, TestSize.Level0)
544 {
545     if (!IsSupportPageCompress()) {
546         GTEST_SKIP() << "Current testcase is not compatible";
547     }
548     /**
549      * @tc.steps: step1. Open the exist db through vfs option:compressvfs using SQLITE_OPEN_READONLY
550      * @tc.expected: step1. Execute successfully
551      */
552     sqlite3 *db1 = nullptr;
553     EXPECT_EQ(sqlite3_open_v2(TEST_DB, &db1, SQLITE_OPEN_READONLY, "compressvfs"), SQLITE_WARNING);
554     // lock file not exist, return not a compress db
555     EXPECT_EQ(sqlite3_extended_errcode(db1), SQLITE_WARNING_NOTCOMPRESSDB);
556     sqlite3_close_v2(db1);
557 }
558 
559 /**
560  * @tc.name: CompressTest010
561  * @tc.desc: Test to insert data while transaction executing
562  * @tc.type: FUNC
563  */
564 HWTEST_F(SQLiteCompressTest, CompressTest010, TestSize.Level0)
565 {
566     if (!IsSupportPageCompress()) {
567         GTEST_SKIP() << "Current testcase is not compatible";
568     }
569     /**
570      * @tc.steps: step1. Create a brand new db while page compression enabled
571      * @tc.expected: step1. Execute successfully
572      */
573     std::string dbPath = TEST_DIR "/compresstest010.db";
574     UtPresetDb(dbPath, "compressvfs");
575     /**
576      * @tc.steps: step2. Open the db used to begin transaction, delete 5 entries
577      * @tc.expected: step2. Execute successfully
578      */
579     sqlite3 *db1 = nullptr;
580     EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db1, SQLITE_OPEN_READWRITE, "compressvfs"), SQLITE_OK);
581     EXPECT_EQ(sqlite3_exec(db1, "BEGIN;", nullptr, nullptr, nullptr), SQLITE_OK);
582     // delete data from 996 ~ 1000
583     EXPECT_EQ(sqlite3_exec(db1, "DELETE FROM salary WHERE entryId > 995;", nullptr, nullptr, nullptr), SQLITE_OK);
584     /**
585      * @tc.steps: step3. Open another db used to insert data, before commit transaction
586      * @tc.expected: step3. Execute successfully
587      */
588     sqlite3 *db2 = nullptr;
589     EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db2, SQLITE_OPEN_READWRITE, "compressvfs"), SQLITE_OK);
590     static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary123"
591         "(entryId INTEGER PRIMARY KEY, entryName Text, salary REAL, class INTEGER);";
592     EXPECT_EQ(sqlite3_exec(db2, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_BUSY);
593     sqlite3_close_v2(db2);
594     EXPECT_EQ(sqlite3_exec(db1, "COMMIT;", nullptr, nullptr, nullptr), SQLITE_OK);
595     sqlite3_close_v2(db1);
596 }
597 
598 /**
599  * @tc.name: CompressTest011
600  * @tc.desc: Test to check lock file name
601  * @tc.type: FUNC
602  */
603 HWTEST_F(SQLiteCompressTest, CompressTest011, TestSize.Level0)
604 {
605     if (!IsSupportPageCompress()) {
606         GTEST_SKIP() << "Current testcase is not compatible";
607     }
608     /**
609      * @tc.steps: step1. Get lock file name from non-compress db connection
610      * @tc.expected: step1. Execute successfully
611      */
612     const char *dbName = sqlite3_db_filename(db_, "main");
613     const char *walName = sqlite3_filename_wal(dbName);
614     const char *lockName = walName + strlen(walName) + 1;
615     std::string expectLockFilenameSuffix = "/sqlitecompresstest/test.db";
616     std::string lockPathStr = lockName;
617     EXPECT_TRUE(lockPathStr.find(expectLockFilenameSuffix) != std::string::npos);
618     /**
619      * @tc.steps: step2. Create a brand new db while page compression enabled, check lock filename
620      * @tc.expected: step2. Execute successfully
621      */
622     std::string dbPath = TEST_DIR "/compresstest011.db";
623     UtPresetDb(dbPath, "compressvfs");
624     sqlite3 *db1 = nullptr;
625     EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db1, SQLITE_OPEN_READWRITE, "compressvfs"), SQLITE_OK);
626     EXPECT_EQ(sqlite3_exec(db1, UT_DDL_CREATE_PHONE.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
627     const char *dbName1 = sqlite3_db_filename(db1, "main");
628     const char *walName1 = sqlite3_filename_wal(dbName1);
629     const char *lockName1 = walName1 + strlen(walName1) + 1;
630     std::string expectLockFilenameSuffix1 = "/sqlitecompresstest/compresstest011.db-lockcompress";
631     lockPathStr = lockName1;
632     EXPECT_TRUE(lockPathStr.find(expectLockFilenameSuffix1) != std::string::npos);
633     sqlite3_close_v2(db1);
634 }
635 
636 /**
637  * @tc.name: CompressTest012
638  * @tc.desc: Test to check lock file name
639  * @tc.type: FUNC
640  */
641 HWTEST_F(SQLiteCompressTest, CompressTest012, TestSize.Level0)
642 {
643     if (!IsSupportPageCompress()) {
644         GTEST_SKIP() << "Current testcase is not compatible";
645     }
646     /**
647      * @tc.steps: step1. Create brand new db as main db, and a compress db as slave
648      * @tc.expected: step1. Execute successfully
649      */
650     std::string dbPath = TEST_DIR "/test011.db";
651     UtPresetDb(dbPath, "");
652     sqlite3 *db = nullptr;
653     EXPECT_EQ(sqlite3_open_v2(dbPath.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr), SQLITE_OK);
654     std::string slavePath = TEST_DIR "/test011_slave.db";
655     sqlite3 *slaveDb = nullptr;
656     EXPECT_EQ(sqlite3_open_v2(slavePath.c_str(), &slaveDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "compressvfs"),
657         SQLITE_OK);
658     EXPECT_EQ(sqlite3_exec(slaveDb, "PRAGMA meta_double_write=enabled;", nullptr, nullptr, nullptr), SQLITE_OK);
659     EXPECT_EQ(sqlite3_exec(slaveDb, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr), SQLITE_OK);
660     EXPECT_EQ(sqlite3_exec(slaveDb, UT_DDL_CREATE_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
661     EXPECT_EQ(sqlite3_exec(slaveDb, UT_DML_INSERT_DEMO.c_str(), nullptr, nullptr, nullptr), SQLITE_OK);
662     int persistMode = 1;
663     EXPECT_EQ(sqlite3_file_control(slaveDb, "main", SQLITE_FCNTL_PERSIST_WAL, &persistMode), SQLITE_OK);
664     UtBackupDatabase(db, slaveDb);
665     /**
666      * @tc.steps: step2. Insert serveral data into slave db, then backup again
667      * @tc.expected: step2. Execute successfully
668      */
669     static const char *UT_INSERT_DATA = "INSERT INTO salary(entryId, entryName, salary, class) VALUES(?,?,?,?);";
670     sqlite3_stmt *insertStmt = NULL;
671     EXPECT_EQ(sqlite3_prepare_v2(slaveDb, UT_INSERT_DATA, -1, &insertStmt, NULL), SQLITE_OK);
672     for (int i = 0; i < 100; i++) {  // 100 means the total number of insert data
673         sqlite3_bind_int(insertStmt, 1, i + 20000);  // 20000 is the begining of entryId to insert
674         sqlite3_bind_text(insertStmt, 2, "salary-entry-name", -1, SQLITE_STATIC);  // 2 is the seq number of 2nd field
675         sqlite3_bind_double(insertStmt, 3, i);  // 3 is the seq number of 3rd field
676         sqlite3_bind_int(insertStmt, 4, i + 1);  // 4 is the seq number of 4th field
677         EXPECT_EQ(sqlite3_step(insertStmt), SQLITE_DONE);
678         sqlite3_reset(insertStmt);
679     }
680     sqlite3_finalize(insertStmt);
681     // Backup again, all data insert above should be covered
682     UtBackupDatabase(db, slaveDb);
683     sqlite3_close_v2(slaveDb);
684     sqlite3_close_v2(db);
685     UtCheckPresetDb(slavePath, "compressvfs");
686 }
687 
688 }  // namespace Test
689