• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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