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
16 #include "distributeddb_tools_unit_test.h"
17 #include "platform_specific.h"
18
19 using namespace DistributedDB;
20
21 namespace DistributedDBUnitTest {
GetCurrentDir(std::string & dir)22 int DistributedDBToolsUnitTest::GetCurrentDir(std::string &dir)
23 {
24 static const int maxFileLength = 1024;
25 dir = "";
26 char buffer[maxFileLength] = {0};
27 int length = readlink("/proc/self/exe", buffer, maxFileLength);
28 if (length < 0 || length >= maxFileLength) {
29 LOGE("read directory err length:%d", length);
30 return -E_LENGTH_ERROR;
31 }
32 LOGD("DIR = %s", buffer);
33 dir = buffer;
34 if (dir.rfind("/") == std::string::npos && dir.rfind("\\") == std::string::npos) {
35 LOGE("current patch format err");
36 return -E_INVALID_PATH;
37 }
38
39 if (dir.rfind("/") != std::string::npos) {
40 dir.erase(dir.rfind("/") + 1);
41 }
42 return E_OK;
43 }
44
TestDirInit(std::string & dir)45 void DistributedDBToolsUnitTest::TestDirInit(std::string &dir)
46 {
47 if (GetCurrentDir(dir) != E_OK) {
48 dir = "/";
49 }
50
51 dir.append("testDbDir");
52 DIR *dirTmp = opendir(dir.c_str());
53 if (dirTmp == nullptr) {
54 if (OS::MakeDBDirectory(dir) != 0) {
55 LOGI("MakeDirectory err!");
56 dir = "/";
57 return;
58 }
59 } else {
60 closedir(dirTmp);
61 }
62 }
63
RemoveTestDbFiles(const std::string & dir)64 int DistributedDBToolsUnitTest::RemoveTestDbFiles(const std::string &dir)
65 {
66 bool isExisted = OS::CheckPathExistence(dir);
67 if (!isExisted) {
68 return E_OK;
69 }
70
71 int nFile = 0;
72 std::string dirName;
73 struct dirent *direntPtr = nullptr;
74 DIR *dirPtr = opendir(dir.c_str());
75 if (dirPtr == nullptr) {
76 LOGE("opendir error!");
77 return -E_INVALID_PATH;
78 }
79 while (true) {
80 direntPtr = readdir(dirPtr);
81 // condition to exit the loop
82 if (direntPtr == nullptr) {
83 break;
84 }
85 // only remove all *.db files
86 std::string str(direntPtr->d_name);
87 if (str == "." || str == "..") {
88 continue;
89 }
90 dirName.clear();
91 dirName.append(dir).append("/").append(str);
92 if (direntPtr->d_type == DT_DIR) {
93 RemoveTestDbFiles(dirName);
94 rmdir(dirName.c_str());
95 } else if (remove(dirName.c_str()) != 0) {
96 LOGI("remove file: %s failed!", dirName.c_str());
97 continue;
98 }
99 nFile++;
100 }
101 closedir(dirPtr);
102 LOGI("Total %d test db files are removed!", nFile);
103 return 0;
104 }
105
CreateDataBase(const std::string & dbUri)106 sqlite3 *RelationalTestUtils::CreateDataBase(const std::string &dbUri)
107 {
108 LOGD("Create database: %s", dbUri.c_str());
109 sqlite3 *db = nullptr;
110 if (int r = sqlite3_open_v2(dbUri.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
111 LOGE("Open database [%s] failed. %d", dbUri.c_str(), r);
112 if (db != nullptr) {
113 (void)sqlite3_close_v2(db);
114 db = nullptr;
115 }
116 }
117 return db;
118 }
119
ExecSql(sqlite3 * db,const std::string & sql)120 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql)
121 {
122 if (db == nullptr || sql.empty()) {
123 return -E_INVALID_ARGS;
124 }
125 char *errMsg = nullptr;
126 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
127 if (errCode != SQLITE_OK && errMsg != nullptr) {
128 LOGE("Execute sql failed. %d err: %s", errCode, errMsg);
129 }
130 sqlite3_free(errMsg);
131 return errCode;
132 }
133
ExecSql(sqlite3 * db,const std::string & sql,const std::function<int (sqlite3_stmt *)> & bindCallback,const std::function<int (sqlite3_stmt *)> & resultCallback)134 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql,
135 const std::function<int (sqlite3_stmt *)> &bindCallback, const std::function<int (sqlite3_stmt *)> &resultCallback)
136 {
137 if (db == nullptr || sql.empty()) {
138 return -E_INVALID_ARGS;
139 }
140
141 bool bindFinish = true;
142 sqlite3_stmt *stmt = nullptr;
143 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
144 if (errCode != E_OK) {
145 goto END;
146 }
147
148 do {
149 if (bindCallback) {
150 errCode = bindCallback(stmt);
151 if (errCode != E_OK && errCode != -E_UNFINISHED) {
152 goto END;
153 }
154 bindFinish = (errCode != -E_UNFINISHED); // continue bind if unfinished
155 }
156
157 bool isStepFinished = false;
158 while (!isStepFinished) {
159 errCode = SQLiteUtils::StepWithRetry(stmt);
160 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
161 errCode = E_OK; // Step finished
162 isStepFinished = true;
163 break;
164 } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
165 goto END; // Step return error
166 }
167 if (resultCallback == nullptr) {
168 continue;
169 }
170 errCode = resultCallback(stmt);
171 if (errCode != E_OK) {
172 goto END;
173 }
174 }
175 SQLiteUtils::ResetStatement(stmt, false, errCode);
176 } while (!bindFinish);
177
178 END:
179 SQLiteUtils::ResetStatement(stmt, true, errCode);
180 return errCode;
181 }
182 } // namespace DistributedDBUnitTest
183