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