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