• 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 <string>
21 #include <unistd.h>
22 
23 #include "common.h"
24 #include "sqlite3sym.h"
25 
26 using namespace testing::ext;
27 using namespace UnitTest::SQLiteTest;
28 
29 #define TEST_DIR "./sqlitebinlogtest"
30 #define TEST_DB (TEST_DIR "/test.db")
31 #define TEST_BACKUP_DB (TEST_DIR "/test_bak.db")
32 #define TEST_DATA_COUNT 1000
33 #define TEST_DATA_REAL 16.1
34 
UtSqliteLogPrint(const void * data,int err,const char * msg)35 static void UtSqliteLogPrint(const void *data, int err, const char *msg)
36 {
37     std::cout << "SqliteBinlogTest SQLite xLog err:" << err << ", msg:" << msg << std::endl;
38 }
39 
UtPresetDb(const char * dbFile)40 static void UtPresetDb(const char *dbFile)
41 {
42     /**
43      * @tc.steps: step1. Prepare compressed db
44      * @tc.expected: step1. Execute successfully
45      */
46     sqlite3 *db = NULL;
47     std::string dbFileUri = "file:";
48     dbFileUri += dbFile;
49     EXPECT_EQ(sqlite3_open(dbFileUri.c_str(), &db), SQLITE_OK);
50     /**
51      * @tc.steps: step2. Create table and fill it, make db size big enough
52      * @tc.expected: step2. Execute successfully
53      */
54     static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary("
55         "entryId INTEGER PRIMARY KEY,"
56         "entryName Text,"
57         "salary REAL,"
58         "class INTEGER);";
59     EXPECT_EQ(sqlite3_exec(db, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_OK);
60     sqlite3_close(db);
61 }
62 
UtEnableBinlog(sqlite3 * db)63 static void UtEnableBinlog(sqlite3 *db)
64 {
65     Sqlite3BinlogConfig cfg = {
66         .mode = Sqlite3BinlogMode::ROW,
67         .fullCallbackThreshold = 2,
68         .maxFileSize = 1024 * 1024 * 4,
69         .xErrorCallback = nullptr,
70         .xLogFullCallback = nullptr,
71         .callbackCtx = nullptr,
72     };
73     EXPECT_EQ(sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_BINLOG, &cfg), SQLITE_OK);
74 }
75 
UtQueryResult(void * data,int argc,char ** argv,char ** azColName)76 static int UtQueryResult(void *data, int argc, char **argv, char **azColName)
77 {
78     int count = *static_cast<int *>(data);
79     *static_cast<int *>(data) = count + 1;
80     // 2 means 2 fields, entryId, entryName
81     EXPECT_EQ(argc, 2);
82     return SQLITE_OK;
83 }
84 
UtGetRecordCount(sqlite3 * db)85 static int UtGetRecordCount(sqlite3 *db)
86 {
87     int count = 0;
88     EXPECT_EQ(sqlite3_exec(db, "SELECT entryId, entryName FROM salary;", UtQueryResult, &count, nullptr), SQLITE_OK);
89     return count;
90 }
91 
92 class SqliteBinlogTest : public testing::Test {
93 public:
94     static void SetUpTestCase(void);
95     static void TearDownTestCase(void);
96     void SetUp();
97     void TearDown();
98 };
99 
SetUpTestCase(void)100 void SqliteBinlogTest::SetUpTestCase(void)
101 {
102     Common::RemoveDir(TEST_DIR);
103     Common::MakeDir(TEST_DIR);
104 }
105 
TearDownTestCase(void)106 void SqliteBinlogTest::TearDownTestCase(void)
107 {
108 }
109 
SetUp(void)110 void SqliteBinlogTest::SetUp(void)
111 {
112     std::string command = "rm -rf ";
113     command += TEST_DIR "/*";
114     system(command.c_str());
115     sqlite3_config(SQLITE_CONFIG_LOG, &UtSqliteLogPrint, NULL);
116     UtPresetDb(TEST_DB);
117     UtPresetDb(TEST_BACKUP_DB);
118 }
119 
TearDown(void)120 void SqliteBinlogTest::TearDown(void)
121 {
122     sqlite3_config(SQLITE_CONFIG_LOG, NULL, NULL);
123 }
124 
125 /**
126  * @tc.name: BinlogReplayTest001
127  * @tc.desc: Test replay sql with test value that has single quote
128  * @tc.type: FUNC
129  */
130 HWTEST_F(SqliteBinlogTest, BinlogReplayTest001, TestSize.Level0)
131 {
132     /**
133      * @tc.steps: step1. open db and set binlog
134      * @tc.expected: step1. ok
135      */
136     sqlite3 *db = NULL;
137     EXPECT_EQ(sqlite3_open_v2(TEST_DB, &db,
138         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr), SQLITE_OK);
139     ASSERT_NE(db, nullptr);
140     UtEnableBinlog(db);
141     /**
142      * @tc.steps: step2. Insert records with single quotes
143      * @tc.expected: step2. Execute successfully
144      */
145     static const char *UT_SQL_INSERT_DATA =
146         "INSERT INTO salary(entryId, entryName, salary, class) VALUES(?,?,?,?);";
147     sqlite3_stmt *insertStmt = NULL;
148     EXPECT_EQ(sqlite3_prepare_v2(db, UT_SQL_INSERT_DATA, -1, &insertStmt, NULL), SQLITE_OK);
149     for (int i = 0; i < TEST_DATA_COUNT; i++) {
150         // bind parameters, 1, 2, 3, 4 are sequence number of fields
151         sqlite3_bind_int(insertStmt, 1, i + 1);
152         sqlite3_bind_text(insertStmt, 2, "'salary-entry-name'", -1, SQLITE_STATIC);
153         sqlite3_bind_double(insertStmt, 3, TEST_DATA_REAL + i);
154         sqlite3_bind_int(insertStmt, 4, i + 1);
155         EXPECT_EQ(sqlite3_step(insertStmt), SQLITE_DONE);
156         sqlite3_reset(insertStmt);
157     }
158     sqlite3_finalize(insertStmt);
159     /**
160      * @tc.steps: step3. binlog replay to write into backup db
161      * @tc.expected: step3. Return SQLITE_OK
162      */
163     sqlite3 *backupDb = NULL;
164     EXPECT_EQ(sqlite3_open_v2(TEST_BACKUP_DB, &backupDb,
165         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr), SQLITE_OK);
166     ASSERT_NE(backupDb, nullptr);
167     EXPECT_EQ(sqlite3_replay_binlog(db, backupDb), SQLITE_OK);
168     /**
169      * @tc.steps: step4. check db count
170      * @tc.expected: step4. both db have TEST_DATA_COUNT
171      */
172     EXPECT_EQ(UtGetRecordCount(db), TEST_DATA_COUNT);
173     EXPECT_EQ(UtGetRecordCount(backupDb), TEST_DATA_COUNT);
174     sqlite3_close_v2(db);
175     sqlite3_close_v2(backupDb);
176 }
177