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 <cstdio>
20 #include <fstream>
21 #include <string>
22 #include <unistd.h>
23 #include <vector>
24
25 #include "sqlite3sym.h"
26
27 using namespace testing::ext;
28
29 #define TEST_DIR "./sqlitetest"
30 #define TEST_DB (TEST_DIR "/test.db")
31 #define TEST_DATA_COUNT 1000
32 #define TEST_DATA_REAL 16.1
33
UtSqliteLogPrint(const void * data,int err,const char * msg)34 static void UtSqliteLogPrint(const void *data, int err, const char *msg)
35 {
36 std::cout << "LibSQLiteTest SQLite xLog err:" << err << ", msg:" << msg << std::endl;
37 }
38
UtPresetDb(const char * dbFile)39 static void UtPresetDb(const char *dbFile)
40 {
41 /**
42 * @tc.steps: step1. Prepare db used to simulate corrupted
43 * @tc.expected: step1. Execute successfully
44 */
45 sqlite3 *db = NULL;
46 std::string dbFileUri = "file:";
47 dbFileUri += dbFile;
48 dbFileUri += "?vfs=cksmvfs";
49 EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &db), SQLITE_OK);
50 /**
51 * @tc.steps: step1. Enable cksumvfs using PRAGMA checksum_persist_enable,
52 * @tc.expected: step1. Execute successfully
53 */
54 static const char *UT_PRAGMA_CKSUM_ENABLE = "PRAGMA checksum_persist_enable=ON";
55 EXPECT_EQ(sqlite3_exec(db, UT_PRAGMA_CKSUM_ENABLE, NULL, NULL, NULL), SQLITE_OK);
56 /**
57 * @tc.steps: step1. Create table and fill it, make db size big enough
58 * @tc.expected: step1. Execute successfully
59 */
60 static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary("
61 "entryId INTEGER PRIMARY KEY,"
62 "entryName Text,"
63 "salary REAL,"
64 "class INTEGER);";
65 EXPECT_EQ(sqlite3_exec(db, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_OK);
66 static const char *UT_SQL_INSERT_DATA = "INSERT INTO salary(entryId, entryName, salary, class) VALUES(?,?,?,?);";
67 sqlite3_stmt *insertStmt = NULL;
68 EXPECT_EQ(sqlite3_prepare_v2(db, UT_SQL_INSERT_DATA, -1, &insertStmt, NULL), SQLITE_OK);
69 for (int i = 0; i < TEST_DATA_COUNT; i++) {
70 // bind parameters, 1, 2, 3, 4 are sequence number of fields
71 sqlite3_bind_int(insertStmt, 1, i + 1);
72 sqlite3_bind_text(insertStmt, 2, "salary-entry-name", -1, SQLITE_STATIC);
73 sqlite3_bind_double(insertStmt, 3, TEST_DATA_REAL + i);
74 sqlite3_bind_int(insertStmt, 4, i + 1);
75 EXPECT_EQ(sqlite3_step(insertStmt), SQLITE_DONE);
76 sqlite3_reset(insertStmt);
77 }
78 sqlite3_finalize(insertStmt);
79 sqlite3_close(db);
80 }
81
82 class LibSQLiteTest : public testing::Test {
83 public:
84 static void SetUpTestCase(void);
85 static void TearDownTestCase(void);
86 void SetUp();
87 void TearDown();
88 };
89
SetUpTestCase(void)90 void LibSQLiteTest::SetUpTestCase(void)
91 {
92 // permission 0770
93 mkdir(TEST_DIR, 0770);
94 }
95
TearDownTestCase(void)96 void LibSQLiteTest::TearDownTestCase(void)
97 {
98 }
99
SetUp(void)100 void LibSQLiteTest::SetUp(void)
101 {
102 unlink(TEST_DB);
103 sqlite3_config(SQLITE_CONFIG_LOG, &UtSqliteLogPrint, NULL);
104 EXPECT_EQ(sqlite3_register_cksumvfs(NULL), SQLITE_OK);
105 UtPresetDb(TEST_DB);
106 }
107
TearDown(void)108 void LibSQLiteTest::TearDown(void)
109 {
110 EXPECT_EQ(sqlite3_unregister_cksumvfs(), SQLITE_OK);
111 sqlite3_config(SQLITE_CONFIG_LOG, NULL, NULL);
112 }
113
UtCorruptDb(const std::string & dbFile,size_t offset,size_t len,unsigned char ch)114 static void UtCorruptDb(const std::string &dbFile, size_t offset, size_t len, unsigned char ch)
115 {
116 std::fstream f;
117 f.open(dbFile.c_str());
118 f.seekp(offset, std::ios::beg);
119 std::vector<char> buf(len, ch);
120 f.write(buf.data(), len);
121 f.close();
122 }
123
UtSqliteExecCallback(void * data,int argc,char ** argv,char ** azColName)124 static int UtSqliteExecCallback(void *data, int argc, char **argv, char **azColName)
125 {
126 std::cout << (const char *)data << " result:" << std::endl;
127 for (int i = 0; i < argc; i++) {
128 std::cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << std::endl;
129 }
130 std::cout << std::endl;
131 return 0;
132 }
133
134 /**
135 * @tc.name: Lib_SQLite_Test_001
136 * @tc.desc: Test to enable cksumvfs.
137 * @tc.type: FUNC
138 */
139 HWTEST_F(LibSQLiteTest, Lib_SQLite_Test_001, TestSize.Level0)
140 {
141 /**
142 * @tc.steps: step1. Corrupt db file, reopen and make a quick check
143 * @tc.expected: step1. Return SQLITE_IOERR, as meta table info corrupted
144 */
145 sqlite3 *db = NULL;
146 UtCorruptDb(TEST_DB, 3 * 4096 + 1000, 1, 0xFF); // 3 * 4096 + 1000 is the target page's position in file
147 std::string dbFileUri = "file:";
148 dbFileUri += TEST_DB;
149 dbFileUri += "?vfs=cksmvfs";
150 EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &db), SQLITE_OK);
151 static const char *UT_SQL_SELECT_TABLE = "SELECT COUNT(*) FROM salary WHERE entryId=3;";
152 EXPECT_EQ(sqlite3_exec(db, UT_SQL_SELECT_TABLE, NULL, NULL, NULL), SQLITE_OK);
153 /**
154 * @tc.steps: step2. Disable checksum_verification, re-quary the table
155 * @tc.expected: step2. Execute successfully
156 */
157 static const char *UT_PRAGMA_DISABLE_CKSUM = "PRAGMA checksum_verification=OFF;";
158 EXPECT_EQ(sqlite3_exec(db, UT_PRAGMA_DISABLE_CKSUM, UtSqliteExecCallback, (void *)"PRAGMA", NULL), SQLITE_OK);
159 EXPECT_EQ(sqlite3_exec(db, UT_SQL_SELECT_TABLE, NULL, NULL, NULL), SQLITE_OK);
160 /**
161 * @tc.steps: step2. Disable checksum_verification, re-quary the table
162 * @tc.expected: step2. Return SQLITE_OK, as page already in the cache
163 */
164 static const char *UT_PRAGMA_ENABLE_CKSUM = "PRAGMA checksum_verification=ON;";
165 EXPECT_EQ(sqlite3_exec(db, UT_PRAGMA_ENABLE_CKSUM, UtSqliteExecCallback, (void *)"PRAGMA", NULL), SQLITE_OK);
166 EXPECT_EQ(sqlite3_exec(db, UT_SQL_SELECT_TABLE, NULL, NULL, NULL), SQLITE_OK);
167 sqlite3_close(db);
168 }
169
170 /**
171 * @tc.name: Lib_SQLite_Test_002
172 * @tc.desc: Test to enable and disable checksum_verification.
173 * @tc.type: FUNC
174 */
175 HWTEST_F(LibSQLiteTest, Lib_SQLite_Test_002, TestSize.Level0)
176 {
177 /**
178 * @tc.steps: step1. Corrupt db file, reopen and make a quick check
179 * @tc.expected: step1. Return SQLITE_IOERR, as meta table info corrupted
180 */
181 sqlite3 *db = NULL;
182 UtCorruptDb(TEST_DB, 3 * 4096 + 1000, 1, 0xFF); // 3 * 4096 + 1000 is the target page's position in file
183 std::string dbFileUri = "file:";
184 dbFileUri += TEST_DB;
185 dbFileUri += "?vfs=cksmvfs";
186 EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &db), SQLITE_OK);
187 static const char *UT_SQL_SELECT_TABLE_1 = "SELECT COUNT(*) FROM salary WHERE entryId=3;";
188 EXPECT_EQ(sqlite3_exec(db, UT_SQL_SELECT_TABLE_1, NULL, NULL, NULL), SQLITE_OK);
189 /**
190 * @tc.steps: step2. Disable checksum_verification, re-check the table
191 * @tc.expected: step2. Execute successfully
192 */
193 static const char *UT_PRAGMA_DISABLE_CKSUM = "PRAGMA checksum_verification=OFF;";
194 EXPECT_EQ(sqlite3_exec(db, UT_PRAGMA_DISABLE_CKSUM, UtSqliteExecCallback, (void *)"PRAGMA", NULL), SQLITE_OK);
195 EXPECT_EQ(sqlite3_exec(db, UT_SQL_SELECT_TABLE_1, NULL, NULL, NULL), SQLITE_OK);
196 /**
197 * @tc.steps: step3. Enable checksum_verification again, re-quary the user table
198 * @tc.expected: step3. Return SQLITE_OK, as page already in the cache
199 */
200 UtCorruptDb(TEST_DB, 7 * 4096 + 1000, 1, 0xFF); // 7 * 4096 + 1000 is the target page's position in file
201 static const char *UT_SQL_SELECT_TABLE_2 = "SELECT COUNT(*) FROM salary WHERE entryId=500;";
202 static const char *UT_PRAGMA_ENABLE_CKSUM = "PRAGMA checksum_verification=ON;";
203 EXPECT_EQ(sqlite3_exec(db, UT_PRAGMA_ENABLE_CKSUM, UtSqliteExecCallback, (void *)"PRAGMA", NULL), SQLITE_OK);
204 EXPECT_EQ(sqlite3_exec(db, UT_SQL_SELECT_TABLE_2, NULL, NULL, NULL), SQLITE_OK);
205 sqlite3_close(db);
206 }
207