1 /*
2 * Copyright (c) 2022 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_test.h"
17 #include <cstring>
18 #include <dirent.h>
19 #include <fstream>
20 #include <openssl/rand.h>
21 #include <random>
22 #include <set>
23 #include <sys/types.h>
24
25 #include "db_common.h"
26 #include "db_constant.h"
27 #include "generic_single_ver_kv_entry.h"
28 #include "platform_specific.h"
29 #include "single_ver_data_packet.h"
30 #include "value_hash_calc.h"
31
32 using namespace DistributedDB;
33 namespace DistributedDBTest {
GetCurrentDir(std::string & dir)34 int DistributedDBToolsTest::GetCurrentDir(std::string &dir)
35 {
36 static const int maxFileLength = 1024;
37 dir = "";
38 char buffer[maxFileLength] = {0};
39 int length = readlink("/proc/self/exe", buffer, maxFileLength);
40 if (length < 0 || length >= maxFileLength) {
41 LOGE("read directory err length:%d", length);
42 return -E_LENGTH_ERROR;
43 }
44 LOGD("DIR = %s", buffer);
45 dir = buffer;
46 if (dir.rfind("/") == std::string::npos && dir.rfind("\\") == std::string::npos) {
47 LOGE("current patch format err");
48 return -E_INVALID_PATH;
49 }
50
51 if (dir.rfind("/") != std::string::npos) {
52 dir.erase(dir.rfind("/") + 1);
53 }
54 return E_OK;
55 }
56
TestDirInit(std::string & dir)57 void DistributedDBToolsTest::TestDirInit(std::string &dir)
58 {
59 if (GetCurrentDir(dir) != E_OK) {
60 dir = "/";
61 }
62
63 dir.append("testDbDir");
64 DIR *dirTmp = opendir(dir.c_str());
65 if (dirTmp == nullptr) {
66 if (OS::MakeDBDirectory(dir) != 0) {
67 LOGI("MakeDirectory err!");
68 dir = "/";
69 return;
70 }
71 } else {
72 closedir(dirTmp);
73 }
74 }
75
RemoveTestDbFiles(const std::string & dir)76 int DistributedDBToolsTest::RemoveTestDbFiles(const std::string &dir)
77 {
78 bool isExisted = OS::CheckPathExistence(dir);
79 if (!isExisted) {
80 return E_OK;
81 }
82
83 int nFile = 0;
84 std::string dirName;
85 struct dirent *direntPtr = nullptr;
86 DIR *dirPtr = opendir(dir.c_str());
87 if (dirPtr == nullptr) {
88 LOGE("opendir error!");
89 return -E_INVALID_PATH;
90 }
91 while (true) {
92 direntPtr = readdir(dirPtr);
93 // condition to exit the loop
94 if (direntPtr == nullptr) {
95 break;
96 }
97 // only remove all *.db files
98 std::string str(direntPtr->d_name);
99 if (str == "." || str == "..") {
100 continue;
101 }
102 dirName.clear();
103 dirName.append(dir).append("/").append(str);
104 if (direntPtr->d_type == DT_DIR) {
105 RemoveTestDbFiles(dirName);
106 rmdir(dirName.c_str());
107 } else if (remove(dirName.c_str()) != 0) {
108 LOGI("remove file: %s failed!", dirName.c_str());
109 continue;
110 }
111 nFile++;
112 }
113 closedir(dirPtr);
114 LOGI("Total %d test db files are removed!", nFile);
115 return 0;
116 }
117
GetRandomKeyValue(std::vector<uint8_t> & value,uint32_t defaultSize)118 void DistributedDBToolsTest::GetRandomKeyValue(std::vector<uint8_t> &value, uint32_t defaultSize)
119 {
120 uint32_t randSize = 0;
121 if (defaultSize == 0) {
122 uint8_t simSize = 0;
123 RAND_bytes(&simSize, 1);
124 randSize = (simSize == 0) ? 1 : simSize;
125 } else {
126 randSize = defaultSize;
127 }
128
129 value.resize(randSize);
130 RAND_bytes(value.data(), randSize);
131 }
132
SyncTestWithQuery(KvStoreNbDelegate * delegate,const std::vector<std::string> & devices,SyncMode mode,std::map<std::string,DBStatus> & statuses,const Query & query)133 DBStatus DistributedDBToolsTest::SyncTestWithQuery(KvStoreNbDelegate* delegate,
134 const std::vector<std::string>& devices, SyncMode mode,
135 std::map<std::string, DBStatus>& statuses, const Query &query)
136 {
137 std::mutex syncLock;
138 std::condition_variable syncCondVar;
139 statuses.clear();
140 DBStatus callStatus = delegate->Sync(devices, mode,
141 [&statuses, &syncLock, &syncCondVar](const std::map<std::string, DBStatus>& statusMap) {
142 statuses = statusMap;
143 std::unique_lock<std::mutex> innerlock(syncLock);
144 syncCondVar.notify_one();
145 }, query, false);
146 std::unique_lock<std::mutex> lock(syncLock);
147 syncCondVar.wait(lock, [callStatus, &statuses]() {
148 if (callStatus != OK) {
149 return true;
150 }
151 return !statuses.empty();
152 });
153 return callStatus;
154 }
155
SyncTest(KvStoreNbDelegate * delegate,const std::vector<std::string> & devices,SyncMode mode,std::map<std::string,DBStatus> & statuses)156 DBStatus DistributedDBToolsTest::SyncTest(KvStoreNbDelegate* delegate, const std::vector<std::string>& devices,
157 SyncMode mode, std::map<std::string, DBStatus>& statuses)
158 {
159 std::mutex syncLock;
160 std::condition_variable syncCondVar;
161 statuses.clear();
162 DBStatus callStatus = delegate->Sync(devices, mode,
163 [&statuses, &syncLock, &syncCondVar](const std::map<std::string, DBStatus>& statusMap) {
164 statuses = statusMap;
165 std::unique_lock<std::mutex> innerlock(syncLock);
166 syncCondVar.notify_one();
167 }, false);
168 std::unique_lock<std::mutex> lock(syncLock);
169 syncCondVar.wait(lock, [callStatus, &statuses]() {
170 if (callStatus != OK) {
171 return true;
172 }
173 return !statuses.empty();
174 });
175 return callStatus;
176 }
177
KvStoreObserverTest()178 KvStoreObserverTest::KvStoreObserverTest() : callCount_(0), isCleared_(false)
179 {}
180
OnChange(const KvStoreChangedData & data)181 void KvStoreObserverTest::OnChange(const KvStoreChangedData& data)
182 {
183 callCount_++;
184 inserted_ = data.GetEntriesInserted();
185 updated_ = data.GetEntriesUpdated();
186 deleted_ = data.GetEntriesDeleted();
187 isCleared_ = data.IsCleared();
188 LOGD("Onchangedata :%zu -- %zu -- %zu -- %d", inserted_.size(), updated_.size(), deleted_.size(), isCleared_);
189 LOGD("Onchange() called success!");
190 }
191
CreateDataBase(const std::string & dbUri)192 sqlite3 *RdbTestUtils::CreateDataBase(const std::string &dbUri)
193 {
194 sqlite3 *db = nullptr;
195 if (sqlite3_open_v2(dbUri.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
196 if (db != nullptr) {
197 (void)sqlite3_close_v2(db);
198 db = nullptr;
199 }
200 }
201 return db;
202 }
203
ExecSql(sqlite3 * db,const std::string & sql)204 int RdbTestUtils::ExecSql(sqlite3 *db, const std::string &sql)
205 {
206 if (db == nullptr || sql.empty()) {
207 return -E_INVALID_ARGS;
208 }
209 char *errMsg = nullptr;
210 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
211 if (errCode != SQLITE_OK && errMsg != nullptr) {
212 LOGE("Execute sql failed. %d err: %s", errCode, errMsg);
213 }
214 sqlite3_free(errMsg);
215 return errCode;
216 }
217
CreateDeviceTable(sqlite3 * db,const std::string & table,const std::string & device)218 int RdbTestUtils::CreateDeviceTable(sqlite3 *db, const std::string &table, const std::string &device)
219 {
220 std::string deviceTable = DBCommon::GetDistributedTableName(device, table);
221 TableInfo baseTbl;
222 if (SQLiteUtils::AnalysisSchema(db, table, baseTbl) != E_OK) {
223 return -1;
224 }
225 if (SQLiteUtils::CreateSameStuTable(db, baseTbl, deviceTable) != E_OK) {
226 return -1;
227 }
228 if (SQLiteUtils::CloneIndexes(db, table, deviceTable) != E_OK) {
229 return -1;
230 }
231 return 0;
232 }
233 }