• 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 <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