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