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
CorruptCallBack(const std::string & appId,const std::string & userId,const std::string & storeId)993 void KvStoreCorruptInfo::CorruptCallBack(const std::string &appId, const std::string &userId,
994 const std::string &storeId)
995 {
996 DatabaseInfo databaseInfo;
997 databaseInfo.appId = appId;
998 databaseInfo.userId = userId;
999 databaseInfo.storeId = storeId;
1000 LOGD("appId :%s, userId:%s, storeId:%s", appId.c_str(), userId.c_str(), storeId.c_str());
1001 databaseInfoVect_.push_back(databaseInfo);
1002 }
1003
GetDatabaseInfoSize() const1004 size_t KvStoreCorruptInfo::GetDatabaseInfoSize() const
1005 {
1006 return databaseInfoVect_.size();
1007 }
1008
IsDataBaseCorrupted(const std::string & appId,const std::string & userId,const std::string & storeId) const1009 bool KvStoreCorruptInfo::IsDataBaseCorrupted(const std::string &appId, const std::string &userId,
1010 const std::string &storeId) const
1011 {
1012 for (const auto &item : databaseInfoVect_) {
1013 if (item.appId == appId &&
1014 item.userId == userId &&
1015 item.storeId == storeId) {
1016 return true;
1017 }
1018 }
1019 return false;
1020 }
1021
Reset()1022 void KvStoreCorruptInfo::Reset()
1023 {
1024 databaseInfoVect_.clear();
1025 }
1026
GetRandInt(const int randMin,const int randMax)1027 int DistributedDBToolsUnitTest::GetRandInt(const int randMin, const int randMax)
1028 {
1029 std::random_device randDev;
1030 std::mt19937 genRand(randDev());
1031 std::uniform_int_distribution<int> disRand(randMin, randMax);
1032 return disRand(genRand);
1033 }
1034
GetRandInt64(const int64_t randMin,const int64_t randMax)1035 int64_t DistributedDBToolsUnitTest::GetRandInt64(const int64_t randMin, const int64_t randMax)
1036 {
1037 std::random_device randDev;
1038 std::mt19937_64 genRand(randDev());
1039 std::uniform_int_distribution<int64_t> disRand(randMin, randMax);
1040 return disRand(genRand);
1041 }
1042
PrintTestCaseInfo()1043 void DistributedDBToolsUnitTest::PrintTestCaseInfo()
1044 {
1045 testing::UnitTest *test = testing::UnitTest::GetInstance();
1046 ASSERT_NE(test, nullptr);
1047 const testing::TestInfo *testInfo = test->current_test_info();
1048 ASSERT_NE(testInfo, nullptr);
1049 LOGI("Start unit test: %s.%s", testInfo->test_case_name(), testInfo->name());
1050 }
1051
BuildMessage(const DataSyncMessageInfo & messageInfo,DistributedDB::Message * & message)1052 int DistributedDBToolsUnitTest::BuildMessage(const DataSyncMessageInfo &messageInfo,
1053 DistributedDB::Message *&message)
1054 {
1055 auto packet = new (std::nothrow) DataRequestPacket;
1056 if (packet == nullptr) {
1057 return -E_OUT_OF_MEMORY;
1058 }
1059 message = new (std::nothrow) Message(messageInfo.messageId_);
1060 if (message == nullptr) {
1061 delete packet;
1062 packet = nullptr;
1063 return -E_OUT_OF_MEMORY;
1064 }
1065 packet->SetBasicInfo(messageInfo.sendCode_, messageInfo.version_, messageInfo.mode_);
1066 packet->SetWaterMark(messageInfo.localMark_, messageInfo.peerMark_, messageInfo.deleteMark_);
1067 std::vector<uint64_t> reserved {messageInfo.packetId_};
1068 packet->SetReserved(reserved);
1069 message->SetMessageType(messageInfo.messageType_);
1070 message->SetSessionId(messageInfo.sessionId_);
1071 message->SetSequenceId(messageInfo.sequenceId_);
1072 message->SetExternalObject(packet);
1073 return E_OK;
1074 }
1075
CreateDataBase(const std::string & dbUri)1076 sqlite3 *RelationalTestUtils::CreateDataBase(const std::string &dbUri)
1077 {
1078 LOGD("Create database: %s", dbUri.c_str());
1079 sqlite3 *db = nullptr;
1080 if (int r = sqlite3_open_v2(dbUri.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
1081 LOGE("Open database [%s] failed. %d", dbUri.c_str(), r);
1082 if (db != nullptr) {
1083 (void)sqlite3_close_v2(db);
1084 db = nullptr;
1085 }
1086 }
1087 return db;
1088 }
1089
ExecSql(sqlite3 * db,const std::string & sql)1090 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql)
1091 {
1092 if (db == nullptr || sql.empty()) {
1093 return -E_INVALID_ARGS;
1094 }
1095 char *errMsg = nullptr;
1096 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
1097 if (errCode != SQLITE_OK && errMsg != nullptr) {
1098 LOGE("Execute sql failed. %d err: %s", errCode, errMsg);
1099 }
1100 sqlite3_free(errMsg);
1101 return errCode;
1102 }
1103
ExecSql(sqlite3 * db,const std::string & sql,const std::function<int (sqlite3_stmt *)> & bindCallback,const std::function<int (sqlite3_stmt *)> & resultCallback)1104 int RelationalTestUtils::ExecSql(sqlite3 *db, const std::string &sql,
1105 const std::function<int (sqlite3_stmt *)> &bindCallback, const std::function<int (sqlite3_stmt *)> &resultCallback)
1106 {
1107 if (db == nullptr || sql.empty()) {
1108 return -E_INVALID_ARGS;
1109 }
1110
1111 bool bindFinish = true;
1112 sqlite3_stmt *stmt = nullptr;
1113 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1114 if (errCode != E_OK) {
1115 goto END;
1116 }
1117
1118 do {
1119 if (bindCallback) {
1120 errCode = bindCallback(stmt);
1121 if (errCode != E_OK && errCode != -E_UNFINISHED) {
1122 goto END;
1123 }
1124 bindFinish = (errCode != -E_UNFINISHED); // continue bind if unfinished
1125 }
1126
1127 while (true) {
1128 errCode = SQLiteUtils::StepWithRetry(stmt);
1129 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1130 errCode = E_OK; // Step finished
1131 break;
1132 } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1133 goto END; // Step return error
1134 }
1135 if (resultCallback == nullptr) {
1136 continue;
1137 }
1138 errCode = resultCallback(stmt);
1139 if (errCode != E_OK) {
1140 goto END;
1141 }
1142 }
1143 SQLiteUtils::ResetStatement(stmt, false, errCode);
1144 } while (!bindFinish);
1145
1146 END:
1147 SQLiteUtils::ResetStatement(stmt, true, errCode);
1148 return errCode;
1149 }
1150
CreateDeviceTable(sqlite3 * db,const std::string & table,const std::string & device)1151 void RelationalTestUtils::CreateDeviceTable(sqlite3 *db, const std::string &table, const std::string &device)
1152 {
1153 ASSERT_NE(db, nullptr);
1154 std::string deviceTable = DBCommon::GetDistributedTableName(device, table);
1155 TableInfo baseTbl;
1156 ASSERT_EQ(SQLiteUtils::AnalysisSchema(db, table, baseTbl), E_OK);
1157 EXPECT_EQ(SQLiteUtils::CreateSameStuTable(db, baseTbl, deviceTable), E_OK);
1158 EXPECT_EQ(SQLiteUtils::CloneIndexes(db, table, deviceTable), E_OK);
1159 }
1160
CheckSqlResult(sqlite3 * db,const std::string & sql,bool & result)1161 int RelationalTestUtils::CheckSqlResult(sqlite3 *db, const std::string &sql, bool &result)
1162 {
1163 if (db == nullptr || sql.empty()) {
1164 return -E_INVALID_ARGS;
1165 }
1166 sqlite3_stmt *stmt = nullptr;
1167 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1168 if (errCode != E_OK) {
1169 goto END;
1170 }
1171
1172 errCode = SQLiteUtils::StepWithRetry(stmt);
1173 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1174 result = true;
1175 errCode = E_OK;
1176 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1177 result = false;
1178 errCode = E_OK;
1179 }
1180 END:
1181 SQLiteUtils::ResetStatement(stmt, true, errCode);
1182 return errCode;
1183 }
1184
CheckTableRecords(sqlite3 * db,const std::string & table)1185 int RelationalTestUtils::CheckTableRecords(sqlite3 *db, const std::string &table)
1186 {
1187 if (db == nullptr || table.empty()) {
1188 return -E_INVALID_ARGS;
1189 }
1190 int count = -1;
1191 std::string sql = "select count(1) from " + table + ";";
1192
1193 sqlite3_stmt *stmt = nullptr;
1194 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1195 if (errCode != E_OK) {
1196 goto END;
1197 }
1198
1199 errCode = SQLiteUtils::StepWithRetry(stmt);
1200 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1201 count = sqlite3_column_int(stmt, 0);
1202 }
1203 END:
1204 SQLiteUtils::ResetStatement(stmt, true, errCode);
1205 return count;
1206 }
1207
GetMetaData(sqlite3 * db,const DistributedDB::Key & key,DistributedDB::Value & value)1208 int RelationalTestUtils::GetMetaData(sqlite3 *db, const DistributedDB::Key &key, DistributedDB::Value &value)
1209 {
1210 if (db == nullptr) {
1211 return -E_INVALID_ARGS;
1212 }
1213
1214 std::string sql = "SELECT value FROM " + DBConstant::RELATIONAL_PREFIX + "metadata WHERE key = ?;";
1215 sqlite3_stmt *stmt = nullptr;
1216 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1217 if (errCode != E_OK) {
1218 goto END;
1219 }
1220 errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key);
1221 if (errCode != E_OK) {
1222 goto END;
1223 }
1224
1225 errCode = SQLiteUtils::StepWithRetry(stmt);
1226 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1227 errCode = SQLiteUtils::GetColumnBlobValue(stmt, 0, value);
1228 }
1229 END:
1230 SQLiteUtils::ResetStatement(stmt, true, errCode);
1231 return errCode;
1232 }
1233
SetMetaData(sqlite3 * db,const DistributedDB::Key & key,const DistributedDB::Value & value)1234 int RelationalTestUtils::SetMetaData(sqlite3 *db, const DistributedDB::Key &key, const DistributedDB::Value &value)
1235 {
1236 if (db == nullptr) {
1237 return -E_INVALID_ARGS;
1238 }
1239
1240 std::string sql = "INSERT OR REPLACE INTO " + DBConstant::RELATIONAL_PREFIX + "metadata VALUES (?, ?);";
1241 sqlite3_stmt *stmt = nullptr;
1242 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
1243 if (errCode != E_OK) {
1244 goto END;
1245 }
1246 errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key);
1247 if (errCode != E_OK) {
1248 goto END;
1249 }
1250 errCode = SQLiteUtils::BindBlobToStatement(stmt, 2, value); // 2: bind index
1251 if (errCode != E_OK) {
1252 goto END;
1253 }
1254
1255 errCode = SQLiteUtils::StepWithRetry(stmt);
1256 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1257 errCode = E_OK;
1258 }
1259 END:
1260 SQLiteUtils::ResetStatement(stmt, true, errCode);
1261 return SQLiteUtils::MapSQLiteErrno(errCode);
1262 }
1263
CloudBlockSync(const DistributedDB::Query & query,DistributedDB::RelationalStoreDelegate * delegate,DistributedDB::DBStatus expect,DistributedDB::DBStatus callbackExpect)1264 void RelationalTestUtils::CloudBlockSync(const DistributedDB::Query &query,
1265 DistributedDB::RelationalStoreDelegate *delegate, DistributedDB::DBStatus expect,
1266 DistributedDB::DBStatus callbackExpect)
1267 {
1268 ASSERT_NE(delegate, nullptr);
1269 std::mutex dataMutex;
1270 std::condition_variable cv;
1271 bool finish = false;
1272 auto callback = [callbackExpect, &cv, &dataMutex, &finish](const std::map<std::string, SyncProcess> &process) {
1273 for (const auto &item: process) {
1274 if (item.second.process == DistributedDB::FINISHED) {
1275 {
1276 std::lock_guard<std::mutex> autoLock(dataMutex);
1277 finish = true;
1278 }
1279 EXPECT_EQ(item.second.errCode, callbackExpect);
1280 cv.notify_one();
1281 }
1282 }
1283 };
1284 ASSERT_EQ(delegate->Sync({ "CLOUD" }, SYNC_MODE_CLOUD_MERGE, query, callback, DBConstant::MAX_TIMEOUT), expect);
1285 if (expect != DistributedDB::DBStatus::OK) {
1286 return;
1287 }
1288 std::unique_lock<std::mutex> uniqueLock(dataMutex);
1289 cv.wait(uniqueLock, [&finish]() {
1290 return finish;
1291 });
1292 }
1293
SelectData(sqlite3 * db,const DistributedDB::TableSchema & schema,std::vector<DistributedDB::VBucket> & data)1294 int RelationalTestUtils::SelectData(sqlite3 *db, const DistributedDB::TableSchema &schema,
1295 std::vector<DistributedDB::VBucket> &data)
1296 {
1297 LOGD("[RelationalTestUtils] Begin select data");
1298 int errCode = E_OK;
1299 std::string selectSql = "SELECT ";
1300 for (const auto &field : schema.fields) {
1301 selectSql += field.colName + ",";
1302 }
1303 selectSql.pop_back();
1304 selectSql += " FROM " + schema.name;
1305 sqlite3_stmt *statement = nullptr;
1306 errCode = SQLiteUtils::GetStatement(db, selectSql, statement);
1307 if (errCode != E_OK) {
1308 LOGE("[RelationalTestUtils] Prepare statement failed %d", errCode);
1309 return errCode;
1310 }
1311 do {
1312 errCode = SQLiteUtils::StepWithRetry(statement, false);
1313 errCode = (errCode == -SQLITE_ROW) ? E_OK :
1314 (errCode == -SQLITE_DONE) ? -E_FINISHED : errCode;
1315 if (errCode != E_OK) {
1316 break;
1317 }
1318 VBucket rowData;
1319 for (size_t index = 0; index < schema.fields.size(); ++index) {
1320 Type colValue;
1321 int ret = SQLiteRelationalUtils::GetCloudValueByType(statement, schema.fields[index].type, index, colValue);
1322 if (ret != E_OK) {
1323 LOGE("[RelationalTestUtils] Get col value failed %d", ret);
1324 break;
1325 }
1326 rowData[schema.fields[index].colName] = colValue;
1327 }
1328 data.push_back(rowData);
1329 } while (errCode == E_OK);
1330 if (errCode == -E_FINISHED) {
1331 errCode = E_OK;
1332 }
1333 int err = E_OK;
1334 SQLiteUtils::ResetStatement(statement, true, err);
1335 LOGW("[RelationalTestUtils] Select data finished errCode %d", errCode);
1336 return errCode != E_OK ? errCode : err;
1337 }
1338
GetAssets(const DistributedDB::Type & value,const std::shared_ptr<DistributedDB::ICloudDataTranslate> & translate,bool isAsset)1339 DistributedDB::Assets RelationalTestUtils::GetAssets(const DistributedDB::Type &value,
1340 const std::shared_ptr<DistributedDB::ICloudDataTranslate> &translate, bool isAsset)
1341 {
1342 DistributedDB::Assets assets;
1343 if (value.index() == TYPE_INDEX<Assets>) {
1344 auto tmp = std::get<Assets>(value);
1345 assets.insert(assets.end(), tmp.begin(), tmp.end());
1346 } else if (value.index() == TYPE_INDEX<Asset>) {
1347 assets.push_back(std::get<Asset>(value));
1348 } else if (value.index() == TYPE_INDEX<Bytes> && translate != nullptr) {
1349 if (isAsset) {
1350 auto tmpAsset = translate->BlobToAsset(std::get<Bytes>(value));
1351 assets.push_back(tmpAsset);
1352 } else {
1353 auto tmpAssets = translate->BlobToAssets(std::get<Bytes>(value));
1354 assets.insert(assets.end(), tmpAssets.begin(), tmpAssets.end());
1355 }
1356 }
1357 return assets;
1358 }
1359
InsertCloudRecord(int64_t begin,int64_t count,const std::string & tableName,const std::shared_ptr<DistributedDB::VirtualCloudDb> & cloudDbPtr,int32_t assetCount)1360 DistributedDB::DBStatus RelationalTestUtils::InsertCloudRecord(int64_t begin, int64_t count,
1361 const std::string &tableName, const std::shared_ptr<DistributedDB::VirtualCloudDb> &cloudDbPtr, int32_t assetCount)
1362 {
1363 if (cloudDbPtr == nullptr) {
1364 LOGE("[RelationalTestUtils] Not support insert cloud with null");
1365 return DistributedDB::DBStatus::DB_ERROR;
1366 }
1367 std::vector<VBucket> record;
1368 std::vector<VBucket> extend;
1369 Timestamp now = DistributedDB::TimeHelper::GetSysCurrentTime();
1370 for (int64_t i = begin; i < (begin + count); ++i) {
1371 VBucket data;
1372 data.insert_or_assign("id", std::to_string(i));
1373 data.insert_or_assign("name", "Cloud" + std::to_string(i));
1374 Assets assets;
1375 std::string assetNameBegin = "Phone" + std::to_string(i);
1376 for (int j = 1; j <= assetCount; ++j) {
1377 Asset asset;
1378 asset.name = assetNameBegin + "_" + std::to_string(j);
1379 asset.status = AssetStatus::INSERT;
1380 asset.hash = "DEC";
1381 asset.assetId = std::to_string(j);
1382 assets.push_back(asset);
1383 }
1384 data.insert_or_assign("assets", assets);
1385 record.push_back(data);
1386 VBucket log;
1387 log.insert_or_assign(DistributedDB::CloudDbConstant::CREATE_FIELD, static_cast<int64_t>(
1388 now / DistributedDB::CloudDbConstant::TEN_THOUSAND));
1389 log.insert_or_assign(DistributedDB::CloudDbConstant::MODIFY_FIELD, static_cast<int64_t>(
1390 now / DistributedDB::CloudDbConstant::TEN_THOUSAND));
1391 log.insert_or_assign(DistributedDB::CloudDbConstant::DELETE_FIELD, false);
1392 extend.push_back(log);
1393 }
1394 return cloudDbPtr->BatchInsert(tableName, std::move(record), extend);
1395 }
1396
GetAllAssets(sqlite3 * db,const DistributedDB::TableSchema & schema,const std::shared_ptr<DistributedDB::ICloudDataTranslate> & translate)1397 std::vector<DistributedDB::Assets> RelationalTestUtils::GetAllAssets(sqlite3 *db,
1398 const DistributedDB::TableSchema &schema, const std::shared_ptr<DistributedDB::ICloudDataTranslate> &translate)
1399 {
1400 std::vector<DistributedDB::Assets> res;
1401 if (db == nullptr || translate == nullptr) {
1402 LOGW("[RelationalTestUtils] DB or translate is null");
1403 return res;
1404 }
1405 std::vector<VBucket> allData;
1406 EXPECT_EQ(RelationalTestUtils::SelectData(db, schema, allData), E_OK);
1407 std::map<std::string, int32_t> assetFields;
1408 for (const auto &field : schema.fields) {
1409 if (field.type != TYPE_INDEX<Asset> && field.type != TYPE_INDEX<Assets>) {
1410 continue;
1411 }
1412 assetFields[field.colName] = field.type;
1413 }
1414 for (const auto &oneRow : allData) {
1415 Assets assets;
1416 for (const auto &[col, data] : oneRow) {
1417 if (assetFields.find(col) == assetFields.end()) {
1418 continue;
1419 }
1420 auto tmpAssets = GetAssets(data, translate, (assetFields[col] == TYPE_INDEX<Asset>));
1421 assets.insert(assets.end(), tmpAssets.begin(), tmpAssets.end());
1422 }
1423 res.push_back(assets);
1424 }
1425 return res;
1426 }
1427
GetRecordLog(sqlite3 * db,const std::string & tableName,std::vector<DistributedDB::VBucket> & records)1428 int RelationalTestUtils::GetRecordLog(sqlite3 *db, const std::string &tableName,
1429 std::vector<DistributedDB::VBucket> &records)
1430 {
1431 DistributedDB::TableSchema schema;
1432 schema.name = DBCommon::GetLogTableName(tableName);
1433 Field field;
1434 field.type = TYPE_INDEX<int64_t>;
1435 field.colName = "data_key";
1436 schema.fields.push_back(field);
1437 field.colName = "flag";
1438 schema.fields.push_back(field);
1439 field.colName = "cursor";
1440 schema.fields.push_back(field);
1441 field.colName = "cloud_gid";
1442 field.type = TYPE_INDEX<std::string>;
1443 schema.fields.push_back(field);
1444 return SelectData(db, schema, records);
1445 }
1446
DeleteRecord(sqlite3 * db,const std::string & tableName,const std::vector<std::map<std::string,std::string>> & conditions)1447 int RelationalTestUtils::DeleteRecord(sqlite3 *db, const std::string &tableName,
1448 const std::vector<std::map<std::string, std::string>> &conditions)
1449 {
1450 if (db == nullptr || tableName.empty()) {
1451 LOGE("[RelationalTestUtils] db is null or table is empty");
1452 return -E_INVALID_ARGS;
1453 }
1454 int errCode = E_OK;
1455 for (const auto &condition : conditions) {
1456 std::string deleteSql = "DELETE FROM " + tableName + " WHERE ";
1457 int count = 0;
1458 for (const auto &[col, value] : condition) {
1459 if (count > 0) {
1460 deleteSql += " AND ";
1461 }
1462 deleteSql += col + "=" + value;
1463 count++;
1464 }
1465 LOGD("[RelationalTestUtils] Sql is %s", deleteSql.c_str());
1466 errCode = ExecSql(db, deleteSql);
1467 if (errCode != E_OK) {
1468 return errCode;
1469 }
1470 }
1471 return errCode;
1472 }
1473
IsSupport()1474 bool DBInfoHandleTest::IsSupport()
1475 {
1476 std::lock_guard<std::mutex> autoLock(supportMutex_);
1477 return localIsSupport_;
1478 }
1479
IsNeedAutoSync(const std::string & userId,const std::string & appId,const std::string & storeId,const DeviceInfos & devInfo)1480 bool DBInfoHandleTest::IsNeedAutoSync(const std::string &userId, const std::string &appId, const std::string &storeId,
1481 const DeviceInfos &devInfo)
1482 {
1483 std::lock_guard<std::mutex> autoLock(autoSyncMutex_);
1484 return isNeedAutoSync_;
1485 }
1486
SetLocalIsSupport(bool isSupport)1487 void DBInfoHandleTest::SetLocalIsSupport(bool isSupport)
1488 {
1489 std::lock_guard<std::mutex> autoLock(supportMutex_);
1490 localIsSupport_ = isSupport;
1491 }
1492
SetNeedAutoSync(bool needAutoSync)1493 void DBInfoHandleTest::SetNeedAutoSync(bool needAutoSync)
1494 {
1495 std::lock_guard<std::mutex> autoLock(autoSyncMutex_);
1496 isNeedAutoSync_ = needAutoSync;
1497 }
1498 } // namespace DistributedDBUnitTest
1499