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