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