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 <codecvt>
19 #include <cstdio>
20 #include <cstring>
21 #include <dirent.h>
22 #include <fstream>
23 #include <gtest/gtest.h>
24 #include <locale>
25 #include <openssl/rand.h>
26 #include <random>
27 #include <set>
28 #include <sys/types.h>
29
30 #include "cloud/cloud_db_constant.h"
31 #include "cloud/cloud_db_types.h"
32 #include "db_common.h"
33 #include "db_constant.h"
34 #include "generic_single_ver_kv_entry.h"
35 #include "platform_specific.h"
36 #include "runtime_config.h"
37 #include "single_ver_data_packet.h"
38 #include "sqlite_relational_utils.h"
39 #include "store_observer.h"
40 #include "time_helper.h"
41 #include "value_hash_calc.h"
42
43 using namespace DistributedDB;
44
45 namespace DistributedDBUnitTest {
46 namespace {
47 const std::string CREATE_LOCAL_TABLE_SQL =
48 "CREATE TABLE IF NOT EXISTS local_data(" \
49 "key BLOB PRIMARY KEY," \
50 "value BLOB," \
51 "timestamp INT," \
52 "hash_key BLOB);";
53
54 const std::string CREATE_META_TABLE_SQL =
55 "CREATE TABLE IF NOT EXISTS meta_data(" \
56 "key BLOB PRIMARY KEY NOT NULL," \
57 "value BLOB);";
58
59 const std::string CREATE_SYNC_TABLE_SQL =
60 "CREATE TABLE IF NOT EXISTS sync_data(" \
61 "key BLOB NOT NULL," \
62 "value BLOB," \
63 "timestamp INT NOT NULL," \
64 "flag INT NOT NULL," \
65 "device BLOB," \
66 "ori_device BLOB," \
67 "hash_key BLOB PRIMARY KEY NOT NULL," \
68 "w_timestamp INT);";
69
70 const std::string CREATE_SYNC_TABLE_INDEX_SQL =
71 "CREATE INDEX IF NOT EXISTS key_index ON sync_data (key);";
72
73 const std::string CREATE_TABLE_SQL =
74 "CREATE TABLE IF NOT EXISTS version_data(key BLOB, value BLOB, oper_flag INTEGER, version INTEGER, " \
75 "timestamp INTEGER, ori_timestamp INTEGER, hash_key BLOB, " \
76 "PRIMARY key(hash_key, version));";
77
78 const std::string CREATE_SQL =
79 "CREATE TABLE IF NOT EXISTS data(key BLOB PRIMARY key, value BLOB);";
80
CompareEntry(const DistributedDB::Entry & a,const DistributedDB::Entry & b)81 bool CompareEntry(const DistributedDB::Entry &a, const DistributedDB::Entry &b)
82 {
83 return (a.key < b.key);
84 }
85 }
86
87 // OpenDbProperties.uri do not need
CreateMockSingleDb(DatabaseInfo & dbInfo,OpenDbProperties & properties)88 int DistributedDBToolsUnitTest::CreateMockSingleDb(DatabaseInfo &dbInfo, OpenDbProperties &properties)
89 {
90 std::string identifier = dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId;
91 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
92 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifier);
93
94 if (OS::GetRealPath(dbInfo.dir, properties.uri) != E_OK) {
95 LOGE("Failed to canonicalize the path.");
96 return -E_INVALID_ARGS;
97 }
98
99 int errCode = DBCommon::CreateStoreDirectory(dbInfo.dir, identifierName, DBConstant::SINGLE_SUB_DIR, true);
100 if (errCode != E_OK) {
101 return errCode;
102 }
103
104 properties.uri = dbInfo.dir + "/" + identifierName + "/" +
105 DBConstant::SINGLE_SUB_DIR + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION;
106 if (properties.sqls.empty()) {
107 std::vector<std::string> defaultCreateTableSqls = {
108 CREATE_LOCAL_TABLE_SQL,
109 CREATE_META_TABLE_SQL,
110 CREATE_SYNC_TABLE_SQL,
111 CREATE_SYNC_TABLE_INDEX_SQL
112 };
113 properties.sqls = defaultCreateTableSqls;
114 }
115
116 sqlite3 *db = nullptr;
117 errCode = SQLiteUtils::OpenDatabase(properties, db);
118 if (errCode != E_OK) {
119 return errCode;
120 }
121 errCode = SQLiteUtils::SetUserVer(properties, dbInfo.dbUserVersion);
122 if (errCode != E_OK) {
123 return errCode;
124 }
125
126 (void)sqlite3_close_v2(db);
127 db = nullptr;
128 return errCode;
129 }
130
CreatMockMultiDb(OpenDbProperties & properties,DatabaseInfo & dbInfo)131 static int CreatMockMultiDb(OpenDbProperties &properties, DatabaseInfo &dbInfo)
132 {
133 sqlite3 *db = nullptr;
134 (void)SQLiteUtils::OpenDatabase(properties, db);
135 int errCode = SQLiteUtils::SetUserVer(properties, dbInfo.dbUserVersion);
136 (void)sqlite3_close_v2(db);
137 db = nullptr;
138 if (errCode != E_OK) {
139 return errCode;
140 }
141 return errCode;
142 }
143
OpenMockMultiDb(DatabaseInfo & dbInfo,OpenDbProperties & properties)144 int DistributedDBToolsUnitTest::OpenMockMultiDb(DatabaseInfo &dbInfo, OpenDbProperties &properties)
145 {
146 std::string identifier = dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId;
147 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
148 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifier);
149
150 OpenDbProperties commitProperties = properties;
151 commitProperties.uri = dbInfo.dir + "/" + identifierName + "/" + DBConstant::MULTI_SUB_DIR +
152 "/commit_logs" + DBConstant::DB_EXTENSION;
153
154 commitProperties.sqls = {CREATE_SQL};
155
156 OpenDbProperties kvStorageProperties = commitProperties;
157 kvStorageProperties.uri = dbInfo.dir + "/" + identifierName + "/" +
158 DBConstant::MULTI_SUB_DIR + "/value_storage" + DBConstant::DB_EXTENSION;
159 OpenDbProperties metaStorageProperties = commitProperties;
160 metaStorageProperties.uri = dbInfo.dir + "/" + identifierName + "/" +
161 DBConstant::MULTI_SUB_DIR + "/meta_storage" + DBConstant::DB_EXTENSION;
162
163 // test code, Don't needpay too much attention to exception handling
164 int errCode = CreatMockMultiDb(properties, dbInfo);
165 if (errCode != E_OK) {
166 return errCode;
167 }
168
169 errCode = CreatMockMultiDb(kvStorageProperties, dbInfo);
170 if (errCode != E_OK) {
171 return errCode;
172 }
173
174 errCode = CreatMockMultiDb(metaStorageProperties, dbInfo);
175 if (errCode != E_OK) {
176 return errCode;
177 }
178
179 return errCode;
180 }
181
182 // OpenDbProperties.uri do not need
CreateMockMultiDb(DatabaseInfo & dbInfo,OpenDbProperties & properties)183 int DistributedDBToolsUnitTest::CreateMockMultiDb(DatabaseInfo &dbInfo, OpenDbProperties &properties)
184 {
185 std::string identifier = dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId;
186 std::string hashIdentifier = DBCommon::TransferHashString(identifier);
187 std::string identifierName = DBCommon::TransferStringToHex(hashIdentifier);
188
189 if (OS::GetRealPath(dbInfo.dir, properties.uri) != E_OK) {
190 LOGE("Failed to canonicalize the path.");
191 return -E_INVALID_ARGS;
192 }
193
194 int errCode = DBCommon::CreateStoreDirectory(dbInfo.dir, identifierName, DBConstant::MULTI_SUB_DIR, true);
195 if (errCode != E_OK) {
196 return errCode;
197 }
198
199 properties.uri = dbInfo.dir + "/" + identifierName + "/" + DBConstant::MULTI_SUB_DIR +
200 "/" + DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
201
202 if (properties.sqls.empty()) {
203 properties.sqls = {CREATE_TABLE_SQL};
204 }
205
206 OpenMockMultiDb(dbInfo, properties);
207
208 return errCode;
209 }
210
GetResourceDir(std::string & dir)211 int DistributedDBToolsUnitTest::GetResourceDir(std::string& dir)
212 {
213 int errCode = GetCurrentDir(dir);
214 if (errCode != E_OK) {
215 return -E_INVALID_PATH;
216 }
217 #ifdef DB_DEBUG_ENV
218 dir = dir + "/resource/";
219 #endif
220 return E_OK;
221 }
222
GetCurrentDir(std::string & dir)223 int DistributedDBToolsUnitTest::GetCurrentDir(std::string &dir)
224 {
225 static const int maxFileLength = 1024;
226 dir = "";
227 char buffer[maxFileLength] = {0};
228 int length = readlink("/proc/self/exe", buffer, maxFileLength);
229 if (length < 0 || length >= maxFileLength) {
230 LOGE("read directory err length:%d", length);
231 return -E_LENGTH_ERROR;
232 }
233 LOGD("DIR = %s", buffer);
234 dir = buffer;
235 if (dir.rfind("/") == std::string::npos && dir.rfind("\\") == std::string::npos) {
236 LOGE("current patch format err");
237 return -E_INVALID_PATH;
238 }
239
240 if (dir.rfind("/") != std::string::npos) {
241 dir.erase(dir.rfind("/") + 1);
242 }
243 return E_OK;
244 }
245
TestDirInit(std::string & dir)246 void DistributedDBToolsUnitTest::TestDirInit(std::string &dir)
247 {
248 if (GetCurrentDir(dir) != E_OK) {
249 dir = "/";
250 }
251
252 dir.append("testDbDir");
253 DIR *dirTmp = opendir(dir.c_str());
254 if (dirTmp == nullptr) {
255 if (OS::MakeDBDirectory(dir) != 0) {
256 LOGI("MakeDirectory err!");
257 dir = "/";
258 return;
259 }
260 } else {
261 closedir(dirTmp);
262 }
263 }
264
RemoveTestDbFiles(const std::string & dir)265 int DistributedDBToolsUnitTest::RemoveTestDbFiles(const std::string &dir)
266 {
267 bool isExisted = OS::CheckPathExistence(dir);
268 if (!isExisted) {
269 return E_OK;
270 }
271
272 int nFile = 0;
273 std::string dirName;
274 struct dirent *direntPtr = nullptr;
275 DIR *dirPtr = opendir(dir.c_str());
276 if (dirPtr == nullptr) {
277 LOGE("opendir error!");
278 return -E_INVALID_PATH;
279 }
280 while (true) {
281 direntPtr = readdir(dirPtr);
282 // condition to exit the loop
283 if (direntPtr == nullptr) {
284 break;
285 }
286 // only remove all *.db files
287 std::string str(direntPtr->d_name);
288 if (str == "." || str == "..") {
289 continue;
290 }
291 dirName.clear();
292 dirName.append(dir).append("/").append(str);
293 if (direntPtr->d_type == DT_DIR) {
294 RemoveTestDbFiles(dirName);
295 rmdir(dirName.c_str());
296 } else if (remove(dirName.c_str()) != 0) {
297 LOGI("remove file: %s failed!", dirName.c_str());
298 continue;
299 }
300 nFile++;
301 }
302 closedir(dirPtr);
303 LOGI("Total %d test db files are removed!", nFile);
304 return 0;
305 }
306
307 #ifndef OMIT_MULTI_VER
KvStoreDelegateCallback(DBStatus statusSrc,KvStoreDelegate * kvStoreSrc,DBStatus & statusDst,KvStoreDelegate * & kvStoreDst)308 void DistributedDBToolsUnitTest::KvStoreDelegateCallback(
309 DBStatus statusSrc, KvStoreDelegate *kvStoreSrc, DBStatus &statusDst, KvStoreDelegate *&kvStoreDst)
310 {
311 statusDst = statusSrc;
312 kvStoreDst = kvStoreSrc;
313 }
314
SnapshotDelegateCallback(DBStatus statusSrc,KvStoreSnapshotDelegate * snapshot,DBStatus & statusDst,KvStoreSnapshotDelegate * & snapshotDst)315 void DistributedDBToolsUnitTest::SnapshotDelegateCallback(
316 DBStatus statusSrc, KvStoreSnapshotDelegate* snapshot, DBStatus &statusDst, KvStoreSnapshotDelegate *&snapshotDst)
317 {
318 statusDst = statusSrc;
319 snapshotDst = snapshot;
320 }
321 #endif
322
KvStoreNbDelegateCallback(DBStatus statusSrc,KvStoreNbDelegate * kvStoreSrc,DBStatus & statusDst,KvStoreNbDelegate * & kvStoreDst)323 void DistributedDBToolsUnitTest::KvStoreNbDelegateCallback(
324 DBStatus statusSrc, KvStoreNbDelegate* kvStoreSrc, DBStatus &statusDst, KvStoreNbDelegate *&kvStoreDst)
325 {
326 statusDst = statusSrc;
327 kvStoreDst = kvStoreSrc;
328 }
329
ValueCallback(DBStatus statusSrc,const Value & valueSrc,DBStatus & statusDst,Value & valueDst)330 void DistributedDBToolsUnitTest::ValueCallback(
331 DBStatus statusSrc, const Value &valueSrc, DBStatus &statusDst, Value &valueDst)
332 {
333 statusDst = statusSrc;
334 valueDst = valueSrc;
335 }
336
EntryVectorCallback(DBStatus statusSrc,const std::vector<Entry> & entrySrc,DBStatus & statusDst,unsigned long & matchSize,std::vector<Entry> & entryDst)337 void DistributedDBToolsUnitTest::EntryVectorCallback(DBStatus statusSrc, const std::vector<Entry> &entrySrc,
338 DBStatus &statusDst, unsigned long &matchSize, std::vector<Entry> &entryDst)
339 {
340 statusDst = statusSrc;
341 matchSize = static_cast<unsigned long>(entrySrc.size());
342 entryDst = entrySrc;
343 }
344
345 // size need bigger than prefixkey length
GetRandPrefixKey(const std::vector<uint8_t> & prefixKey,uint32_t size)346 std::vector<uint8_t> DistributedDBToolsUnitTest::GetRandPrefixKey(const std::vector<uint8_t> &prefixKey, uint32_t size)
347 {
348 std::vector<uint8_t> value;
349 if (size <= prefixKey.size()) {
350 return value;
351 }
352 DistributedDBToolsUnitTest::GetRandomKeyValue(value, size - prefixKey.size());
353 std::vector<uint8_t> res(prefixKey);
354 res.insert(res.end(), value.begin(), value.end());
355 return res;
356 }
357
GetRandomKeyValue(std::vector<uint8_t> & value,uint32_t defaultSize)358 void DistributedDBToolsUnitTest::GetRandomKeyValue(std::vector<uint8_t> &value, uint32_t defaultSize)
359 {
360 uint32_t randSize = 0;
361 if (defaultSize == 0) {
362 uint8_t simSize = 0;
363 RAND_bytes(&simSize, 1);
364 randSize = (simSize == 0) ? 1 : simSize;
365 } else {
366 randSize = defaultSize;
367 }
368
369 value.resize(randSize);
370 RAND_bytes(value.data(), randSize);
371 }
372
IsValueEqual(const DistributedDB::Value & read,const DistributedDB::Value & origin)373 bool DistributedDBToolsUnitTest::IsValueEqual(const DistributedDB::Value &read, const DistributedDB::Value &origin)
374 {
375 if (read != origin) {
376 DBCommon::PrintHexVector(read, __LINE__, "read");
377 DBCommon::PrintHexVector(origin, __LINE__, "origin");
378 return false;
379 }
380
381 return true;
382 }
383
IsEntryEqual(const DistributedDB::Entry & entryOrg,const DistributedDB::Entry & entryRet)384 bool DistributedDBToolsUnitTest::IsEntryEqual(const DistributedDB::Entry &entryOrg,
385 const DistributedDB::Entry &entryRet)
386 {
387 if (entryOrg.key != entryRet.key) {
388 LOGD("key not equal, entryOrg key size is [%zu], entryRet key size is [%zu]", entryOrg.key.size(),
389 entryRet.key.size());
390 return false;
391 }
392
393 if (entryOrg.value != entryRet.value) {
394 LOGD("value not equal, entryOrg value size is [%zu], entryRet value size is [%zu]", entryOrg.value.size(),
395 entryRet.value.size());
396 return false;
397 }
398
399 return true;
400 }
401
IsEntriesEqual(const std::vector<DistributedDB::Entry> & entriesOrg,const std::vector<DistributedDB::Entry> & entriesRet,bool needSort)402 bool DistributedDBToolsUnitTest::IsEntriesEqual(const std::vector<DistributedDB::Entry> &entriesOrg,
403 const std::vector<DistributedDB::Entry> &entriesRet, bool needSort)
404 {
405 LOGD("entriesOrg size is [%zu], entriesRet size is [%zu]", entriesOrg.size(),
406 entriesRet.size());
407
408 if (entriesOrg.size() != entriesRet.size()) {
409 return false;
410 }
411 std::vector<DistributedDB::Entry> entries1 = entriesOrg;
412 std::vector<DistributedDB::Entry> entries2 = entriesRet;
413
414 if (needSort) {
415 sort(entries1.begin(), entries1.end(), CompareEntry);
416 sort(entries2.begin(), entries2.end(), CompareEntry);
417 }
418
419 for (size_t i = 0; i < entries1.size(); i++) {
420 if (entries1[i].key != entries2[i].key) {
421 LOGE("IsEntriesEqual failed, key of index[%zu] not match", i);
422 return false;
423 }
424 if (entries1[i].value != entries2[i].value) {
425 LOGE("IsEntriesEqual failed, value of index[%zu] not match", i);
426 return false;
427 }
428 }
429
430 return true;
431 }
432
CheckObserverResult(const std::vector<DistributedDB::Entry> & orgEntries,const std::list<DistributedDB::Entry> & resultLst)433 bool DistributedDBToolsUnitTest::CheckObserverResult(const std::vector<DistributedDB::Entry> &orgEntries,
434 const std::list<DistributedDB::Entry> &resultLst)
435 {
436 LOGD("orgEntries.size() is [%zu], resultLst.size() is [%zu]", orgEntries.size(),
437 resultLst.size());
438
439 if (orgEntries.size() != resultLst.size()) {
440 return false;
441 }
442
443 int index = 0;
444 for (const auto &entry : resultLst) {
445 if (entry.key != orgEntries[index].key) {
446 LOGE("CheckObserverResult failed, key of index[%d] not match", index);
447 return false;
448 }
449 if (entry.value != orgEntries[index].value) {
450 LOGE("CheckObserverResult failed, value of index[%d] not match", index);
451 return false;
452 }
453 index++;
454 }
455
456 return true;
457 }
458
IsEntryExist(const DistributedDB::Entry & entry,const std::vector<DistributedDB::Entry> & entries)459 bool DistributedDBToolsUnitTest::IsEntryExist(const DistributedDB::Entry &entry,
460 const std::vector<DistributedDB::Entry> &entries)
461 {
462 std::set<std::vector<uint8_t>> sets;
463 for (const auto &iter : entries) {
464 sets.insert(iter.key);
465 }
466
467 if (entries.size() != sets.size()) {
468 return false;
469 }
470 sets.clear();
471 bool isFound = false;
472 for (const auto &iter : entries) {
473 if (entry.key == iter.key) {
474 if (entry.value == iter.value) {
475 isFound = true;
476 }
477 break;
478 }
479 }
480 return isFound;
481 }
482
IsItemValueExist(const DistributedDB::DataItem & item,const std::vector<DistributedDB::DataItem> & items)483 bool DistributedDBToolsUnitTest::IsItemValueExist(const DistributedDB::DataItem &item,
484 const std::vector<DistributedDB::DataItem> &items)
485 {
486 std::set<Key> sets;
487 for (const auto &iter : items) {
488 sets.insert(iter.key);
489 }
490
491 if (items.size() != sets.size()) {
492 return false;
493 }
494 sets.clear();
495 bool isFound = false;
496 for (const auto &iter : items) {
497 if (item.key == iter.key) {
498 if (item.value == iter.value) {
499 isFound = true;
500 }
501 break;
502 }
503 }
504 return isFound;
505 }
506
IsKvEntryExist(const DistributedDB::Entry & entry,const std::vector<DistributedDB::Entry> & entries)507 bool DistributedDBToolsUnitTest::IsKvEntryExist(const DistributedDB::Entry &entry,
508 const std::vector<DistributedDB::Entry> &entries)
509 {
510 std::set<std::vector<uint8_t>> sets;
511 for (const auto &iter : entries) {
512 sets.insert(iter.key);
513 }
514
515 if (entries.size() != sets.size()) {
516 return false;
517 }
518 sets.clear();
519 bool isFound = false;
520 for (const auto &iter : entries) {
521 if (entry.key == iter.key) {
522 if (entry.value == iter.value) {
523 isFound = true;
524 }
525 break;
526 }
527 }
528
529 return isFound;
530 }
531
ModifyDatabaseFile(const std::string & fileDir,uint64_t modifyPos,uint32_t modifyCnt,uint32_t value)532 int DistributedDBToolsUnitTest::ModifyDatabaseFile(const std::string &fileDir, uint64_t modifyPos,
533 uint32_t modifyCnt, uint32_t value)
534 {
535 LOGI("Modify database file:%s", fileDir.c_str());
536 std::fstream dataFile(fileDir, std::fstream::binary | std::fstream::out | std::fstream::in);
537 if (!dataFile.is_open()) {
538 LOGD("Open the database file failed");
539 return -E_UNEXPECTED_DATA;
540 }
541
542 if (!dataFile.seekg(0, std::fstream::end)) {
543 return -E_UNEXPECTED_DATA;
544 }
545
546 uint64_t fileSize;
547 std::ios::pos_type pos = dataFile.tellg();
548 if (pos < 0) {
549 return -E_UNEXPECTED_DATA;
550 } else {
551 fileSize = static_cast<uint64_t>(pos);
552 if (fileSize < 1024) { // the least page size is 1024 bytes.
553 LOGE("Invalid database file:%" PRIu64 ".", fileSize);
554 return -E_UNEXPECTED_DATA;
555 }
556 }
557
558 if (fileSize <= modifyPos) {
559 return E_OK;
560 }
561
562 if (!dataFile.seekp(modifyPos)) {
563 return -E_UNEXPECTED_DATA;
564 }
565 for (uint32_t i = 0; i < modifyCnt; i++) {
566 if (!dataFile.write(reinterpret_cast<char *>(&value), sizeof(uint32_t))) {
567 return -E_UNEXPECTED_DATA;
568 }
569 }
570
571 dataFile.flush();
572 return E_OK;
573 }
574
GetSyncDataTest(const SyncInputArg & syncInputArg,SQLiteSingleVerNaturalStore * store,std::vector<DataItem> & dataItems,ContinueToken & continueStmtToken)575 int DistributedDBToolsUnitTest::GetSyncDataTest(const SyncInputArg &syncInputArg, SQLiteSingleVerNaturalStore *store,
576 std::vector<DataItem> &dataItems, ContinueToken &continueStmtToken)
577 {
578 std::vector<SingleVerKvEntry *> entries;
579 DataSizeSpecInfo syncDataSizeInfo = {syncInputArg.blockSize_, DBConstant::MAX_HPMODE_PACK_ITEM_SIZE};
580 int errCode = store->GetSyncData(syncInputArg.begin_, syncInputArg.end_, entries,
581 continueStmtToken, syncDataSizeInfo);
582
583 ConvertSingleVerEntryToItems(entries, dataItems);
584 return errCode;
585 }
586
GetSyncDataNextTest(SQLiteSingleVerNaturalStore * store,uint32_t blockSize,std::vector<DataItem> & dataItems,ContinueToken & continueStmtToken)587 int DistributedDBToolsUnitTest::GetSyncDataNextTest(SQLiteSingleVerNaturalStore *store, uint32_t blockSize,
588 std::vector<DataItem> &dataItems, ContinueToken &continueStmtToken)
589 {
590 std::vector<SingleVerKvEntry *> entries;
591 DataSizeSpecInfo syncDataSizeInfo = {blockSize, DBConstant::MAX_HPMODE_PACK_ITEM_SIZE};
592 int errCode = store->GetSyncDataNext(entries, continueStmtToken, syncDataSizeInfo);
593
594 ConvertSingleVerEntryToItems(entries, dataItems);
595 return errCode;
596 }
597
PutSyncDataTest(SQLiteSingleVerNaturalStore * store,const std::vector<DataItem> & dataItems,const std::string & deviceName)598 int DistributedDBToolsUnitTest::PutSyncDataTest(SQLiteSingleVerNaturalStore *store,
599 const std::vector<DataItem> &dataItems, const std::string &deviceName)
600 {
601 QueryObject query(Query::Select());
602 return PutSyncDataTest(store, dataItems, deviceName, query);
603 }
604
PutSyncDataTest(SQLiteSingleVerNaturalStore * store,const std::vector<DataItem> & dataItems,const std::string & deviceName,const QueryObject & query)605 int DistributedDBToolsUnitTest::PutSyncDataTest(SQLiteSingleVerNaturalStore *store,
606 const std::vector<DataItem> &dataItems, const std::string &deviceName, const QueryObject &query)
607 {
608 std::vector<SingleVerKvEntry *> entries;
609 std::vector<DistributedDB::DataItem> items = dataItems;
610 for (auto &item : items) {
611 auto *entry = new (std::nothrow) GenericSingleVerKvEntry();
612 if (entry == nullptr) {
613 ReleaseSingleVerEntry(entries);
614 return -E_OUT_OF_MEMORY;
615 }
616 entry->SetEntryData(std::move(item));
617 entry->SetWriteTimestamp(entry->GetTimestamp());
618 entries.push_back(entry);
619 }
620
621 int errCode = store->PutSyncDataWithQuery(query, entries, deviceName);
622 ReleaseSingleVerEntry(entries);
623 return errCode;
624 }
625
ConvertItemsToSingleVerEntry(const std::vector<DistributedDB::DataItem> & dataItems,std::vector<DistributedDB::SingleVerKvEntry * > & entries)626 int DistributedDBToolsUnitTest::ConvertItemsToSingleVerEntry(const std::vector<DistributedDB::DataItem> &dataItems,
627 std::vector<DistributedDB::SingleVerKvEntry *> &entries)
628 {
629 std::vector<DistributedDB::DataItem> items = dataItems;
630 for (auto &item : items) {
631 GenericSingleVerKvEntry *entry = new (std::nothrow) GenericSingleVerKvEntry();
632 if (entry == nullptr) {
633 ReleaseSingleVerEntry(entries);
634 return -E_OUT_OF_MEMORY;
635 }
636 entry->SetEntryData(std::move(item));
637 entries.push_back(entry);
638 }
639 return E_OK;
640 }
641
ConvertSingleVerEntryToItems(std::vector<DistributedDB::SingleVerKvEntry * > & entries,std::vector<DistributedDB::DataItem> & dataItems)642 void DistributedDBToolsUnitTest::ConvertSingleVerEntryToItems(std::vector<DistributedDB::SingleVerKvEntry *> &entries,
643 std::vector<DistributedDB::DataItem> &dataItems)
644 {
645 for (auto &itemEntry : entries) {
646 GenericSingleVerKvEntry *entry = reinterpret_cast<GenericSingleVerKvEntry *>(itemEntry);
647 if (entry != nullptr) {
648 DataItem item;
649 item.origDev = entry->GetOrigDevice();
650 item.flag = entry->GetFlag();
651 item.timestamp = entry->GetTimestamp();
652 entry->GetKey(item.key);
653 entry->GetValue(item.value);
654 dataItems.push_back(item);
655 // clear vector entry
656 delete itemEntry;
657 itemEntry = nullptr;
658 }
659 }
660 entries.clear();
661 }
662
ReleaseSingleVerEntry(std::vector<DistributedDB::SingleVerKvEntry * > & entries)663 void DistributedDBToolsUnitTest::ReleaseSingleVerEntry(std::vector<DistributedDB::SingleVerKvEntry *> &entries)
664 {
665 for (auto &item : entries) {
666 delete item;
667 item = nullptr;
668 }
669 entries.clear();
670 }
671
CalcHash(const std::vector<uint8_t> & value,std::vector<uint8_t> & hashValue)672 void DistributedDBToolsUnitTest::CalcHash(const std::vector<uint8_t> &value, std::vector<uint8_t> &hashValue)
673 {
674 ValueHashCalc hashCalc;
675 hashCalc.Initialize();
676 hashCalc.Update(value);
677 hashCalc.GetResult(hashValue);
678 }
679
Dump()680 void DistributedDBToolsUnitTest::Dump()
681 {
682 constexpr const char *rightDumpParam = "--database";
683 constexpr const char *ignoreDumpParam = "ignore-param";
684 const std::u16string u16DumpRightParam =
685 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(rightDumpParam);
686 const std::u16string u16DumpIgnoreParam =
687 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(ignoreDumpParam);
688 std::vector<std::u16string> params = {
689 u16DumpRightParam,
690 u16DumpIgnoreParam
691 };
692 // print to std::cout
693 RuntimeConfig::Dump(0, params);
694 }
695
GetKvNbStoreDirectory(const std::string & identifier,const std::string & dbFilePath,const std::string & dbDir)696 std::string DistributedDBToolsUnitTest::GetKvNbStoreDirectory(const std::string &identifier,
697 const std::string &dbFilePath, const std::string &dbDir)
698 {
699 std::string identifierName = DBCommon::TransferStringToHex(identifier);
700 return dbDir + "/" + identifierName + "/" + dbFilePath;
701 }
702
KvStoreObserverUnitTest()703 KvStoreObserverUnitTest::KvStoreObserverUnitTest() : callCount_(0), isCleared_(false)
704 {}
705
OnChange(const KvStoreChangedData & data)706 void KvStoreObserverUnitTest::OnChange(const KvStoreChangedData& data)
707 {
708 callCount_++;
709 inserted_ = data.GetEntriesInserted();
710 updated_ = data.GetEntriesUpdated();
711 deleted_ = data.GetEntriesDeleted();
712 isCleared_ = data.IsCleared();
713 LOGD("Onchangedata :%zu -- %zu -- %zu -- %d", inserted_.size(), updated_.size(), deleted_.size(), isCleared_);
714 LOGD("Onchange() called success!");
715 }
716
OnChange(const DistributedDB::StoreChangedData & data)717 void KvStoreObserverUnitTest::OnChange(const DistributedDB::StoreChangedData &data)
718 {
719 (void)data;
720 KvStoreObserver::OnChange(data);
721 }
722
OnChange(DistributedDB::StoreObserver::StoreChangedInfo && data)723 void KvStoreObserverUnitTest::OnChange(DistributedDB::StoreObserver::StoreChangedInfo &&data)
724 {
725 (void)data;
726 KvStoreObserver::OnChange(std::move(data));
727 }
728
OnChange(DistributedDB::Origin origin,const std::string & originalId,DistributedDB::ChangedData && data)729 void KvStoreObserverUnitTest::OnChange(DistributedDB::Origin origin, const std::string &originalId,
730 DistributedDB::ChangedData &&data)
731 {
732 (void)origin;
733 (void)originalId;
734 (void)data;
735 KvStoreObserver::OnChange(origin, originalId, std::move(data));
736 }
737
ResetToZero()738 void KvStoreObserverUnitTest::ResetToZero()
739 {
740 callCount_ = 0;
741 isCleared_ = false;
742 inserted_.clear();
743 updated_.clear();
744 deleted_.clear();
745 }
746
GetCallCount() const747 unsigned long KvStoreObserverUnitTest::GetCallCount() const
748 {
749 return callCount_;
750 }
751
GetEntriesInserted() const752 const std::list<Entry> &KvStoreObserverUnitTest::GetEntriesInserted() const
753 {
754 return inserted_;
755 }
756
GetEntriesUpdated() const757 const std::list<Entry> &KvStoreObserverUnitTest::GetEntriesUpdated() const
758 {
759 return updated_;
760 }
761
GetEntriesDeleted() const762 const std::list<Entry> &KvStoreObserverUnitTest::GetEntriesDeleted() const
763 {
764 return deleted_;
765 }
766
IsCleared() const767 bool KvStoreObserverUnitTest::IsCleared() const
768 {
769 return isCleared_;
770 }
771
RelationalStoreObserverUnitTest()772 RelationalStoreObserverUnitTest::RelationalStoreObserverUnitTest() : callCount_(0)
773 {
774 }
775
GetCallCount() const776 unsigned long RelationalStoreObserverUnitTest::GetCallCount() const
777 {
778 return callCount_;
779 }
780
GetCloudCallCount() const781 unsigned long RelationalStoreObserverUnitTest::GetCloudCallCount() const
782 {
783 return cloudCallCount_;
784 }
785
OnChange(const StoreChangedData & data)786 void RelationalStoreObserverUnitTest::OnChange(const StoreChangedData &data)
787 {
788 callCount_++;
789 changeDevice_ = data.GetDataChangeDevice();
790 data.GetStoreProperty(storeProperty_);
791 LOGD("Onchangedata : %s", changeDevice_.c_str());
792 LOGD("Onchange() called success!");
793 }
794
OnChange(DistributedDB::Origin origin,const std::string & originalId,DistributedDB::ChangedData && data)795 void RelationalStoreObserverUnitTest::OnChange(
796 DistributedDB::Origin origin, const std::string &originalId, DistributedDB::ChangedData &&data)
797 {
798 cloudCallCount_++;
799 savedChangedData_[data.tableName] = data;
800 LOGD("cloud sync Onchangedata, tableName = %s", data.tableName.c_str());
801 }
802
GetCallbackDetailsType() const803 uint32_t RelationalStoreObserverUnitTest::GetCallbackDetailsType() const
804 {
805 return detailsType_;
806 }
807
SetCallbackDetailsType(uint32_t type)808 void RelationalStoreObserverUnitTest::SetCallbackDetailsType(uint32_t type)
809 {
810 detailsType_ = type;
811 }
812
SetExpectedResult(const DistributedDB::ChangedData & changedData)813 void RelationalStoreObserverUnitTest::SetExpectedResult(const DistributedDB::ChangedData &changedData)
814 {
815 expectedChangedData_[changedData.tableName] = changedData;
816 }
817
IsPrimaryKeyEq(DistributedDB::Type & input,DistributedDB::Type & expected)818 static bool IsPrimaryKeyEq(DistributedDB::Type &input, DistributedDB::Type &expected)
819 {
820 if (input.index() != expected.index()) {
821 return false;
822 }
823 switch (expected.index()) {
824 case TYPE_INDEX<int64_t>:
825 if (std::get<int64_t>(input) != std::get<int64_t>(expected)) {
826 return false;
827 }
828 break;
829 case TYPE_INDEX<std::string>:
830 if (std::get<std::string>(input) != std::get<std::string>(expected)) {
831 return false;
832 }
833 break;
834 case TYPE_INDEX<bool>:
835 if (std::get<bool>(input) != std::get<bool>(expected)) {
836 return false;
837 }
838 break;
839 case TYPE_INDEX<double>:
840 case TYPE_INDEX<Bytes>:
841 case TYPE_INDEX<Asset>:
842 case TYPE_INDEX<Assets>:
843 LOGE("NOT HANDLE THIS SITUATION");
844 return false;
845 default: {
846 break;
847 }
848 }
849 return true;
850 }
851
IsPrimaryDataEq(uint64_t type,DistributedDB::ChangedData & input,DistributedDB::ChangedData & expected)852 static bool IsPrimaryDataEq(
853 uint64_t type, DistributedDB::ChangedData &input, DistributedDB::ChangedData &expected)
854 {
855 for (size_t m = 0; m < input.primaryData[type].size(); m++) {
856 if (m >= expected.primaryData[type].size()) {
857 LOGE("Actual primary data's size is more than the expected!");
858 return false;
859 }
860 if (input.primaryData[type][m].size() != expected.primaryData[type][m].size()) {
861 LOGE("Primary data fields' size is not equal!");
862 return false;
863 }
864 for (size_t k = 0; k < input.primaryData[type][m].size(); k++) {
865 if (!IsPrimaryKeyEq(input.primaryData[type][m][k], expected.primaryData[type][m][k])) {
866 return false;
867 }
868 }
869 }
870 return true;
871 }
872
IsAllTypePrimaryDataEq(DistributedDB::ChangedData & input,DistributedDB::ChangedData & expected)873 static bool IsAllTypePrimaryDataEq(DistributedDB::ChangedData &input, DistributedDB::ChangedData &expected)
874 {
875 for (uint64_t type = ChangeType::OP_INSERT; type < ChangeType::OP_BUTT; ++type) {
876 if (!IsPrimaryDataEq(type, input, expected)) {
877 return false;
878 }
879 }
880 return true;
881 }
882
isChangedDataEq(DistributedDB::ChangedData & input,DistributedDB::ChangedData & expected)883 static bool isChangedDataEq(DistributedDB::ChangedData &input, DistributedDB::ChangedData &expected)
884 {
885 if (input.tableName != expected.tableName) {
886 return false;
887 }
888 if (input.properties.isTrackedDataChange != expected.properties.isTrackedDataChange) {
889 return false;
890 }
891 if (input.field.size() != expected.field.size()) {
892 return false;
893 }
894 for (size_t i = 0; i < input.field.size(); i++) {
895 if (!DBCommon::CaseInsensitiveCompare(input.field[i], expected.field[i])) {
896 return false;
897 }
898 }
899 return IsAllTypePrimaryDataEq(input, expected);
900 }
901
IsAllChangedDataEq()902 bool RelationalStoreObserverUnitTest::IsAllChangedDataEq()
903 {
904 for (auto iter = expectedChangedData_.begin(); iter != expectedChangedData_.end(); ++iter) {
905 auto iterInSavedChangedData = savedChangedData_.find(iter->first);
906 if (iterInSavedChangedData == savedChangedData_.end()) {
907 return false;
908 }
909 if (!isChangedDataEq(iterInSavedChangedData->second, iter->second)) {
910 return false;
911 }
912 }
913 return true;
914 }
915
ClearChangedData()916 void RelationalStoreObserverUnitTest::ClearChangedData()
917 {
918 expectedChangedData_.clear();
919 savedChangedData_.clear();
920 }
921
ResetToZero()922 void RelationalStoreObserverUnitTest::ResetToZero()
923 {
924 callCount_ = 0;
925 changeDevice_.clear();
926 storeProperty_ = {};
927 }
928
ResetCloudSyncToZero()929 void RelationalStoreObserverUnitTest::ResetCloudSyncToZero()
930 {
931 cloudCallCount_ = 0u;
932 savedChangedData_.clear();
933 }
934
GetDataChangeDevice() const935 const std::string RelationalStoreObserverUnitTest::GetDataChangeDevice() const
936 {
937 return changeDevice_;
938 }
939
GetStoreProperty() const940 DistributedDB::StoreProperty RelationalStoreObserverUnitTest::GetStoreProperty() const
941 {
942 return storeProperty_;
943 }
944
SyncTest(KvStoreNbDelegate * delegate,const std::vector<std::string> & devices,SyncMode mode,std::map<std::string,DBStatus> & statuses,const Query & query)945 DBStatus DistributedDBToolsUnitTest::SyncTest(KvStoreNbDelegate* delegate,
946 const std::vector<std::string>& devices, SyncMode mode,
947 std::map<std::string, DBStatus>& statuses, const Query &query)
948 {
949 statuses.clear();
950 DBStatus callStatus = delegate->Sync(devices, mode,
951 [&statuses, this](const std::map<std::string, DBStatus>& statusMap) {
952 statuses = statusMap;
953 std::unique_lock<std::mutex> innerlock(this->syncLock_);
954 this->syncCondVar_.notify_one();
955 }, query, false);
956
957 std::unique_lock<std::mutex> lock(syncLock_);
958 syncCondVar_.wait(lock, [callStatus, &statuses]() {
959 if (callStatus != OK) {
960 return true;
961 }
962 return !statuses.empty();
963 });
964 return callStatus;
965 }
966
SyncTest(KvStoreNbDelegate * delegate,const std::vector<std::string> & devices,SyncMode mode,std::map<std::string,DBStatus> & statuses,bool wait)967 DBStatus DistributedDBToolsUnitTest::SyncTest(KvStoreNbDelegate* delegate,
968 const std::vector<std::string>& devices, SyncMode mode,
969 std::map<std::string, DBStatus>& statuses, bool wait)
970 {
971 statuses.clear();
972 DBStatus callStatus = delegate->Sync(devices, mode,
973 [&statuses, this](const std::map<std::string, DBStatus>& statusMap) {
974 statuses = statusMap;
975 std::unique_lock<std::mutex> innerlock(this->syncLock_);
976 this->syncCondVar_.notify_one();
977 }, wait);
978 if (!wait) {
979 std::unique_lock<std::mutex> lock(syncLock_);
980 syncCondVar_.wait(lock, [callStatus, &statuses]() {
981 if (callStatus != OK) {
982 return true;
983 }
984 if (statuses.size() != 0) {
985 return true;
986 }
987 return false;
988 });
989 }
990 return callStatus;
991 }
992
SyncTest(KvStoreNbDelegate * delegate,DeviceSyncOption option,std::map<std::string,DeviceSyncProcess> & syncProcessMap)993 DBStatus DistributedDBToolsUnitTest::SyncTest(KvStoreNbDelegate *delegate, DeviceSyncOption option,
994 std::map<std::string, DeviceSyncProcess> &syncProcessMap)
995 {
996 syncProcessMap.clear();
997 DeviceSyncProcessCallback onProcess =
998 [&syncProcessMap, this](const std::map<std::string, DeviceSyncProcess> &processMap) {
999 syncProcessMap = processMap;
1000 std::unique_lock<std::mutex> innerLock(this->syncLock_);
1001 this->syncCondVar_.notify_one();
1002 };
1003 DBStatus status = delegate->Sync(option, onProcess);
1004 if (option.isWait) {
1005 return status;
1006 }
1007 std::unique_lock<std::mutex> lock(this->syncLock_);
1008 this->syncCondVar_.wait(lock, [status, &syncProcessMap]() {
1009 if (status != OK) {
1010 return true;
1011 }
1012 if (syncProcessMap.empty()) {
1013 return false;
1014 }
1015 for (const auto &entry : syncProcessMap) {
1016 if (entry.second.process < ProcessStatus::FINISHED) {
1017 return false;
1018 }
1019 }
1020 return true;
1021 });
1022 return status;
1023 }
1024
CorruptCallBack(const std::string & appId,const std::string & userId,const std::string & storeId)1025 void KvStoreCorruptInfo::CorruptCallBack(const std::string &appId, const std::string &userId,
1026 const std::string &storeId)
1027 {
1028 DatabaseInfo databaseInfo;
1029 databaseInfo.appId = appId;
1030 databaseInfo.userId = userId;
1031 databaseInfo.storeId = storeId;
1032 LOGD("appId :%s, userId:%s, storeId:%s", appId.c_str(), userId.c_str(), storeId.c_str());
1033 databaseInfoVect_.push_back(databaseInfo);
1034 }
1035
GetDatabaseInfoSize() const1036 size_t KvStoreCorruptInfo::GetDatabaseInfoSize() const
1037 {
1038 return databaseInfoVect_.size();
1039 }
1040
IsDataBaseCorrupted(const std::string & appId,const std::string & userId,const std::string & storeId) const1041 bool KvStoreCorruptInfo::IsDataBaseCorrupted(const std::string &appId, const std::string &userId,
1042 const std::string &storeId) const
1043 {
1044 for (const auto &item : databaseInfoVect_) {
1045 if (item.appId == appId &&
1046 item.userId == userId &&
1047 item.storeId == storeId) {
1048 return true;
1049 }
1050 }
1051 return false;
1052 }
1053
Reset()1054 void KvStoreCorruptInfo::Reset()
1055 {
1056 databaseInfoVect_.clear();
1057 }
1058
GetRandInt(const int randMin,const int randMax)1059 int DistributedDBToolsUnitTest::GetRandInt(const int randMin, const int randMax)
1060 {
1061 std::random_device randDev;
1062 std::mt19937 genRand(randDev());
1063 std::uniform_int_distribution<int> disRand(randMin, randMax);
1064 return disRand(genRand);
1065 }
1066
GetRandInt64(const int64_t randMin,const int64_t randMax)1067 int64_t DistributedDBToolsUnitTest::GetRandInt64(const int64_t randMin, const int64_t randMax)
1068 {
1069 std::random_device randDev;
1070 std::mt19937_64 genRand(randDev());
1071 std::uniform_int_distribution<int64_t> disRand(randMin, randMax);
1072 return disRand(genRand);
1073 }
1074
PrintTestCaseInfo()1075 void DistributedDBToolsUnitTest::PrintTestCaseInfo()
1076 {
1077 testing::UnitTest *test = testing::UnitTest::GetInstance();
1078 ASSERT_NE(test, nullptr);
1079 const testing::TestInfo *testInfo = test->current_test_info();
1080 ASSERT_NE(testInfo, nullptr);
1081 LOGI("Start unit test: %s.%s", testInfo->test_case_name(), testInfo->name());
1082 }
1083
BuildMessage(const DataSyncMessageInfo & messageInfo,DistributedDB::Message * & message)1084 int DistributedDBToolsUnitTest::BuildMessage(const DataSyncMessageInfo &messageInfo,
1085 DistributedDB::Message *&message)
1086 {
1087 auto packet = new (std::nothrow) DataRequestPacket;
1088 if (packet == nullptr) {
1089 return -E_OUT_OF_MEMORY;
1090 }
1091 message = new (std::nothrow) Message(messageInfo.messageId_);
1092 if (message == nullptr) {
1093 delete packet;
1094 packet = nullptr;
1095 return -E_OUT_OF_MEMORY;
1096 }
1097 packet->SetBasicInfo(messageInfo.sendCode_, messageInfo.version_, messageInfo.mode_);
1098 packet->SetWaterMark(messageInfo.localMark_, messageInfo.peerMark_, messageInfo.deleteMark_);
1099 std::vector<uint64_t> reserved {messageInfo.packetId_};
1100 packet->SetReserved(reserved);
1101 message->SetMessageType(messageInfo.messageType_);
1102 message->SetSessionId(messageInfo.sessionId_);
1103 message->SetSequenceId(messageInfo.sequenceId_);
1104 message->SetExternalObject(packet);
1105 return E_OK;
1106 }
1107
CreateDataBase(const std::string & dbUri)1108 sqlite3 *RelationalTestUtils::CreateDataBase(const std::string &dbUri)
1109 {
1110 LOGD("Create database: %s", dbUri.c_str());
1111 sqlite3 *db = nullptr;
1112 if (int r = sqlite3_open_v2(dbUri.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
1113 LOGE("Open database [%s] failed. %d", dbUri.c_str(), r);
1114 if (db != nullptr) {
1115 (void)sqlite3_close_v2(db);
1116 db = nullptr;
1117 }
1118 }
1119 return db;
1120 }
1121
ExecSql(sqlite3 * db,const std::string & sql)1122 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql)
1123 {
1124 if (db == nullptr || sql.empty()) {
1125 return -E_INVALID_ARGS;
1126 }
1127 char *errMsg = nullptr;
1128 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
1129 if (errCode != SQLITE_OK && errMsg != nullptr) {
1130 LOGE("Execute sql failed. %d err: %s", errCode, errMsg);
1131 }
1132 sqlite3_free(errMsg);
1133 return errCode;
1134 }
1135
ExecSql(sqlite3 * db,const std::string & sql,const std::function<int (sqlite3_stmt *)> & bindCallback,const std::function<int (sqlite3_stmt *)> & resultCallback)1136 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql,
1137 const std::function<int (sqlite3_stmt *)> &bindCallback, const std::function<int (sqlite3_stmt *)> &resultCallback)
1138 {
1139 if (db == nullptr || sql.empty()) {
1140 return -E_INVALID_ARGS;
1141 }
1142
1143 bool bindFinish = true;
1144 sqlite3_stmt *stmt = nullptr;
1145 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1146 if (errCode != E_OK) {
1147 goto END;
1148 }
1149
1150 do {
1151 if (bindCallback) {
1152 errCode = bindCallback(stmt);
1153 if (errCode != E_OK && errCode != -E_UNFINISHED) {
1154 goto END;
1155 }
1156 bindFinish = (errCode != -E_UNFINISHED); // continue bind if unfinished
1157 }
1158
1159 while (true) {
1160 errCode = SQLiteUtils::StepWithRetry(stmt);
1161 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1162 errCode = E_OK; // Step finished
1163 break;
1164 } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1165 goto END; // Step return error
1166 }
1167 if (resultCallback == nullptr) {
1168 continue;
1169 }
1170 errCode = resultCallback(stmt);
1171 if (errCode != E_OK) {
1172 goto END;
1173 }
1174 }
1175 SQLiteUtils::ResetStatement(stmt, false, errCode);
1176 } while (!bindFinish);
1177
1178 END:
1179 SQLiteUtils::ResetStatement(stmt, true, errCode);
1180 return errCode;
1181 }
1182
CreateDeviceTable(sqlite3 * db,const std::string & table,const std::string & device)1183 void RelationalTestUtils::CreateDeviceTable(sqlite3 *db, const std::string &table, const std::string &device)
1184 {
1185 ASSERT_NE(db, nullptr);
1186 std::string deviceTable = DBCommon::GetDistributedTableName(device, table);
1187 TableInfo baseTbl;
1188 ASSERT_EQ(SQLiteUtils::AnalysisSchema(db, table, baseTbl), E_OK);
1189 EXPECT_EQ(SQLiteUtils::CreateSameStuTable(db, baseTbl, deviceTable), E_OK);
1190 EXPECT_EQ(SQLiteUtils::CloneIndexes(db, table, deviceTable), E_OK);
1191 }
1192
CheckSqlResult(sqlite3 * db,const std::string & sql,bool & result)1193 int RelationalTestUtils::CheckSqlResult(sqlite3 *db, const std::string &sql, bool &result)
1194 {
1195 if (db == nullptr || sql.empty()) {
1196 return -E_INVALID_ARGS;
1197 }
1198 sqlite3_stmt *stmt = nullptr;
1199 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1200 if (errCode != E_OK) {
1201 goto END;
1202 }
1203
1204 errCode = SQLiteUtils::StepWithRetry(stmt);
1205 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1206 result = true;
1207 errCode = E_OK;
1208 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1209 result = false;
1210 errCode = E_OK;
1211 }
1212 END:
1213 SQLiteUtils::ResetStatement(stmt, true, errCode);
1214 return errCode;
1215 }
1216
CheckTableRecords(sqlite3 * db,const std::string & table)1217 int RelationalTestUtils::CheckTableRecords(sqlite3 *db, const std::string &table)
1218 {
1219 if (db == nullptr || table.empty()) {
1220 return -E_INVALID_ARGS;
1221 }
1222 int count = -1;
1223 std::string sql = "select count(1) from " + table + ";";
1224
1225 sqlite3_stmt *stmt = nullptr;
1226 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1227 if (errCode != E_OK) {
1228 goto END;
1229 }
1230
1231 errCode = SQLiteUtils::StepWithRetry(stmt);
1232 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1233 count = sqlite3_column_int(stmt, 0);
1234 }
1235 END:
1236 SQLiteUtils::ResetStatement(stmt, true, errCode);
1237 return count;
1238 }
1239
GetMetaData(sqlite3 * db,const DistributedDB::Key & key,DistributedDB::Value & value)1240 int RelationalTestUtils::GetMetaData(sqlite3 *db, const DistributedDB::Key &key, DistributedDB::Value &value)
1241 {
1242 if (db == nullptr) {
1243 return -E_INVALID_ARGS;
1244 }
1245
1246 std::string sql = "SELECT value FROM " + DBConstant::RELATIONAL_PREFIX + "metadata WHERE key = ?;";
1247 sqlite3_stmt *stmt = nullptr;
1248 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1249 if (errCode != E_OK) {
1250 goto END;
1251 }
1252 errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key);
1253 if (errCode != E_OK) {
1254 goto END;
1255 }
1256
1257 errCode = SQLiteUtils::StepWithRetry(stmt);
1258 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1259 errCode = SQLiteUtils::GetColumnBlobValue(stmt, 0, value);
1260 }
1261 END:
1262 SQLiteUtils::ResetStatement(stmt, true, errCode);
1263 return errCode;
1264 }
1265
SetMetaData(sqlite3 * db,const DistributedDB::Key & key,const DistributedDB::Value & value)1266 int RelationalTestUtils::SetMetaData(sqlite3 *db, const DistributedDB::Key &key, const DistributedDB::Value &value)
1267 {
1268 if (db == nullptr) {
1269 return -E_INVALID_ARGS;
1270 }
1271
1272 std::string sql = "INSERT OR REPLACE INTO " + DBConstant::RELATIONAL_PREFIX + "metadata VALUES (?, ?);";
1273 sqlite3_stmt *stmt = nullptr;
1274 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1275 if (errCode != E_OK) {
1276 goto END;
1277 }
1278 errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key);
1279 if (errCode != E_OK) {
1280 goto END;
1281 }
1282 errCode = SQLiteUtils::BindBlobToStatement(stmt, 2, value); // 2: bind index
1283 if (errCode != E_OK) {
1284 goto END;
1285 }
1286
1287 errCode = SQLiteUtils::StepWithRetry(stmt);
1288 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1289 errCode = E_OK;
1290 }
1291 END:
1292 SQLiteUtils::ResetStatement(stmt, true, errCode);
1293 return SQLiteUtils::MapSQLiteErrno(errCode);
1294 }
1295
CloudBlockSync(const DistributedDB::Query & query,DistributedDB::RelationalStoreDelegate * delegate,DistributedDB::DBStatus expect,DistributedDB::DBStatus callbackExpect)1296 void RelationalTestUtils::CloudBlockSync(const DistributedDB::Query &query,
1297 DistributedDB::RelationalStoreDelegate *delegate, DistributedDB::DBStatus expect,
1298 DistributedDB::DBStatus callbackExpect)
1299 {
1300 ASSERT_NE(delegate, nullptr);
1301 std::mutex dataMutex;
1302 std::condition_variable cv;
1303 bool finish = false;
1304 auto callback = [callbackExpect, &cv, &dataMutex, &finish](const std::map<std::string, SyncProcess> &process) {
1305 for (const auto &item: process) {
1306 if (item.second.process == DistributedDB::FINISHED) {
1307 {
1308 std::lock_guard<std::mutex> autoLock(dataMutex);
1309 finish = true;
1310 }
1311 EXPECT_EQ(item.second.errCode, callbackExpect);
1312 cv.notify_one();
1313 }
1314 }
1315 };
1316 ASSERT_EQ(delegate->Sync({ "CLOUD" }, SYNC_MODE_CLOUD_MERGE, query, callback, DBConstant::MAX_TIMEOUT), expect);
1317 if (expect != DistributedDB::DBStatus::OK) {
1318 return;
1319 }
1320 std::unique_lock<std::mutex> uniqueLock(dataMutex);
1321 cv.wait(uniqueLock, [&finish]() {
1322 return finish;
1323 });
1324 }
1325
SelectData(sqlite3 * db,const DistributedDB::TableSchema & schema,std::vector<DistributedDB::VBucket> & data)1326 int RelationalTestUtils::SelectData(sqlite3 *db, const DistributedDB::TableSchema &schema,
1327 std::vector<DistributedDB::VBucket> &data)
1328 {
1329 LOGD("[RelationalTestUtils] Begin select data");
1330 int errCode = E_OK;
1331 std::string selectSql = "SELECT ";
1332 for (const auto &field : schema.fields) {
1333 selectSql += field.colName + ",";
1334 }
1335 selectSql.pop_back();
1336 selectSql += " FROM " + schema.name;
1337 sqlite3_stmt *statement = nullptr;
1338 errCode = SQLiteUtils::GetStatement(db, selectSql, statement);
1339 if (errCode != E_OK) {
1340 LOGE("[RelationalTestUtils] Prepare statement failed %d", errCode);
1341 return errCode;
1342 }
1343 do {
1344 errCode = SQLiteUtils::StepWithRetry(statement, false);
1345 errCode = (errCode == -SQLITE_ROW) ? E_OK :
1346 (errCode == -SQLITE_DONE) ? -E_FINISHED : errCode;
1347 if (errCode != E_OK) {
1348 break;
1349 }
1350 VBucket rowData;
1351 for (size_t index = 0; index < schema.fields.size(); ++index) {
1352 Type colValue;
1353 int ret = SQLiteRelationalUtils::GetCloudValueByType(statement, schema.fields[index].type, index, colValue);
1354 if (ret != E_OK) {
1355 LOGE("[RelationalTestUtils] Get col value failed %d", ret);
1356 break;
1357 }
1358 rowData[schema.fields[index].colName] = colValue;
1359 }
1360 data.push_back(rowData);
1361 } while (errCode == E_OK);
1362 if (errCode == -E_FINISHED) {
1363 errCode = E_OK;
1364 }
1365 int err = E_OK;
1366 SQLiteUtils::ResetStatement(statement, true, err);
1367 LOGW("[RelationalTestUtils] Select data finished errCode %d", errCode);
1368 return errCode != E_OK ? errCode : err;
1369 }
1370
GetAssets(const DistributedDB::Type & value,const std::shared_ptr<DistributedDB::ICloudDataTranslate> & translate,bool isAsset)1371 DistributedDB::Assets RelationalTestUtils::GetAssets(const DistributedDB::Type &value,
1372 const std::shared_ptr<DistributedDB::ICloudDataTranslate> &translate, bool isAsset)
1373 {
1374 DistributedDB::Assets assets;
1375 if (value.index() == TYPE_INDEX<Assets>) {
1376 auto tmp = std::get<Assets>(value);
1377 assets.insert(assets.end(), tmp.begin(), tmp.end());
1378 } else if (value.index() == TYPE_INDEX<Asset>) {
1379 assets.push_back(std::get<Asset>(value));
1380 } else if (value.index() == TYPE_INDEX<Bytes> && translate != nullptr) {
1381 if (isAsset) {
1382 auto tmpAsset = translate->BlobToAsset(std::get<Bytes>(value));
1383 assets.push_back(tmpAsset);
1384 } else {
1385 auto tmpAssets = translate->BlobToAssets(std::get<Bytes>(value));
1386 assets.insert(assets.end(), tmpAssets.begin(), tmpAssets.end());
1387 }
1388 }
1389 return assets;
1390 }
1391
InsertCloudRecord(int64_t begin,int64_t count,const std::string & tableName,const std::shared_ptr<DistributedDB::VirtualCloudDb> & cloudDbPtr,int32_t assetCount)1392 DistributedDB::DBStatus RelationalTestUtils::InsertCloudRecord(int64_t begin, int64_t count,
1393 const std::string &tableName, const std::shared_ptr<DistributedDB::VirtualCloudDb> &cloudDbPtr, int32_t assetCount)
1394 {
1395 if (cloudDbPtr == nullptr) {
1396 LOGE("[RelationalTestUtils] Not support insert cloud with null");
1397 return DistributedDB::DBStatus::DB_ERROR;
1398 }
1399 std::vector<VBucket> record;
1400 std::vector<VBucket> extend;
1401 Timestamp now = DistributedDB::TimeHelper::GetSysCurrentTime();
1402 for (int64_t i = begin; i < (begin + count); ++i) {
1403 VBucket data;
1404 data.insert_or_assign("id", std::to_string(i));
1405 data.insert_or_assign("name", "Cloud" + std::to_string(i));
1406 Assets assets;
1407 std::string assetNameBegin = "Phone" + std::to_string(i);
1408 for (int j = 1; j <= assetCount; ++j) {
1409 Asset asset;
1410 asset.name = assetNameBegin + "_" + std::to_string(j);
1411 asset.status = AssetStatus::INSERT;
1412 asset.hash = "DEC";
1413 asset.assetId = std::to_string(j);
1414 assets.push_back(asset);
1415 }
1416 data.insert_or_assign("assets", assets);
1417 record.push_back(data);
1418 VBucket log;
1419 log.insert_or_assign(DistributedDB::CloudDbConstant::CREATE_FIELD, static_cast<int64_t>(
1420 now / DistributedDB::CloudDbConstant::TEN_THOUSAND));
1421 log.insert_or_assign(DistributedDB::CloudDbConstant::MODIFY_FIELD, static_cast<int64_t>(
1422 now / DistributedDB::CloudDbConstant::TEN_THOUSAND));
1423 log.insert_or_assign(DistributedDB::CloudDbConstant::DELETE_FIELD, false);
1424 extend.push_back(log);
1425 }
1426 return cloudDbPtr->BatchInsert(tableName, std::move(record), extend);
1427 }
1428
GetAllAssets(sqlite3 * db,const DistributedDB::TableSchema & schema,const std::shared_ptr<DistributedDB::ICloudDataTranslate> & translate)1429 std::vector<DistributedDB::Assets> RelationalTestUtils::GetAllAssets(sqlite3 *db,
1430 const DistributedDB::TableSchema &schema, const std::shared_ptr<DistributedDB::ICloudDataTranslate> &translate)
1431 {
1432 std::vector<DistributedDB::Assets> res;
1433 if (db == nullptr || translate == nullptr) {
1434 LOGW("[RelationalTestUtils] DB or translate is null");
1435 return res;
1436 }
1437 std::vector<VBucket> allData;
1438 EXPECT_EQ(RelationalTestUtils::SelectData(db, schema, allData), E_OK);
1439 std::map<std::string, int32_t> assetFields;
1440 for (const auto &field : schema.fields) {
1441 if (field.type != TYPE_INDEX<Asset> && field.type != TYPE_INDEX<Assets>) {
1442 continue;
1443 }
1444 assetFields[field.colName] = field.type;
1445 }
1446 for (const auto &oneRow : allData) {
1447 Assets assets;
1448 for (const auto &[col, data] : oneRow) {
1449 if (assetFields.find(col) == assetFields.end()) {
1450 continue;
1451 }
1452 auto tmpAssets = GetAssets(data, translate, (assetFields[col] == TYPE_INDEX<Asset>));
1453 assets.insert(assets.end(), tmpAssets.begin(), tmpAssets.end());
1454 }
1455 res.push_back(assets);
1456 }
1457 return res;
1458 }
1459
GetRecordLog(sqlite3 * db,const std::string & tableName,std::vector<DistributedDB::VBucket> & records)1460 int RelationalTestUtils::GetRecordLog(sqlite3 *db, const std::string &tableName,
1461 std::vector<DistributedDB::VBucket> &records)
1462 {
1463 DistributedDB::TableSchema schema;
1464 schema.name = DBCommon::GetLogTableName(tableName);
1465 Field field;
1466 field.type = TYPE_INDEX<int64_t>;
1467 field.colName = "data_key";
1468 schema.fields.push_back(field);
1469 field.colName = "flag";
1470 schema.fields.push_back(field);
1471 field.colName = "cursor";
1472 schema.fields.push_back(field);
1473 field.colName = "cloud_gid";
1474 field.type = TYPE_INDEX<std::string>;
1475 schema.fields.push_back(field);
1476 return SelectData(db, schema, records);
1477 }
1478
DeleteRecord(sqlite3 * db,const std::string & tableName,const std::vector<std::map<std::string,std::string>> & conditions)1479 int RelationalTestUtils::DeleteRecord(sqlite3 *db, const std::string &tableName,
1480 const std::vector<std::map<std::string, std::string>> &conditions)
1481 {
1482 if (db == nullptr || tableName.empty()) {
1483 LOGE("[RelationalTestUtils] db is null or table is empty");
1484 return -E_INVALID_ARGS;
1485 }
1486 int errCode = E_OK;
1487 for (const auto &condition : conditions) {
1488 std::string deleteSql = "DELETE FROM " + tableName + " WHERE ";
1489 int count = 0;
1490 for (const auto &[col, value] : condition) {
1491 if (count > 0) {
1492 deleteSql += " AND ";
1493 }
1494 deleteSql += col + "=" + value;
1495 count++;
1496 }
1497 LOGD("[RelationalTestUtils] Sql is %s", deleteSql.c_str());
1498 errCode = ExecSql(db, deleteSql);
1499 if (errCode != E_OK) {
1500 return errCode;
1501 }
1502 }
1503 return errCode;
1504 }
1505
IsSupport()1506 bool DBInfoHandleTest::IsSupport()
1507 {
1508 std::lock_guard<std::mutex> autoLock(supportMutex_);
1509 return localIsSupport_;
1510 }
1511
IsNeedAutoSync(const std::string & userId,const std::string & appId,const std::string & storeId,const DeviceInfos & devInfo)1512 bool DBInfoHandleTest::IsNeedAutoSync(const std::string &userId, const std::string &appId, const std::string &storeId,
1513 const DeviceInfos &devInfo)
1514 {
1515 std::lock_guard<std::mutex> autoLock(autoSyncMutex_);
1516 return isNeedAutoSync_;
1517 }
1518
SetLocalIsSupport(bool isSupport)1519 void DBInfoHandleTest::SetLocalIsSupport(bool isSupport)
1520 {
1521 std::lock_guard<std::mutex> autoLock(supportMutex_);
1522 localIsSupport_ = isSupport;
1523 }
1524
SetNeedAutoSync(bool needAutoSync)1525 void DBInfoHandleTest::SetNeedAutoSync(bool needAutoSync)
1526 {
1527 std::lock_guard<std::mutex> autoLock(autoSyncMutex_);
1528 isNeedAutoSync_ = needAutoSync;
1529 }
1530 } // namespace DistributedDBUnitTest
1531