1 /*
2 * Copyright (c) 2021 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
18 #include <cstring>
19 #include <dirent.h>
20 #include <fstream>
21 #include <gtest/gtest.h>
22 #include <openssl/rand.h>
23 #include <random>
24 #include <set>
25 #include <sys/types.h>
26
27
28 #include "db_common.h"
29 #include "db_constant.h"
30 #include "generic_single_ver_kv_entry.h"
31 #include "platform_specific.h"
32 #include "single_ver_data_packet.h"
33 #include "value_hash_calc.h"
34
35 using namespace DistributedDB;
36
37 namespace DistributedDBUnitTest {
38 namespace {
39 const std::string CREATE_LOCAL_TABLE_SQL =
40 "CREATE TABLE IF NOT EXISTS local_data(" \
41 "key BLOB PRIMARY KEY," \
42 "value BLOB," \
43 "timestamp INT," \
44 "hash_key BLOB);";
45
46 const std::string CREATE_META_TABLE_SQL =
47 "CREATE TABLE IF NOT EXISTS meta_data(" \
48 "key BLOB PRIMARY KEY NOT NULL," \
49 "value BLOB);";
50
51 const std::string CREATE_SYNC_TABLE_SQL =
52 "CREATE TABLE IF NOT EXISTS sync_data(" \
53 "key BLOB NOT NULL," \
54 "value BLOB," \
55 "timestamp INT NOT NULL," \
56 "flag INT NOT NULL," \
57 "device BLOB," \
58 "ori_device BLOB," \
59 "hash_key BLOB PRIMARY KEY NOT NULL," \
60 "w_timestamp INT);";
61
62 const std::string CREATE_SYNC_TABLE_INDEX_SQL =
63 "CREATE INDEX IF NOT EXISTS key_index ON sync_data (key);";
64
65 const std::string CREATE_TABLE_SQL =
66 "CREATE TABLE IF NOT EXISTS version_data(key BLOB, value BLOB, oper_flag INTEGER, version INTEGER, " \
67 "timestamp INTEGER, ori_timestamp INTEGER, hash_key BLOB, " \
68 "PRIMARY key(hash_key, version));";
69
70 const std::string CREATE_SQL =
71 "CREATE TABLE IF NOT EXISTS data(key BLOB PRIMARY key, value BLOB);";
72
CompareEntry(const DistributedDB::Entry & a,const DistributedDB::Entry & b)73 bool CompareEntry(const DistributedDB::Entry &a, const DistributedDB::Entry &b)
74 {
75 return (a.key < b.key);
76 }
77 }
78
79 // OpenDbProperties.uri do not need
CreateMockSingleDb(DatabaseInfo & dbInfo,OpenDbProperties & properties)80 int DistributedDBToolsUnitTest::CreateMockSingleDb(DatabaseInfo &dbInfo, OpenDbProperties &properties)
81 {
82 std::string identifier = dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId;
83 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
84 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifier);
85
86 if (OS::GetRealPath(dbInfo.dir, properties.uri) != E_OK) {
87 LOGE("Failed to canonicalize the path.");
88 return -E_INVALID_ARGS;
89 }
90
91 int errCode = DBCommon::CreateStoreDirectory(dbInfo.dir, identifierName, DBConstant::SINGLE_SUB_DIR, true);
92 if (errCode != E_OK) {
93 return errCode;
94 }
95
96 properties.uri = dbInfo.dir + "/" + identifierName + "/" +
97 DBConstant::SINGLE_SUB_DIR + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::SQLITE_DB_EXTENSION;
98 if (properties.sqls.empty()) {
99 std::vector<std::string> defaultCreateTableSqls = {
100 CREATE_LOCAL_TABLE_SQL,
101 CREATE_META_TABLE_SQL,
102 CREATE_SYNC_TABLE_SQL,
103 CREATE_SYNC_TABLE_INDEX_SQL
104 };
105 properties.sqls = defaultCreateTableSqls;
106 }
107
108 sqlite3 *db = nullptr;
109 errCode = SQLiteUtils::OpenDatabase(properties, db);
110 if (errCode != E_OK) {
111 return errCode;
112 }
113 errCode = SQLiteUtils::SetUserVer(properties, dbInfo.dbUserVersion);
114 if (errCode != E_OK) {
115 return errCode;
116 }
117
118 (void)sqlite3_close_v2(db);
119 db = nullptr;
120 return errCode;
121 }
122
CreatMockMultiDb(OpenDbProperties & properties,DatabaseInfo & dbInfo)123 static int CreatMockMultiDb(OpenDbProperties &properties, DatabaseInfo &dbInfo)
124 {
125 sqlite3 *db = nullptr;
126 (void)SQLiteUtils::OpenDatabase(properties, db);
127 int errCode = SQLiteUtils::SetUserVer(properties, dbInfo.dbUserVersion);
128 (void)sqlite3_close_v2(db);
129 db = nullptr;
130 if (errCode != E_OK) {
131 return errCode;
132 }
133 return errCode;
134 }
135
OpenMockMultiDb(DatabaseInfo & dbInfo,OpenDbProperties & properties)136 int DistributedDBToolsUnitTest::OpenMockMultiDb(DatabaseInfo &dbInfo, OpenDbProperties &properties)
137 {
138 std::string identifier = dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId;
139 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
140 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifier);
141
142 OpenDbProperties commitProperties = properties;
143 commitProperties.uri = dbInfo.dir + "/" + identifierName + "/" + DBConstant::MULTI_SUB_DIR +
144 "/commit_logs" + DBConstant::SQLITE_DB_EXTENSION;
145
146 commitProperties.sqls = {CREATE_SQL};
147
148 OpenDbProperties kvStorageProperties = commitProperties;
149 kvStorageProperties.uri = dbInfo.dir + "/" + identifierName + "/" +
150 DBConstant::MULTI_SUB_DIR + "/value_storage" + DBConstant::SQLITE_DB_EXTENSION;
151 OpenDbProperties metaStorageProperties = commitProperties;
152 metaStorageProperties.uri = dbInfo.dir + "/" + identifierName + "/" +
153 DBConstant::MULTI_SUB_DIR + "/meta_storage" + DBConstant::SQLITE_DB_EXTENSION;
154
155 // test code, Don't needpay too much attention to exception handling
156 int errCode = CreatMockMultiDb(properties, dbInfo);
157 if (errCode != E_OK) {
158 return errCode;
159 }
160
161 errCode = CreatMockMultiDb(kvStorageProperties, dbInfo);
162 if (errCode != E_OK) {
163 return errCode;
164 }
165
166 errCode = CreatMockMultiDb(metaStorageProperties, dbInfo);
167 if (errCode != E_OK) {
168 return errCode;
169 }
170
171 return errCode;
172 }
173
174 // OpenDbProperties.uri do not need
CreateMockMultiDb(DatabaseInfo & dbInfo,OpenDbProperties & properties)175 int DistributedDBToolsUnitTest::CreateMockMultiDb(DatabaseInfo &dbInfo, OpenDbProperties &properties)
176 {
177 std::string identifier = dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId;
178 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
179 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifier);
180
181 if (OS::GetRealPath(dbInfo.dir, properties.uri) != E_OK) {
182 LOGE("Failed to canonicalize the path.");
183 return -E_INVALID_ARGS;
184 }
185
186 int errCode = DBCommon::CreateStoreDirectory(dbInfo.dir, identifierName, DBConstant::MULTI_SUB_DIR, true);
187 if (errCode != E_OK) {
188 return errCode;
189 }
190
191 properties.uri = dbInfo.dir + "/" + identifierName + "/" + DBConstant::MULTI_SUB_DIR +
192 "/" + DBConstant::MULTI_VER_DATA_STORE + DBConstant::SQLITE_DB_EXTENSION;
193
194 if (properties.sqls.empty()) {
195 properties.sqls = {CREATE_TABLE_SQL};
196 }
197
198 OpenMockMultiDb(dbInfo, properties);
199
200 return errCode;
201 }
202
GetResourceDir(std::string & dir)203 int DistributedDBToolsUnitTest::GetResourceDir(std::string& dir)
204 {
205 int errCode = GetCurrentDir(dir);
206 if (errCode != E_OK) {
207 return -E_INVALID_PATH;
208 }
209
210 return E_OK;
211 }
212
GetCurrentDir(std::string & dir)213 int DistributedDBToolsUnitTest::GetCurrentDir(std::string &dir)
214 {
215 static const int maxFileLength = 1024;
216 dir = "";
217 char buffer[maxFileLength] = {0};
218 int length = readlink("/proc/self/exe", buffer, maxFileLength);
219 if (length < 0 || length >= maxFileLength) {
220 LOGE("read directory err length:%d", length);
221 return -E_LENGTH_ERROR;
222 }
223 LOGD("DIR = %s", buffer);
224 dir = buffer;
225 if (dir.rfind("/") == std::string::npos && dir.rfind("\\") == std::string::npos) {
226 LOGE("current patch format err");
227 return -E_INVALID_PATH;
228 }
229
230 if (dir.rfind("/") != std::string::npos) {
231 dir.erase(dir.rfind("/") + 1);
232 }
233 return E_OK;
234 }
235
TestDirInit(std::string & dir)236 void DistributedDBToolsUnitTest::TestDirInit(std::string &dir)
237 {
238 if (GetCurrentDir(dir) != E_OK) {
239 dir = "/";
240 }
241
242 dir.append("testDbDir");
243 DIR *dirTmp = opendir(dir.c_str());
244 if (dirTmp == nullptr) {
245 if (OS::MakeDBDirectory(dir) != 0) {
246 LOGI("MakeDirectory err!");
247 dir = "/";
248 return;
249 }
250 } else {
251 closedir(dirTmp);
252 }
253 }
254
RemoveTestDbFiles(const std::string & dir)255 int DistributedDBToolsUnitTest::RemoveTestDbFiles(const std::string &dir)
256 {
257 bool isExisted = OS::CheckPathExistence(dir);
258 if (!isExisted) {
259 return E_OK;
260 }
261
262 int nFile = 0;
263 std::string dirName;
264 struct dirent *direntPtr = nullptr;
265 DIR *dirPtr = opendir(dir.c_str());
266 if (dirPtr == nullptr) {
267 LOGE("opendir error!");
268 return -E_INVALID_PATH;
269 }
270 while (true) {
271 direntPtr = readdir(dirPtr);
272 // condition to exit the loop
273 if (direntPtr == nullptr) {
274 break;
275 }
276 // only remove all *.db files
277 std::string str(direntPtr->d_name);
278 if (str == "." || str == "..") {
279 continue;
280 }
281 dirName.clear();
282 dirName.append(dir).append("/").append(str);
283 if (direntPtr->d_type == DT_DIR) {
284 RemoveTestDbFiles(dirName);
285 rmdir(dirName.c_str());
286 } else if (remove(dirName.c_str()) != 0) {
287 LOGI("remove file: %s failed!", dirName.c_str());
288 continue;
289 }
290 nFile++;
291 }
292 closedir(dirPtr);
293 LOGI("Total %d test db files are removed!", nFile);
294 return 0;
295 }
296
KvStoreDelegateCallback(DBStatus statusSrc,KvStoreDelegate * kvStoreSrc,DBStatus & statusDst,KvStoreDelegate * & kvStoreDst)297 void DistributedDBToolsUnitTest::KvStoreDelegateCallback(
298 DBStatus statusSrc, KvStoreDelegate *kvStoreSrc, DBStatus &statusDst, KvStoreDelegate *&kvStoreDst)
299 {
300 statusDst = statusSrc;
301 kvStoreDst = kvStoreSrc;
302 }
303
KvStoreNbDelegateCallback(DBStatus statusSrc,KvStoreNbDelegate * kvStoreSrc,DBStatus & statusDst,KvStoreNbDelegate * & kvStoreDst)304 void DistributedDBToolsUnitTest::KvStoreNbDelegateCallback(
305 DBStatus statusSrc, KvStoreNbDelegate* kvStoreSrc, DBStatus &statusDst, KvStoreNbDelegate *&kvStoreDst)
306 {
307 statusDst = statusSrc;
308 kvStoreDst = kvStoreSrc;
309 }
SnapshotDelegateCallback(DBStatus statusSrc,KvStoreSnapshotDelegate * snapshot,DBStatus & statusDst,KvStoreSnapshotDelegate * & snapshotDst)310 void DistributedDBToolsUnitTest::SnapshotDelegateCallback(
311 DBStatus statusSrc, KvStoreSnapshotDelegate* snapshot, DBStatus &statusDst, KvStoreSnapshotDelegate *&snapshotDst)
312 {
313 statusDst = statusSrc;
314 snapshotDst = snapshot;
315 }
316
ValueCallback(DBStatus statusSrc,const Value & valueSrc,DBStatus & statusDst,Value & valueDst)317 void DistributedDBToolsUnitTest::ValueCallback(
318 DBStatus statusSrc, const Value &valueSrc, DBStatus &statusDst, Value &valueDst)
319 {
320 statusDst = statusSrc;
321 valueDst = valueSrc;
322 }
323
EntryVectorCallback(DBStatus statusSrc,const std::vector<Entry> & entrySrc,DBStatus & statusDst,unsigned long & matchSize,std::vector<Entry> & entryDst)324 void DistributedDBToolsUnitTest::EntryVectorCallback(DBStatus statusSrc, const std::vector<Entry> &entrySrc,
325 DBStatus &statusDst, unsigned long &matchSize, std::vector<Entry> &entryDst)
326 {
327 statusDst = statusSrc;
328 matchSize = static_cast<unsigned long>(entrySrc.size());
329 entryDst = entrySrc;
330 }
331
332 // size need bigger than prefixkey length
GetRandPrefixKey(const std::vector<uint8_t> & prefixKey,uint32_t size)333 std::vector<uint8_t> DistributedDBToolsUnitTest::GetRandPrefixKey(const std::vector<uint8_t> &prefixKey, uint32_t size)
334 {
335 std::vector<uint8_t> value;
336 if (size <= prefixKey.size()) {
337 return value;
338 }
339 DistributedDBToolsUnitTest::GetRandomKeyValue(value, size - prefixKey.size());
340 std::vector<uint8_t> res(prefixKey);
341 res.insert(res.end(), value.begin(), value.end());
342 return res;
343 }
344
GetRandomKeyValue(std::vector<uint8_t> & value,uint32_t defaultSize)345 void DistributedDBToolsUnitTest::GetRandomKeyValue(std::vector<uint8_t> &value, uint32_t defaultSize)
346 {
347 uint32_t randSize = 0;
348 if (defaultSize == 0) {
349 uint8_t simSize = 0;
350 RAND_bytes(&simSize, 1);
351 randSize = (simSize == 0) ? 1 : simSize;
352 } else {
353 randSize = defaultSize;
354 }
355
356 value.resize(randSize);
357 RAND_bytes(value.data(), randSize);
358 }
359
IsValueEqual(const DistributedDB::Value & read,const DistributedDB::Value & origin)360 bool DistributedDBToolsUnitTest::IsValueEqual(const DistributedDB::Value &read, const DistributedDB::Value &origin)
361 {
362 if (read != origin) {
363 DBCommon::PrintHexVector(read, __LINE__, "read");
364 DBCommon::PrintHexVector(origin, __LINE__, "origin");
365 return false;
366 }
367
368 return true;
369 }
370
IsEntryEqual(const DistributedDB::Entry & entryOrg,const DistributedDB::Entry & entryRet)371 bool DistributedDBToolsUnitTest::IsEntryEqual(const DistributedDB::Entry &entryOrg,
372 const DistributedDB::Entry &entryRet)
373 {
374 if (entryOrg.key != entryRet.key) {
375 LOGD("key not equal, entryOrg key size is [%zu], entryRet key size is [%zu]", entryOrg.key.size(),
376 entryRet.key.size());
377 return false;
378 }
379
380 if (entryOrg.value != entryRet.value) {
381 LOGD("value not equal, entryOrg value size is [%zu], entryRet value size is [%zu]", entryOrg.value.size(),
382 entryRet.value.size());
383 return false;
384 }
385
386 return true;
387 }
388
IsEntriesEqual(const std::vector<DistributedDB::Entry> & entriesOrg,const std::vector<DistributedDB::Entry> & entriesRet,bool needSort)389 bool DistributedDBToolsUnitTest::IsEntriesEqual(const std::vector<DistributedDB::Entry> &entriesOrg,
390 const std::vector<DistributedDB::Entry> &entriesRet, bool needSort)
391 {
392 LOGD("entriesOrg size is [%zu], entriesRet size is [%zu]", entriesOrg.size(),
393 entriesRet.size());
394
395 if (entriesOrg.size() != entriesRet.size()) {
396 return false;
397 }
398 std::vector<DistributedDB::Entry> entries1 = entriesOrg;
399 std::vector<DistributedDB::Entry> entries2 = entriesRet;
400
401 if (needSort) {
402 sort(entries1.begin(), entries1.end(), CompareEntry);
403 sort(entries2.begin(), entries2.end(), CompareEntry);
404 }
405
406 for (size_t i = 0; i < entries1.size(); i++) {
407 if (entries1[i].key != entries2[i].key) {
408 LOGE("IsEntriesEqual failed, key of index[%zu] not match", i);
409 return false;
410 }
411 if (entries1[i].value != entries2[i].value) {
412 LOGE("IsEntriesEqual failed, value of index[%zu] not match", i);
413 return false;
414 }
415 }
416
417 return true;
418 }
419
CheckObserverResult(const std::vector<DistributedDB::Entry> & orgEntries,const std::list<DistributedDB::Entry> & resultLst)420 bool DistributedDBToolsUnitTest::CheckObserverResult(const std::vector<DistributedDB::Entry> &orgEntries,
421 const std::list<DistributedDB::Entry> &resultLst)
422 {
423 LOGD("orgEntries.size() is [%zu], resultLst.size() is [%zu]", orgEntries.size(),
424 resultLst.size());
425
426 if (orgEntries.size() != resultLst.size()) {
427 return false;
428 }
429
430 int index = 0;
431 for (const auto &entry : resultLst) {
432 if (entry.key != orgEntries[index].key) {
433 LOGE("CheckObserverResult failed, key of index[%d] not match", index);
434 return false;
435 }
436 if (entry.value != orgEntries[index].value) {
437 LOGE("CheckObserverResult failed, value of index[%d] not match", index);
438 return false;
439 }
440 index++;
441 }
442
443 return true;
444 }
445
IsEntryExist(const DistributedDB::Entry & entry,const std::vector<DistributedDB::Entry> & entries)446 bool DistributedDBToolsUnitTest::IsEntryExist(const DistributedDB::Entry &entry,
447 const std::vector<DistributedDB::Entry> &entries)
448 {
449 std::set<std::vector<uint8_t>> sets;
450 for (const auto &iter : entries) {
451 sets.insert(iter.key);
452 }
453
454 if (entries.size() != sets.size()) {
455 return false;
456 }
457 sets.clear();
458 bool isFound = false;
459 for (const auto &iter : entries) {
460 if (entry.key == iter.key) {
461 if (entry.value == iter.value) {
462 isFound = true;
463 }
464 break;
465 }
466 }
467 return isFound;
468 }
469
IsItemValueExist(const DistributedDB::DataItem & item,const std::vector<DistributedDB::DataItem> & items)470 bool DistributedDBToolsUnitTest::IsItemValueExist(const DistributedDB::DataItem &item,
471 const std::vector<DistributedDB::DataItem> &items)
472 {
473 std::set<Key> sets;
474 for (const auto &iter : items) {
475 sets.insert(iter.key);
476 }
477
478 if (items.size() != sets.size()) {
479 return false;
480 }
481 sets.clear();
482 bool isFound = false;
483 for (const auto &iter : items) {
484 if (item.key == iter.key) {
485 if (item.value == iter.value) {
486 isFound = true;
487 }
488 break;
489 }
490 }
491 return isFound;
492 }
493
IsKvEntryExist(const DistributedDB::Entry & entry,const std::vector<DistributedDB::Entry> & entries)494 bool DistributedDBToolsUnitTest::IsKvEntryExist(const DistributedDB::Entry &entry,
495 const std::vector<DistributedDB::Entry> &entries)
496 {
497 std::set<std::vector<uint8_t>> sets;
498 for (const auto &iter : entries) {
499 sets.insert(iter.key);
500 }
501
502 if (entries.size() != sets.size()) {
503 return false;
504 }
505 sets.clear();
506 bool isFound = false;
507 for (const auto &iter : entries) {
508 if (entry.key == iter.key) {
509 if (entry.value == iter.value) {
510 isFound = true;
511 }
512 break;
513 }
514 }
515
516 return isFound;
517 }
518
ModifyDatabaseFile(const std::string & fileDir,uint64_t modifyPos,uint32_t modifyCnt,uint32_t value)519 int DistributedDBToolsUnitTest::ModifyDatabaseFile(const std::string &fileDir, uint64_t modifyPos,
520 uint32_t modifyCnt, uint32_t value)
521 {
522 LOGI("Modify database file:%s", fileDir.c_str());
523 std::fstream dataFile(fileDir, std::fstream::binary | std::fstream::out | std::fstream::in);
524 if (!dataFile.is_open()) {
525 LOGD("Open the database file failed");
526 return -E_UNEXPECTED_DATA;
527 }
528
529 if (!dataFile.seekg(0, std::fstream::end)) {
530 return -E_UNEXPECTED_DATA;
531 }
532
533 uint64_t fileSize;
534 std::ios::pos_type pos = dataFile.tellg();
535 if (pos < 0) {
536 return -E_UNEXPECTED_DATA;
537 } else {
538 fileSize = static_cast<uint64_t>(pos);
539 if (fileSize < 1024) { // the least page size is 1024 bytes.
540 LOGE("Invalid database file:%" PRIu64 ".", fileSize);
541 return -E_UNEXPECTED_DATA;
542 }
543 }
544
545 if (fileSize <= modifyPos) {
546 return E_OK;
547 }
548
549 if (!dataFile.seekp(modifyPos)) {
550 return -E_UNEXPECTED_DATA;
551 }
552 for (uint32_t i = 0; i < modifyCnt; i++) {
553 if (!dataFile.write(reinterpret_cast<char *>(&value), sizeof(uint32_t))) {
554 return -E_UNEXPECTED_DATA;
555 }
556 }
557
558 dataFile.flush();
559 return E_OK;
560 }
561
GetSyncDataTest(const SyncInputArg & syncInputArg,SQLiteSingleVerNaturalStore * store,std::vector<DataItem> & dataItems,ContinueToken & continueStmtToken)562 int DistributedDBToolsUnitTest::GetSyncDataTest(const SyncInputArg &syncInputArg, SQLiteSingleVerNaturalStore *store,
563 std::vector<DataItem> &dataItems, ContinueToken &continueStmtToken)
564 {
565 std::vector<SingleVerKvEntry *> entries;
566 DataSizeSpecInfo syncDataSizeInfo = {syncInputArg.blockSize_, DBConstant::MAX_HPMODE_PACK_ITEM_SIZE};
567 int errCode = store->GetSyncData(syncInputArg.begin_, syncInputArg.end_, entries,
568 continueStmtToken, syncDataSizeInfo);
569
570 ConvertSingleVerEntryToItems(entries, dataItems);
571 return errCode;
572 }
573
GetSyncDataNextTest(SQLiteSingleVerNaturalStore * store,uint32_t blockSize,std::vector<DataItem> & dataItems,ContinueToken & continueStmtToken)574 int DistributedDBToolsUnitTest::GetSyncDataNextTest(SQLiteSingleVerNaturalStore *store, uint32_t blockSize,
575 std::vector<DataItem> &dataItems, ContinueToken &continueStmtToken)
576 {
577 std::vector<SingleVerKvEntry *> entries;
578 DataSizeSpecInfo syncDataSizeInfo = {blockSize, DBConstant::MAX_HPMODE_PACK_ITEM_SIZE};
579 int errCode = store->GetSyncDataNext(entries, continueStmtToken, syncDataSizeInfo);
580
581 ConvertSingleVerEntryToItems(entries, dataItems);
582 return errCode;
583 }
584
PutSyncDataTest(SQLiteSingleVerNaturalStore * store,const std::vector<DataItem> & dataItems,const std::string & deviceName)585 int DistributedDBToolsUnitTest::PutSyncDataTest(SQLiteSingleVerNaturalStore *store,
586 const std::vector<DataItem> &dataItems, const std::string &deviceName)
587 {
588 QueryObject query(Query::Select());
589 return PutSyncDataTest(store, dataItems, deviceName, query);
590 }
591
PutSyncDataTest(SQLiteSingleVerNaturalStore * store,const std::vector<DataItem> & dataItems,const std::string & deviceName,const QueryObject & query)592 int DistributedDBToolsUnitTest::PutSyncDataTest(SQLiteSingleVerNaturalStore *store,
593 const std::vector<DataItem> &dataItems, const std::string &deviceName, const QueryObject &query)
594 {
595 std::vector<SingleVerKvEntry *> entries;
596 std::vector<DistributedDB::DataItem> items = dataItems;
597 for (auto &item : items) {
598 auto *entry = new (std::nothrow) GenericSingleVerKvEntry();
599 if (entry == nullptr) {
600 ReleaseSingleVerEntry(entries);
601 return -E_OUT_OF_MEMORY;
602 }
603 entry->SetEntryData(std::move(item));
604 entry->SetWriteTimestamp(entry->GetTimestamp());
605 entries.push_back(entry);
606 }
607
608 int errCode = store->PutSyncDataWithQuery(query, entries, deviceName);
609 ReleaseSingleVerEntry(entries);
610 return errCode;
611 }
612
ConvertItemsToSingleVerEntry(const std::vector<DistributedDB::DataItem> & dataItems,std::vector<DistributedDB::SingleVerKvEntry * > & entries)613 int DistributedDBToolsUnitTest::ConvertItemsToSingleVerEntry(const std::vector<DistributedDB::DataItem> &dataItems,
614 std::vector<DistributedDB::SingleVerKvEntry *> &entries)
615 {
616 std::vector<DistributedDB::DataItem> items = dataItems;
617 for (auto &item : items) {
618 GenericSingleVerKvEntry *entry = new (std::nothrow) GenericSingleVerKvEntry();
619 if (entry == nullptr) {
620 ReleaseSingleVerEntry(entries);
621 return -E_OUT_OF_MEMORY;
622 }
623 entry->SetEntryData(std::move(item));
624 entries.push_back(entry);
625 }
626 return E_OK;
627 }
628
ConvertSingleVerEntryToItems(std::vector<DistributedDB::SingleVerKvEntry * > & entries,std::vector<DistributedDB::DataItem> & dataItems)629 void DistributedDBToolsUnitTest::ConvertSingleVerEntryToItems(std::vector<DistributedDB::SingleVerKvEntry *> &entries,
630 std::vector<DistributedDB::DataItem> &dataItems)
631 {
632 for (auto &itemEntry : entries) {
633 GenericSingleVerKvEntry *entry = reinterpret_cast<GenericSingleVerKvEntry *>(itemEntry);
634 if (entry != nullptr) {
635 DataItem item;
636 item.origDev = entry->GetOrigDevice();
637 item.flag = entry->GetFlag();
638 item.timestamp = entry->GetTimestamp();
639 entry->GetKey(item.key);
640 entry->GetValue(item.value);
641 dataItems.push_back(item);
642 // clear vector entry
643 delete itemEntry;
644 itemEntry = nullptr;
645 }
646 }
647 entries.clear();
648 }
649
ReleaseSingleVerEntry(std::vector<DistributedDB::SingleVerKvEntry * > & entries)650 void DistributedDBToolsUnitTest::ReleaseSingleVerEntry(std::vector<DistributedDB::SingleVerKvEntry *> &entries)
651 {
652 for (auto &item : entries) {
653 delete item;
654 item = nullptr;
655 }
656 entries.clear();
657 }
658
CalcHash(const std::vector<uint8_t> & value,std::vector<uint8_t> & hashValue)659 void DistributedDBToolsUnitTest::CalcHash(const std::vector<uint8_t> &value, std::vector<uint8_t> &hashValue)
660 {
661 ValueHashCalc hashCalc;
662 hashCalc.Initialize();
663 hashCalc.Update(value);
664 hashCalc.GetResult(hashValue);
665 }
666
KvStoreObserverUnitTest()667 KvStoreObserverUnitTest::KvStoreObserverUnitTest() : callCount_(0), isCleared_(false)
668 {}
669
OnChange(const KvStoreChangedData & data)670 void KvStoreObserverUnitTest::OnChange(const KvStoreChangedData& data)
671 {
672 callCount_++;
673 inserted_ = data.GetEntriesInserted();
674 updated_ = data.GetEntriesUpdated();
675 deleted_ = data.GetEntriesDeleted();
676 isCleared_ = data.IsCleared();
677 LOGD("Onchangedata :%zu -- %zu -- %zu -- %d", inserted_.size(), updated_.size(), deleted_.size(), isCleared_);
678 LOGD("Onchange() called success!");
679 }
680
ResetToZero()681 void KvStoreObserverUnitTest::ResetToZero()
682 {
683 callCount_ = 0;
684 isCleared_ = false;
685 inserted_.clear();
686 updated_.clear();
687 deleted_.clear();
688 }
689
GetCallCount() const690 unsigned long KvStoreObserverUnitTest::GetCallCount() const
691 {
692 return callCount_;
693 }
694
GetEntriesInserted() const695 const std::list<Entry> &KvStoreObserverUnitTest::GetEntriesInserted() const
696 {
697 return inserted_;
698 }
699
GetEntriesUpdated() const700 const std::list<Entry> &KvStoreObserverUnitTest::GetEntriesUpdated() const
701 {
702 return updated_;
703 }
704
GetEntriesDeleted() const705 const std::list<Entry> &KvStoreObserverUnitTest::GetEntriesDeleted() const
706 {
707 return deleted_;
708 }
709
IsCleared() const710 bool KvStoreObserverUnitTest::IsCleared() const
711 {
712 return isCleared_;
713 }
714
RelationalStoreObserverUnitTest()715 RelationalStoreObserverUnitTest::RelationalStoreObserverUnitTest() : callCount_(0)
716 {
717 }
718
GetCallCount() const719 unsigned long RelationalStoreObserverUnitTest::GetCallCount() const
720 {
721 return callCount_;
722 }
723
OnChange(const StoreChangedData & data)724 void RelationalStoreObserverUnitTest::OnChange(const StoreChangedData& data)
725 {
726 callCount_++;
727 changeDevice_ = data.GetDataChangeDevice();
728 data.GetStoreProperty(storeProperty_);
729 LOGD("Onchangedata : %s", changeDevice_.c_str());
730 LOGD("Onchange() called success!");
731 }
732
ResetToZero()733 void RelationalStoreObserverUnitTest::ResetToZero()
734 {
735 callCount_ = 0;
736 changeDevice_.clear();
737 storeProperty_ = {};
738 }
739
GetDataChangeDevice() const740 const std::string RelationalStoreObserverUnitTest::GetDataChangeDevice() const
741 {
742 return changeDevice_;
743 }
744
GetStoreProperty() const745 DistributedDB::StoreProperty RelationalStoreObserverUnitTest::GetStoreProperty() const
746 {
747 return storeProperty_;
748 }
749
SyncTest(KvStoreNbDelegate * delegate,const std::vector<std::string> & devices,SyncMode mode,std::map<std::string,DBStatus> & statuses,const Query & query)750 DBStatus DistributedDBToolsUnitTest::SyncTest(KvStoreNbDelegate* delegate,
751 const std::vector<std::string>& devices, SyncMode mode,
752 std::map<std::string, DBStatus>& statuses, const Query &query)
753 {
754 statuses.clear();
755 DBStatus callStatus = delegate->Sync(devices, mode,
756 [&statuses, this](const std::map<std::string, DBStatus>& statusMap) {
757 statuses = statusMap;
758 std::unique_lock<std::mutex> innerlock(this->syncLock_);
759 this->syncCondVar_.notify_one();
760 }, query, false);
761
762 std::unique_lock<std::mutex> lock(syncLock_);
763 syncCondVar_.wait(lock, [callStatus, &statuses]() {
764 if (callStatus != OK) {
765 return true;
766 }
767 return !statuses.empty();
768 });
769 return callStatus;
770 }
771
SyncTest(KvStoreNbDelegate * delegate,const std::vector<std::string> & devices,SyncMode mode,std::map<std::string,DBStatus> & statuses,bool wait)772 DBStatus DistributedDBToolsUnitTest::SyncTest(KvStoreNbDelegate* delegate,
773 const std::vector<std::string>& devices, SyncMode mode,
774 std::map<std::string, DBStatus>& statuses, bool wait)
775 {
776 statuses.clear();
777 DBStatus callStatus = delegate->Sync(devices, mode,
778 [&statuses, this](const std::map<std::string, DBStatus>& statusMap) {
779 statuses = statusMap;
780 std::unique_lock<std::mutex> innerlock(this->syncLock_);
781 this->syncCondVar_.notify_one();
782 }, wait);
783 if (!wait) {
784 std::unique_lock<std::mutex> lock(syncLock_);
785 syncCondVar_.wait(lock, [callStatus, &statuses]() {
786 if (callStatus != OK) {
787 return true;
788 }
789 if (statuses.size() != 0) {
790 return true;
791 }
792 return false;
793 });
794 }
795 return callStatus;
796 }
797
CorruptCallBack(const std::string & appId,const std::string & userId,const std::string & storeId)798 void KvStoreCorruptInfo::CorruptCallBack(const std::string &appId, const std::string &userId,
799 const std::string &storeId)
800 {
801 DatabaseInfo databaseInfo;
802 databaseInfo.appId = appId;
803 databaseInfo.userId = userId;
804 databaseInfo.storeId = storeId;
805 LOGD("appId :%s, userId:%s, storeId:%s", appId.c_str(), userId.c_str(), storeId.c_str());
806 databaseInfoVect_.push_back(databaseInfo);
807 }
808
GetDatabaseInfoSize() const809 size_t KvStoreCorruptInfo::GetDatabaseInfoSize() const
810 {
811 return databaseInfoVect_.size();
812 }
813
IsDataBaseCorrupted(const std::string & appId,const std::string & userId,const std::string & storeId) const814 bool KvStoreCorruptInfo::IsDataBaseCorrupted(const std::string &appId, const std::string &userId,
815 const std::string &storeId) const
816 {
817 for (const auto &item : databaseInfoVect_) {
818 if (item.appId == appId &&
819 item.userId == userId &&
820 item.storeId == storeId) {
821 return true;
822 }
823 }
824 return false;
825 }
826
Reset()827 void KvStoreCorruptInfo::Reset()
828 {
829 databaseInfoVect_.clear();
830 }
831
GetRandInt(const int randMin,const int randMax)832 int DistributedDBToolsUnitTest::GetRandInt(const int randMin, const int randMax)
833 {
834 std::random_device randDev;
835 std::mt19937 genRand(randDev());
836 std::uniform_int_distribution<int> disRand(randMin, randMax);
837 return disRand(genRand);
838 }
839
GetRandInt64(const int64_t randMin,const int64_t randMax)840 int64_t DistributedDBToolsUnitTest::GetRandInt64(const int64_t randMin, const int64_t randMax)
841 {
842 std::random_device randDev;
843 std::mt19937_64 genRand(randDev());
844 std::uniform_int_distribution<int64_t> disRand(randMin, randMax);
845 return disRand(genRand);
846 }
847
PrintTestCaseInfo()848 void DistributedDBToolsUnitTest::PrintTestCaseInfo()
849 {
850 testing::UnitTest *test = testing::UnitTest::GetInstance();
851 ASSERT_NE(test, nullptr);
852 const testing::TestInfo *testInfo = test->current_test_info();
853 ASSERT_NE(testInfo, nullptr);
854 LOGI("Start unit test: %s.%s", testInfo->test_case_name(), testInfo->name());
855 }
856
BuildMessage(const DataSyncMessageInfo & messageInfo,DistributedDB::Message * & message)857 int DistributedDBToolsUnitTest::BuildMessage(const DataSyncMessageInfo &messageInfo,
858 DistributedDB::Message *&message)
859 {
860 auto packet = new (std::nothrow) DataRequestPacket;
861 if (packet == nullptr) {
862 return -E_OUT_OF_MEMORY;
863 }
864 message = new (std::nothrow) Message(messageInfo.messageId_);
865 if (message == nullptr) {
866 delete packet;
867 packet = nullptr;
868 return -E_OUT_OF_MEMORY;
869 }
870 packet->SetBasicInfo(messageInfo.sendCode_, messageInfo.version_, messageInfo.mode_);
871 packet->SetWaterMark(messageInfo.localMark_, messageInfo.peerMark_, messageInfo.deleteMark_);
872 std::vector<uint64_t> reserved {messageInfo.packetId_};
873 packet->SetReserved(reserved);
874 message->SetMessageType(messageInfo.messageType_);
875 message->SetSessionId(messageInfo.sessionId_);
876 message->SetSequenceId(messageInfo.sequenceId_);
877 message->SetExternalObject(packet);
878 return E_OK;
879 }
880
CreateDataBase(const std::string & dbUri)881 sqlite3 *RelationalTestUtils::CreateDataBase(const std::string &dbUri)
882 {
883 LOGD("Create database: %s", dbUri.c_str());
884 sqlite3 *db = nullptr;
885 if (int r = sqlite3_open_v2(dbUri.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
886 LOGE("Open database [%s] failed. %d", dbUri.c_str(), r);
887 if (db != nullptr) {
888 (void)sqlite3_close_v2(db);
889 db = nullptr;
890 }
891 }
892 return db;
893 }
894
ExecSql(sqlite3 * db,const std::string & sql)895 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql)
896 {
897 if (db == nullptr || sql.empty()) {
898 return -E_INVALID_ARGS;
899 }
900 char *errMsg = nullptr;
901 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
902 if (errCode != SQLITE_OK && errMsg != nullptr) {
903 LOGE("Execute sql failed. %d err: %s", errCode, errMsg);
904 }
905 sqlite3_free(errMsg);
906 return errCode;
907 }
908
ExecSql(sqlite3 * db,const std::string & sql,const std::function<int (sqlite3_stmt *)> & bindCallback,const std::function<int (sqlite3_stmt *)> & resultCallback)909 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql,
910 const std::function<int (sqlite3_stmt *)> &bindCallback, const std::function<int (sqlite3_stmt *)> &resultCallback)
911 {
912 if (db == nullptr || sql.empty()) {
913 return -E_INVALID_ARGS;
914 }
915
916 sqlite3_stmt *stmt = nullptr;
917 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
918 if (errCode != E_OK) {
919 goto END;
920 }
921 if (bindCallback) {
922 errCode = bindCallback(stmt);
923 if (errCode != E_OK) {
924 goto END;
925 }
926 }
927
928 do {
929 errCode = SQLiteUtils::StepWithRetry(stmt);
930 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
931 errCode = E_OK;
932 break;
933 } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
934 break;
935 }
936 if (resultCallback && resultCallback(stmt) != E_OK) { // continue step stmt while callback return E_OK
937 goto END;
938 }
939 } while (true);
940 END:
941 SQLiteUtils::ResetStatement(stmt, true, errCode);
942 return errCode;
943 }
944
CreateDeviceTable(sqlite3 * db,const std::string & table,const std::string & device)945 void RelationalTestUtils::CreateDeviceTable(sqlite3 *db, const std::string &table, const std::string &device)
946 {
947 ASSERT_NE(db, nullptr);
948 std::string deviceTable = DBCommon::GetDistributedTableName(device, table);
949 TableInfo baseTbl;
950 ASSERT_EQ(SQLiteUtils::AnalysisSchema(db, table, baseTbl), E_OK);
951 EXPECT_EQ(SQLiteUtils::CreateSameStuTable(db, baseTbl, deviceTable), E_OK);
952 EXPECT_EQ(SQLiteUtils::CloneIndexes(db, table, deviceTable), E_OK);
953 }
954
CheckSqlResult(sqlite3 * db,const std::string & sql,bool & result)955 int RelationalTestUtils::CheckSqlResult(sqlite3 *db, const std::string &sql, bool &result)
956 {
957 if (db == nullptr || sql.empty()) {
958 return -E_INVALID_ARGS;
959 }
960 sqlite3_stmt *stmt = nullptr;
961 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
962 if (errCode != E_OK) {
963 goto END;
964 }
965
966 errCode = SQLiteUtils::StepWithRetry(stmt);
967 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
968 result = true;
969 errCode = E_OK;
970 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
971 result = false;
972 errCode = E_OK;
973 }
974 END:
975 SQLiteUtils::ResetStatement(stmt, true, errCode);
976 return errCode;
977 }
978
CheckTableRecords(sqlite3 * db,const std::string & table)979 int RelationalTestUtils::CheckTableRecords(sqlite3 *db, const std::string &table)
980 {
981 if (db == nullptr || table.empty()) {
982 return -E_INVALID_ARGS;
983 }
984 int count = -1;
985 std::string sql = "select count(1) from " + table + ";";
986
987 sqlite3_stmt *stmt = nullptr;
988 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
989 if (errCode != E_OK) {
990 goto END;
991 }
992
993 errCode = SQLiteUtils::StepWithRetry(stmt);
994 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
995 count = sqlite3_column_int(stmt, 0);
996 }
997 END:
998 SQLiteUtils::ResetStatement(stmt, true, errCode);
999 return count;
1000 }
1001
GetMetaData(sqlite3 * db,const DistributedDB::Key & key,DistributedDB::Value & value)1002 int RelationalTestUtils::GetMetaData(sqlite3 *db, const DistributedDB::Key &key, DistributedDB::Value &value)
1003 {
1004 if (db == nullptr) {
1005 return -E_INVALID_ARGS;
1006 }
1007
1008 std::string sql = "SELECT value FROM " + DBConstant::RELATIONAL_PREFIX + "metadata WHERE key = ?;";
1009 sqlite3_stmt *stmt = nullptr;
1010 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1011 if (errCode != E_OK) {
1012 goto END;
1013 }
1014 errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key);
1015 if (errCode != E_OK) {
1016 goto END;
1017 }
1018
1019 errCode = SQLiteUtils::StepWithRetry(stmt);
1020 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1021 errCode = SQLiteUtils::GetColumnBlobValue(stmt, 0, value);
1022 }
1023 END:
1024 SQLiteUtils::ResetStatement(stmt, true, errCode);
1025 return errCode;
1026 }
1027
SetMetaData(sqlite3 * db,const DistributedDB::Key & key,const DistributedDB::Value & value)1028 int RelationalTestUtils::SetMetaData(sqlite3 *db, const DistributedDB::Key &key, const DistributedDB::Value &value)
1029 {
1030 if (db == nullptr) {
1031 return -E_INVALID_ARGS;
1032 }
1033
1034 std::string sql = "INSERT OR REPLACE INTO " + DBConstant::RELATIONAL_PREFIX + "metadata VALUES (?, ?);";
1035 sqlite3_stmt *stmt = nullptr;
1036 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1037 if (errCode != E_OK) {
1038 goto END;
1039 }
1040 errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key);
1041 if (errCode != E_OK) {
1042 goto END;
1043 }
1044 errCode = SQLiteUtils::BindBlobToStatement(stmt, 2, value); // 2: bind index
1045 if (errCode != E_OK) {
1046 goto END;
1047 }
1048
1049 errCode = SQLiteUtils::StepWithRetry(stmt);
1050 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1051 errCode = E_OK;
1052 }
1053 END:
1054 SQLiteUtils::ResetStatement(stmt, true, errCode);
1055 return SQLiteUtils::MapSQLiteErrno(errCode);
1056 }
1057 } // namespace DistributedDBUnitTest
1058