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