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