• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #ifdef RELATIONAL_STORE
16 #include <gtest/gtest.h>
17 
18 #include "distributeddb_tools_unit_test.h"
19 #include "relational_store_manager.h"
20 #include "distributeddb_data_generate_unit_test.h"
21 #include "relational_sync_able_storage.h"
22 #include "relational_store_instance.h"
23 #include "sqlite_relational_store.h"
24 #include "log_table_manager_factory.h"
25 #include "cloud_db_constant.h"
26 #include "runtime_config.h"
27 #include "virtual_cloud_data_translate.h"
28 
29 using namespace testing::ext;
30 using namespace DistributedDB;
31 using namespace DistributedDBUnitTest;
32 using namespace std;
33 
34 namespace {
35 string g_storeID = "Relational_Store_ID";
36 string g_tableName = "cloudData";
37 string g_logTblName;
38 string g_testDir;
39 string g_storePath;
40 const Timestamp g_startTime = 100000;
41 const int g_deleteFlag = 0x01;
42 const int g_localFlag = 0x02;
43 const std::string CREATE_LOCAL_TABLE_SQL =
44     "CREATE TABLE IF NOT EXISTS " + g_tableName + "(" \
45     "name TEXT ," \
46     "height REAL ," \
47     "married INT ," \
48     "photo BLOB ," \
49     "assert BLOB," \
50     "asserts BLOB," \
51     "age INT);";
52 const std::vector<Field> g_cloudFiled = {
53     {"name", TYPE_INDEX<std::string>}, {"age", TYPE_INDEX<int64_t>},
54     {"height", TYPE_INDEX<double>}, {"married", TYPE_INDEX<bool>}, {"photo", TYPE_INDEX<Bytes>},
55     {"assert", TYPE_INDEX<Asset>}, {"asserts", TYPE_INDEX<Assets>}
56 };
57 const Asset g_localAsset = {
58     .version = 1, .name = "Phone", .uri = "/local/sync", .modifyTime = "123456", .createTime = "",
59     .size = "256", .hash = " ", .flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE),
60     .status = static_cast<uint32_t>(AssetStatus::NORMAL), .timestamp = 0L
61 };
62 DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID);
63 RelationalStoreDelegate *g_delegate = nullptr;
64 IRelationalStore *g_store = nullptr;
65 ICloudSyncStorageInterface *g_cloudStore = nullptr;
66 std::shared_ptr<StorageProxy> g_storageProxy = nullptr;
67 TableSchema g_tableSchema;
68 
CreateDB()69 void CreateDB()
70 {
71     sqlite3 *db = nullptr;
72     int errCode = sqlite3_open(g_storePath.c_str(), &db);
73     if (errCode != SQLITE_OK) {
74         LOGE("open db failed:%d", errCode);
75         sqlite3_close(db);
76         return;
77     }
78 
79     const string sql =
80         "PRAGMA journal_mode=WAL;";
81     ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
82     sqlite3_close(db);
83 }
84 
CreateLogTable()85 void CreateLogTable()
86 {
87     TableInfo table;
88     table.SetTableName(g_tableName);
89     table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION);
90     sqlite3 *db = nullptr;
91     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
92     auto tableManager =
93         LogTableManagerFactory::GetTableManager(DistributedTableMode::COLLABORATION, TableSyncType::CLOUD_COOPERATION);
94     int errCode = tableManager->CreateRelationalLogTable(db, table);
95     EXPECT_EQ(errCode, E_OK);
96     sqlite3_close(db);
97 }
98 
CreateAndInitUserTable(int64_t count,int64_t photoSize)99 void CreateAndInitUserTable(int64_t count, int64_t photoSize)
100 {
101     sqlite3 *db = nullptr;
102     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
103 
104     ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, CREATE_LOCAL_TABLE_SQL), E_OK);
105     std::string photo(photoSize, 'v');
106     std::vector<uint8_t> assetBlob;
107     std::vector<uint8_t> assetsBlob;
108     Asset asset = g_localAsset;
109     int id = 0;
110     Assets assets;
111     asset.name = g_localAsset.name + std::to_string(id++);
112     assets.push_back(asset);
113     asset.name = g_localAsset.name + std::to_string(id++);
114     assets.push_back(asset);
115     int errCode;
116     ASSERT_EQ(RuntimeContext::GetInstance()->AssetToBlob(g_localAsset, assetBlob), E_OK);
117     ASSERT_EQ(RuntimeContext::GetInstance()->AssetsToBlob(assets, assetsBlob), E_OK);
118     for (int i = 1; i <= count; ++i) {
119         string sql = "INSERT OR REPLACE INTO " + g_tableName +
120             " (name, height, married, photo, assert, asserts, age) VALUES ('Tom" + std::to_string(i) +
121             "', '175.8', '0', '" + photo + "', ? , ?,  '18');";
122         sqlite3_stmt *stmt = nullptr;
123         ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
124         if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false) != E_OK) { // 1 is asset index
125             SQLiteUtils::ResetStatement(stmt, true, errCode);
126         }
127         if (SQLiteUtils::BindBlobToStatement(stmt, 2, assetsBlob, false) != E_OK) { // 2 is index of asserts
128             SQLiteUtils::ResetStatement(stmt, true, errCode);
129         }
130         EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
131         SQLiteUtils::ResetStatement(stmt, true, errCode);
132     }
133     sqlite3_close(db);
134 }
135 
InitLogData(int64_t insCount,int64_t updCount,int64_t delCount,int64_t excludeCount)136 void InitLogData(int64_t insCount, int64_t updCount, int64_t delCount, int64_t excludeCount)
137 {
138     sqlite3 *db = nullptr;
139     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
140     std::string flag;
141     std::string cloudGid;
142     for (int64_t i = 1; i <= insCount + updCount + delCount + excludeCount; ++i) {
143         if (i <= insCount) {
144             flag = std::to_string(g_localFlag);
145             cloudGid = "''";
146         } else if (i > insCount && i <= insCount + updCount) {
147             flag = std::to_string(g_localFlag);
148             cloudGid = "'" + g_storeID + std::to_string(i) + "'";
149         } else if (i > (insCount + updCount) && i <= (insCount + updCount + delCount)) {
150             flag = std::to_string(g_localFlag | g_deleteFlag);
151             cloudGid = "'" + g_storeID + std::to_string(i) + "'";
152         } else {
153             flag = std::to_string(g_localFlag | g_deleteFlag);
154             cloudGid = "''";
155         }
156         string sql = "INSERT OR REPLACE INTO " + g_logTblName +
157             " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key, cloud_gid)" +
158             " VALUES ('" + std::to_string(i) + "', '', '', '" +  std::to_string(g_startTime + i) + "', '" +
159             std::to_string(g_startTime + i) + "','" + flag + "','" + std::to_string(i) + "', " + cloudGid + ");";
160         ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
161     }
162     sqlite3_close(db);
163 }
164 
InitLogGid(int64_t count)165 void InitLogGid(int64_t count)
166 {
167     sqlite3 *db = nullptr;
168     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
169     for (int i = 1; i <= count; i++) {
170         string sql = "update " + g_logTblName + " set cloud_gid = '" + std::to_string(i) +
171             "' where data_key = " + std::to_string(i);
172         ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK);
173     }
174     sqlite3_close(db);
175 }
176 
ConstructMultiDownloadData(int64_t count,DownloadData & downloadData)177 void ConstructMultiDownloadData(int64_t count, DownloadData &downloadData)
178 {
179     for (int i = 1; i <= 5; i++) { // 5 is random num
180         Asset asset = g_localAsset;
181         Assets assets;
182         VBucket vBucket;
183         if (i <= 2) { // 2 is deleted or insert type
184             asset.flag = static_cast<uint32_t>(i == 1 ? AssetOpType::DELETE : AssetOpType::INSERT);
185             vBucket[CloudDbConstant::GID_FIELD] = (i == 1 ? std::to_string(i) : std::to_string(count + i));
186         } else {
187             asset.flag = static_cast<uint32_t>(AssetOpType::UPDATE);
188             vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
189         }
190         vBucket["assert"] = asset;
191         asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
192         assets.push_back(asset);
193         asset.flag = static_cast<uint32_t>(AssetOpType::INSERT);
194         assets.push_back(asset);
195         asset.flag = static_cast<uint32_t>(AssetOpType::DELETE);
196         assets.push_back(asset);
197         asset.flag = static_cast<uint32_t>(AssetOpType::UPDATE);
198         assets.push_back(asset);
199         vBucket["asserts"] = assets;
200         std::string name = "lisi" + std::to_string(i);
201         vBucket["name"] = name;
202         vBucket["age"] = (int64_t)i;
203         int64_t mTime = 12345679L + i;
204         vBucket[CloudDbConstant::MODIFY_FIELD] = mTime;
205         vBucket[CloudDbConstant::CREATE_FIELD] = mTime;
206         downloadData.data.push_back(vBucket);
207     }
208     downloadData.opType = { OpType::DELETE, OpType::INSERT, OpType::UPDATE,
209         OpType::UPDATE, OpType::NOT_HANDLE };
210 }
211 
SetDbSchema(const TableSchema & tableSchema)212 void SetDbSchema(const TableSchema &tableSchema)
213 {
214     DataBaseSchema dataBaseSchema;
215     dataBaseSchema.tables.push_back(tableSchema);
216     EXPECT_EQ(g_cloudStore->SetCloudDbSchema(dataBaseSchema), E_OK);
217 }
218 
InitUserDataForAssetTest(int64_t insCount,int64_t photoSize)219 void InitUserDataForAssetTest(int64_t insCount, int64_t photoSize)
220 {
221     sqlite3 *db = nullptr;
222     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
223     ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, CREATE_LOCAL_TABLE_SQL), E_OK);
224     sqlite3_close(db);
225     EXPECT_EQ(g_delegate->CreateDistributedTable(g_tableName, DistributedDB::CLOUD_COOPERATION), OK);
226     CreateAndInitUserTable(insCount, photoSize);
227     SetDbSchema(g_tableSchema);
228 }
229 
QueryCountCallback(void * data,int count,char ** colValue,char ** colName)230 int QueryCountCallback(void *data, int count, char **colValue, char **colName)
231 {
232     if (count != 1) {
233         return 0;
234     }
235     auto expectCount = reinterpret_cast<int64_t>(data);
236     EXPECT_EQ(strtol(colValue[0], nullptr, 10), expectCount); // 10: decimal
237     return 0;
238 }
239 
fillCloudAssetTest(int64_t count,AssetStatus statusType,bool isDownloadSuccess)240 void fillCloudAssetTest(int64_t count, AssetStatus statusType, bool isDownloadSuccess)
241 {
242     VBucket vBucket;
243     vBucket[CloudDbConstant::GID_FIELD] = std::to_string(1);
244     for (int i = 0; i < 4; i ++) { // 4 is AssetStatus Num
245         Asset asset = g_localAsset;
246         asset.flag = i;
247         asset.status = static_cast<uint32_t>(statusType);
248         asset.timestamp = g_startTime;
249         Assets assets;
250         for (int j = 0; j < 4; j++) { // 4 is AssetStatus Num
251             Asset temp = g_localAsset;
252             temp.flag = j;
253             temp.status = static_cast<uint32_t>(statusType);
254             temp.timestamp = g_startTime + j;
255             assets.push_back(temp);
256         }
257         vBucket["assert"] = asset;
258         vBucket["asserts"] = assets;
259         ASSERT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
260         ASSERT_EQ(g_storageProxy->FillCloudAssetForDownload(g_tableName, vBucket, isDownloadSuccess), E_OK);
261         ASSERT_EQ(g_storageProxy->Commit(), E_OK);
262     }
263 }
264 
UpdateLocalAsset(const std::string & tableName,Asset & asset,int64_t rowid)265 void UpdateLocalAsset(const std::string &tableName, Asset &asset, int64_t rowid)
266 {
267     sqlite3 *db = nullptr;
268     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
269     string sql = "UPDATE " + tableName + " SET assert = ? where rowid = '" + std::to_string(rowid) + "';";
270     std::vector<uint8_t> assetBlob;
271     int errCode;
272     RuntimeContext::GetInstance()->AssetToBlob(asset, assetBlob);
273     sqlite3_stmt *stmt = nullptr;
274     ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK);
275     if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false) == E_OK) {
276         EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE));
277     }
278     SQLiteUtils::ResetStatement(stmt, true, errCode);
279     sqlite3_close(db);
280 }
281 
InitStoreProp(const std::string & storePath,const std::string & appId,const std::string & userId,RelationalDBProperties & properties)282 void InitStoreProp(const std::string &storePath, const std::string &appId, const std::string &userId,
283     RelationalDBProperties &properties)
284 {
285     properties.SetStringProp(RelationalDBProperties::DATA_DIR, storePath);
286     properties.SetStringProp(RelationalDBProperties::APP_ID, appId);
287     properties.SetStringProp(RelationalDBProperties::USER_ID, userId);
288     properties.SetStringProp(RelationalDBProperties::STORE_ID, g_storeID);
289     std::string identifier = userId + "-" + appId + "-" + g_storeID;
290     std::string hashIdentifier = DBCommon::TransferHashString(identifier);
291     properties.SetStringProp(RelationalDBProperties::IDENTIFIER_DATA, hashIdentifier);
292 }
293 
GetRelationalStore()294 const RelationalSyncAbleStorage *GetRelationalStore()
295 {
296     RelationalDBProperties properties;
297     InitStoreProp(g_storePath, APP_ID, USER_ID, properties);
298     int errCode = E_OK;
299     g_store = RelationalStoreInstance::GetDataBase(properties, errCode);
300     if (g_store == nullptr) {
301         LOGE("Get db failed:%d", errCode);
302         return nullptr;
303     }
304     return static_cast<SQLiteRelationalStore *>(g_store)->GetStorageEngine();
305 }
306 
GetStorageProxy(ICloudSyncStorageInterface * store)307 std::shared_ptr<StorageProxy> GetStorageProxy(ICloudSyncStorageInterface *store)
308 {
309     return StorageProxy::GetCloudDb(store);
310 }
311 
312 class DistributedDBRelationalCloudSyncableStorageTest : public testing::Test {
313 public:
314     static void SetUpTestCase(void);
315     static void TearDownTestCase(void);
316     void SetUp();
317     void TearDown();
318 };
319 
320 
SetUpTestCase(void)321 void DistributedDBRelationalCloudSyncableStorageTest::SetUpTestCase(void)
322 {
323     DistributedDBToolsUnitTest::TestDirInit(g_testDir);
324     g_storePath = g_testDir + "/cloudDataTest.db";
325     g_logTblName = DBConstant::RELATIONAL_PREFIX + g_tableName + "_log";
326     LOGI("The test db is:%s", g_testDir.c_str());
327     RuntimeConfig::SetCloudTranslate(std::make_shared<VirtualCloudDataTranslate>());
328     g_tableSchema.name = g_tableName;
329     g_tableSchema.fields = g_cloudFiled;
330 }
331 
TearDownTestCase(void)332 void DistributedDBRelationalCloudSyncableStorageTest::TearDownTestCase(void)
333 {}
334 
SetUp(void)335 void DistributedDBRelationalCloudSyncableStorageTest::SetUp(void)
336 {
337     if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
338         LOGE("rm test db files error.");
339     }
340     DistributedDBToolsUnitTest::PrintTestCaseInfo();
341     LOGD("Test dir is %s", g_testDir.c_str());
342     CreateDB();
343     ASSERT_EQ(g_mgr.OpenStore(g_storePath, g_storeID, RelationalStoreDelegate::Option {}, g_delegate), DBStatus::OK);
344     ASSERT_NE(g_delegate, nullptr);
345     g_cloudStore = (ICloudSyncStorageInterface *) GetRelationalStore();
346     ASSERT_NE(g_cloudStore, nullptr);
347     g_storageProxy = GetStorageProxy(g_cloudStore);
348     ASSERT_NE(g_storageProxy, nullptr);
349 }
350 
TearDown(void)351 void DistributedDBRelationalCloudSyncableStorageTest::TearDown(void)
352 {
353     RefObject::DecObjRef(g_store);
354     if (g_delegate != nullptr) {
355         EXPECT_EQ(g_mgr.CloseStore(g_delegate), DBStatus::OK);
356         g_delegate = nullptr;
357     }
358     if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
359         LOGE("rm test db files error.");
360     }
361 }
362 
363 /**
364  * @tc.name: MetaDataTest001
365  * @tc.desc: Test PutMetaData and GetMetaData from ICloudSyncStorageInterface impl class
366  * @tc.type: FUNC
367  * @tc.require:
368  * @tc.author: bty
369  */
370 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, MetaDataTest001, TestSize.Level1)
371 {
372     EXPECT_EQ(g_cloudStore->PutMetaData(KEY_1, VALUE_2), E_OK);
373     EXPECT_EQ(g_cloudStore->PutMetaData(KEY_1, VALUE_3), E_OK);
374 
375     Value value;
376     EXPECT_EQ(g_cloudStore->GetMetaData(KEY_1, value), E_OK);
377     EXPECT_EQ(value, VALUE_3);
378 }
379 
380 /**
381  * @tc.name: MetaDataTest002
382  * @tc.desc: The GetMetaData supports key sizes up to 1024
383  * @tc.type: FUNC
384  * @tc.require:
385  * @tc.author: bty
386  */
387 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, MetaDataTest002, TestSize.Level1)
388 {
389     const string str(DBConstant::MAX_KEY_SIZE, 'k');
390     const Key key(str.begin(), str.end());
391     EXPECT_EQ(g_cloudStore->PutMetaData(key, VALUE_2), E_OK);
392     Value value;
393     EXPECT_EQ(g_cloudStore->GetMetaData(key, value), E_OK);
394     EXPECT_EQ(value, VALUE_2);
395 
396     const string maxStr(DBConstant::MAX_KEY_SIZE + 1, 'k');
397     const Key maxKey(maxStr.begin(), maxStr.end());
398     EXPECT_EQ(g_cloudStore->PutMetaData(maxKey, VALUE_3), E_OK);
399     EXPECT_EQ(g_cloudStore->GetMetaData(maxKey, value), -E_INVALID_ARGS);
400 }
401 
402 /**
403  * @tc.name: TransactionTest001
404  * @tc.desc: No write transaction in the current store, meta interface can called
405  * @tc.type: FUNC
406  * @tc.require:
407  * @tc.author: bty
408   */
409 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest001, TestSize.Level1)
410 {
411     /**
412      * @tc.steps: allow get or put meta in read transaction
413      * @tc.expected: Succeed, return OK.
414      */
415     EXPECT_EQ(g_cloudStore->StartTransaction(TransactType::DEFERRED), E_OK);
416     g_cloudStore->PutMetaData(KEY_1, VALUE_1);
417     EXPECT_EQ(g_cloudStore->Rollback(), E_OK);
418     g_cloudStore->PutMetaData(KEY_2, VALUE_2);
419 
420     Value value;
421     EXPECT_EQ(g_cloudStore->StartTransaction(TransactType::DEFERRED), E_OK);
422     EXPECT_EQ(g_cloudStore->GetMetaData(KEY_1, value), E_OK);
423     EXPECT_EQ(g_cloudStore->GetMetaData(KEY_2, value), E_OK);
424     g_cloudStore->PutMetaData(KEY_3, VALUE_3);
425     EXPECT_EQ(g_cloudStore->GetMetaData(KEY_3, value), E_OK);
426     EXPECT_EQ(g_cloudStore->Commit(), E_OK);
427     EXPECT_EQ(g_cloudStore->GetMetaData(KEY_3, value), E_OK);
428 }
429 
430 /**
431  * @tc.name: TransactionTest002
432  * @tc.desc: Test transaction interface from StorageProxy
433  * @tc.type: FUNC
434  * @tc.require:
435  * @tc.author: bty
436  */
437 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest002, TestSize.Level1)
438 {
439     Timestamp cloudTime = 666888;
440     Timestamp localTime;
441     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
442 
443     /**
444      * @tc.steps: allow get or put waterMark in read transaction
445      * @tc.expected: Succeed, return OK.
446      */
447     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
448     EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
449     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
450     EXPECT_EQ(cloudTime, localTime);
451     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
452     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
453 
454     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
455     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
456     cloudTime = 999666;
457     EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
458     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
459     EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), E_OK);
460     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
461     EXPECT_EQ(cloudTime, localTime);
462 
463     /**
464      * @tc.steps: not allow get or put waterMark in write transaction
465      * @tc.expected: return -E_BUSY.
466      */
467     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
468     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), -E_BUSY);
469     EXPECT_EQ(g_storageProxy->PutLocalWaterMark(g_tableName, cloudTime), -E_BUSY);
470     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
471     EXPECT_EQ(g_storageProxy->GetLocalWaterMark(g_tableName, localTime), E_OK);
472 }
473 
474 /**
475  * @tc.name: TransactionTest003
476  * @tc.desc: Repeatedly call transaction interface from StorageProxy
477  * @tc.type: FUNC
478  * @tc.require:
479  * @tc.author: bty
480  */
481 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest003, TestSize.Level1)
482 {
483     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
484 
485     /**
486      * @tc.steps: Repeated start transactions is not allowed
487      * @tc.expected: return -E_TRANSACT_STATE.
488      */
489     EXPECT_EQ(g_storageProxy->StartTransaction(), -E_TRANSACT_STATE);
490 
491     /**
492      * @tc.steps: Repeated commit is not allowed
493      * @tc.expected: return -E_INVALID_DB.
494      */
495     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
496     EXPECT_EQ(g_storageProxy->Commit(), -E_INVALID_DB);
497 
498     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
499 
500     /**
501      * @tc.steps: Repeated Rollback is not allowed
502      * @tc.expected: return -E_INVALID_DB.
503      */
504     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
505     EXPECT_EQ(g_storageProxy->Rollback(), -E_INVALID_DB);
506 }
507 
508 /**
509  * @tc.name: TransactionTest004
510  * @tc.desc: Call transaction after close storageProxy
511  * @tc.type: FUNC
512  * @tc.require:
513  * @tc.author: bty
514   */
515 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, TransactionTest004, TestSize.Level1)
516 {
517     /**
518      * @tc.steps: transaction is not allowed after closing the proxy
519      * @tc.expected: return -E_INVALID_DB.
520      */
521     EXPECT_EQ(g_storageProxy->Close(), E_OK);
522     EXPECT_EQ(g_storageProxy->StartTransaction(), -E_INVALID_DB);
523     EXPECT_EQ(g_storageProxy->Commit(), -E_INVALID_DB);
524     EXPECT_EQ(g_storageProxy->Rollback(), -E_INVALID_DB);
525 
526     g_storageProxy = GetStorageProxy(g_cloudStore);
527     ASSERT_NE(g_storageProxy, nullptr);
528     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
529 
530     /**
531      * @tc.steps: close proxy is not allowed before the transaction has been commit or rollback
532      * @tc.expected: return -E_BUSY.
533      */
534     EXPECT_EQ(g_storageProxy->Close(), -E_BUSY);
535     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
536     EXPECT_EQ(g_storageProxy->Close(), E_OK);
537 }
538 
539 /**
540  * @tc.name: GetUploadCount001
541  * @tc.desc: Test getUploadCount by ICloudSyncStorageInterface
542  * @tc.type: FUNC
543  * @tc.require:
544  * @tc.author: bty
545  */
546 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount001, TestSize.Level1)
547 {
548     /**
549      * @tc.steps: Table does not exist
550      * @tc.expected: return -SQLITE_ERROR.
551      */
552     int64_t resCount = 0;
553     EXPECT_EQ(g_cloudStore->GetUploadCount(g_tableName, g_startTime, false, resCount), -SQLITE_ERROR);
554 
555     CreateLogTable();
556     int64_t insCount = 100;
557     InitLogData(insCount, insCount, insCount, insCount);
558     EXPECT_EQ(g_cloudStore->GetUploadCount(g_tableName, g_startTime, false, resCount), E_OK);
559     EXPECT_EQ(resCount, insCount + insCount + insCount);
560 
561     /**
562      * @tc.steps: There are no matching data anymore
563      * @tc.expected: count is 0 and return E_OK.
564      */
565     Timestamp invalidTime = g_startTime + g_startTime;
566     EXPECT_EQ(g_cloudStore->GetUploadCount(g_tableName, invalidTime, false, resCount), E_OK);
567     EXPECT_EQ(resCount, 0);
568 }
569 
570 /**
571  * @tc.name: GetUploadCount002
572  * @tc.desc: Test getUploadCount by storageProxy
573  * @tc.type: FUNC
574  * @tc.require:
575  * @tc.author: bty
576   */
577 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount002, TestSize.Level1)
578 {
579     CreateLogTable();
580     int64_t insCount = 100;
581     InitLogData(insCount, insCount, 0, insCount);
582     int64_t resCount = 0;
583 
584     /**
585      * @tc.steps: GetUploadCount must be called under transaction
586      * @tc.expected: return -E_TRANSACT_STATE.
587      */
588     EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), -E_TRANSACT_STATE);
589 
590     int timeOffset = 30;
591     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
592     EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime + timeOffset, false, resCount), E_OK);
593     EXPECT_EQ(resCount, insCount + insCount - timeOffset);
594     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
595 
596     /**
597      * @tc.steps: GetUploadCount also can be called under write transaction
598      * @tc.expected: return E_OK.
599      */
600     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
601     EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime + timeOffset, false, resCount), E_OK);
602     EXPECT_EQ(resCount, insCount + insCount - timeOffset);
603     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
604 }
605 
606 /**
607  * @tc.name: GetUploadCount003
608  * @tc.desc: Test getUploadCount exclude condition of (deleteFlag and cloud_gid is '')
609  * @tc.type: FUNC
610  * @tc.require:
611  * @tc.author: bty
612  */
613 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetUploadCount003, TestSize.Level1)
614 {
615     CreateLogTable();
616     int64_t insCount = 100;
617     InitLogData(0, 0, insCount, insCount);
618     int64_t resCount = 0;
619 
620     /**
621      * @tc.steps: GetUploadCount must be called under transaction
622      * @tc.expected: return -E_TRANSACT_STATE.
623      */
624     EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), -E_TRANSACT_STATE);
625 
626     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
627     EXPECT_EQ(g_storageProxy->GetUploadCount(g_tableName, g_startTime, false, resCount), E_OK);
628     EXPECT_EQ(resCount, insCount);
629     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
630 }
631 
632 /**
633  * @tc.name: FillCloudGid001
634  * @tc.desc: FillCloudGid with invalid parm
635  * @tc.type: FUNC
636  * @tc.require:
637  * @tc.author: bty
638  */
639 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid001, TestSize.Level1)
640 {
641     CreateLogTable();
642     int64_t insCount = 100;
643     InitLogData(insCount, 0, insCount, insCount);
644     CloudSyncData syncData;
645 
646     /**
647      * @tc.steps: rowid set is empty
648      * @tc.expected: return -E_INVALID_ARGS.
649      */
650     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
651     syncData.insData.rowid.push_back(1);
652     syncData.insData.rowid.push_back(2); // 2 is random id
653 
654     /**
655      * @tc.steps: insData set is empty
656      * @tc.expected: return -E_INVALID_ARGS.
657      */
658     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
659     VBucket bucket1;
660     bucket1.insert_or_assign(g_tableName, g_tableName);
661     bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, 1L);
662     syncData.insData.extend.push_back(bucket1);
663 
664     /**
665      * @tc.steps: the size of rowid and insData is not equal
666      * @tc.expected: return -E_INVALID_ARGS.
667      */
668     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
669 
670     /**
671      * @tc.steps: table name is empty
672      * @tc.expected: return -SQLITE_ERROR.
673      */
674     VBucket bucket2;
675     bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, 2L); // 2L is random field
676     syncData.insData.extend.push_back(bucket2);
677     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -SQLITE_ERROR);
678 
679     /**
680      * @tc.steps: the field type does not match
681      * @tc.expected: return -E_INVALID_DATA.
682      */
683     syncData.tableName = g_tableName;
684     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_DATA);
685 
686     /**
687      * @tc.steps: missing field GID_FIELD
688      * @tc.expected: return -E_INVALID_ARGS.
689      */
690     syncData.insData.extend.clear();
691     bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("1"));
692     bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, std::string("2"));
693     syncData.insData.extend.push_back(bucket1);
694     syncData.insData.extend.push_back(bucket2);
695     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -E_INVALID_ARGS);
696 
697     syncData.insData.extend.pop_back();
698     bucket2.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("2"));
699     syncData.insData.extend.push_back(bucket2);
700     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), E_OK);
701 
702     /**
703      * @tc.steps: table name is not exists
704      * @tc.expected: return -SQLITE_ERROR.
705      */
706     syncData.tableName = "noneTable";
707     EXPECT_EQ(g_cloudStore->FillCloudGid(syncData), -SQLITE_ERROR);
708 }
709 
710 /**
711  * @tc.name: FillCloudGid002
712  * @tc.desc: Test whether the num of gid after fill are correct
713  * @tc.type: FUNC
714  * @tc.require:
715  * @tc.author: bty
716  */
717 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid002, TestSize.Level1)
718 {
719     CreateLogTable();
720     int64_t insCount = 100;
721     int64_t updCount = 50;
722     int64_t delCount = 50;
723     InitLogData(insCount, updCount, delCount, insCount);
724 
725     CloudSyncData syncData(g_tableName);
726     for (int64_t i = 1; i <= 3 * insCount; ++i) { // 3 is insert,update and delete type data
727         syncData.insData.rowid.push_back(i);
728         VBucket bucket1;
729         bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(g_startTime + i));
730         syncData.insData.extend.push_back(bucket1);
731     }
732     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
733     EXPECT_EQ(g_storageProxy->FillCloudGid(syncData), E_OK);
734     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
735 
736     sqlite3 *db = nullptr;
737     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
738     std::string querySql = "SELECT COUNT(*) FROM " + g_logTblName + " WHERE cloud_gid in (";
739     for (int64_t i = 1; i <= (insCount + updCount + delCount); ++i) {
740         querySql += "'" + std::to_string(g_startTime + i) + "',";
741     }
742     querySql.pop_back();
743     querySql += ");";
744     EXPECT_EQ(sqlite3_exec(db, querySql.c_str(),
745         QueryCountCallback, reinterpret_cast<void *>(insCount + updCount + delCount), nullptr), SQLITE_OK);
746     sqlite3_close(db);
747 }
748 
749 /**
750  * @tc.name: FillCloudGid003
751  * @tc.desc: Test FillCloudGid after in write transaction
752  * @tc.type: FUNC
753  * @tc.require:
754  * @tc.author: bty
755  */
756 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid003, TestSize.Level1)
757 {
758     CreateLogTable();
759     int64_t insCount = 10;
760     InitLogData(insCount, insCount, insCount, insCount);
761     CloudSyncData syncData(g_tableName);
762     for (int64_t i = 1; i <= (insCount + insCount + insCount); ++i) {
763         syncData.insData.rowid.push_back(i);
764         VBucket bucket1;
765         bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(g_startTime + i));
766         syncData.insData.extend.push_back(bucket1);
767     }
768 
769     /**
770      * @tc.steps: FillCloudGid is not allowed after starting write transaction
771      * @tc.expected: return -E_BUSY.
772      */
773     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
774     EXPECT_EQ(g_storageProxy->FillCloudGid(syncData), -E_BUSY);
775     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
776 }
777 
778 /**
779  * @tc.name: FillCloudGid004
780  * @tc.desc: Test FillCloudGid when gid is empty
781  * @tc.type: FUNC
782  * @tc.require:
783  * @tc.author: bty
784  */
785 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid004, TestSize.Level1)
786 {
787     CreateLogTable();
788     int64_t insCount = 2;
789     InitLogData(insCount, insCount, insCount, insCount);
790     CloudSyncData syncData(g_tableName);
791     syncData.insData.rowid.push_back(0);
792     VBucket bucket1;
793     bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::string(""));
794     syncData.insData.extend.push_back(bucket1);
795 
796     /**
797      * @tc.steps: FillCloudGid is not allowed when gid is empty
798      * @tc.expected: return -E_CLOUD_ERROR.
799      */
800     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
801     EXPECT_EQ(g_storageProxy->FillCloudGid(syncData), -E_CLOUD_ERROR);
802     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
803 }
804 
805 /**
806  * @tc.name: GetCloudData001
807  * @tc.desc: Test GetCloudData,whether the result count and type of data are correct
808  * @tc.type: FUNC
809  * @tc.require:
810  * @tc.author: bty
811  */
812 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData001, TestSize.Level1)
813 {
814     CreateLogTable();
815     int64_t insCount = 100;
816     int64_t updCount = 50;
817     int64_t delCount = 25;
818     int64_t photoSize = 10;
819     InitLogData(insCount, updCount, delCount, insCount);
820     CreateAndInitUserTable(3 * insCount, photoSize); // 3 is insert,update and delete type data
821 
822     ContinueToken token = nullptr;
823     CloudSyncData cloudSyncData;
824     SetDbSchema(g_tableSchema);
825 
826     /**
827      * @tc.steps: There is currently no handle under the transaction
828      * @tc.expected: return -E_INVALID_DB.
829      */
830     int timeOffset = 10;
831     EXPECT_EQ(g_cloudStore->GetCloudData(g_tableSchema, g_startTime + timeOffset, token, cloudSyncData), -E_INVALID_DB);
832 
833     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
834     EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime + timeOffset, token, cloudSyncData), E_OK);
835     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
836     EXPECT_EQ(cloudSyncData.insData.record.size() + cloudSyncData.updData.record.size() +
837         cloudSyncData.delData.record.size(), static_cast<uint64_t>(insCount + updCount + delCount - timeOffset));
838     ASSERT_EQ(cloudSyncData.insData.record.size(), static_cast<uint64_t>(insCount - timeOffset));
839     ASSERT_EQ(cloudSyncData.updData.record.size(), static_cast<uint64_t>(updCount));
840     ASSERT_EQ(cloudSyncData.delData.record.size(), static_cast<uint64_t>(delCount));
841 
842     EXPECT_EQ(cloudSyncData.insData.record[0].find(CloudDbConstant::GID_FIELD), cloudSyncData.insData.record[0].end());
843     EXPECT_NE(cloudSyncData.updData.record[0].find(CloudDbConstant::GID_FIELD), cloudSyncData.insData.record[0].end());
844     EXPECT_NE(cloudSyncData.delData.record[0].find(CloudDbConstant::GID_FIELD), cloudSyncData.insData.record[0].end());
845 
846 
847     /**
848      * @tc.steps: GetCloudData also can be called under write transaction
849      * @tc.expected: return E_OK.
850      */
851     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
852     EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime + timeOffset, token, cloudSyncData), E_OK);
853     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
854 }
855 
856 /**
857  * @tc.name: GetCloudData002
858  * @tc.desc: The maximum return data size of GetCloudData is less than 8M
859  * @tc.type: FUNC
860  * @tc.require:
861  * @tc.author: bty
862  */
863 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData002, TestSize.Level1)
864 {
865     CreateLogTable();
866     int64_t insCount = 1024;
867     int64_t photoSize = 512 * 3;
868     InitLogData(insCount, insCount, insCount, insCount);
869     CreateAndInitUserTable(3 * insCount, photoSize); // 3 is insert,update and delete type data
870 
871 
872     /**
873      * @tc.steps: GetCloudData has not finished querying yet.
874      * @tc.expected: return -E_UNFINISHED.
875      */
876     SetDbSchema(g_tableSchema);
877     ContinueToken token = nullptr;
878     CloudSyncData cloudSyncData1;
879     int timeOffset = 10;
880     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
881     EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime + timeOffset, token, cloudSyncData1),
882         -E_UNFINISHED);
883     EXPECT_LT(cloudSyncData1.insData.record.size() + cloudSyncData1.updData.record.size() +
884         cloudSyncData1.delData.record.size(), static_cast<uint64_t>(insCount));
885     EXPECT_EQ(cloudSyncData1.delData.record.size(), 0u);
886 
887     CloudSyncData cloudSyncData2;
888     EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData2), -E_UNFINISHED);
889     EXPECT_LT(cloudSyncData2.insData.record.size() + cloudSyncData2.updData.record.size() +
890         cloudSyncData2.delData.record.size(), static_cast<uint64_t>(insCount));
891 
892     CloudSyncData cloudSyncData3;
893     EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData3), E_OK);
894     EXPECT_GT(cloudSyncData3.insData.record.size() + cloudSyncData3.updData.record.size() +
895         cloudSyncData3.delData.record.size(), static_cast<uint64_t>(insCount));
896     EXPECT_EQ(cloudSyncData3.insData.record.size(), 0u);
897 
898     /**
899      * @tc.steps: Finished querying, the token has been release.
900      * @tc.expected: return -E_INVALID_ARGS.
901      */
902     EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData3), -E_INVALID_ARGS);
903     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
904 }
905 
906 /**
907  * @tc.name: GetCloudData003
908  * @tc.desc: ReleaseContinueToken required when GetCloudDataNext interrupt
909  * @tc.type: FUNC
910  * @tc.require:
911  * @tc.author: bty
912  */
913 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData003, TestSize.Level1)
914 {
915     CreateLogTable();
916     int64_t insCount = 1024;
917     int64_t photoSize = 1024 * 8;
918     InitLogData(insCount, insCount, insCount, insCount);
919     CreateAndInitUserTable(2 * insCount, photoSize); // 2 is insert,update type data
920 
921     SetDbSchema(g_tableSchema);
922     ContinueToken token = nullptr;
923     CloudSyncData cloudSyncData;
924     EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
925     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
926     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
927     ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
928     token = nullptr;
929     EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData), -E_INVALID_ARGS);
930     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
931 
932     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
933     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
934     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
935     ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
936 }
937 
938 /**
939  * @tc.name: GetCloudData004
940  * @tc.desc: Test get cloudData when asset or assets is NULL
941  * @tc.type: FUNC
942  * @tc.require:
943  * @tc.author: bty
944  */
945 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData004, TestSize.Level1)
946 {
947     CreateLogTable();
948     int64_t insCount = 10;
949     int64_t photoSize = 10;
950     InitLogData(insCount, insCount, insCount, insCount);
951     CreateAndInitUserTable(3 * insCount, photoSize); // 3 is insert,update and delete type data
952 
953     SetDbSchema(g_tableSchema);
954     sqlite3 *db = nullptr;
955     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
956     ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, "UPDATE " + g_tableName + " SET assert = NULL, asserts = NULL;"), E_OK);
957     sqlite3_close(db);
958     ContinueToken token = nullptr;
959     CloudSyncData cloudSyncData;
960     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
961     EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK);
962     EXPECT_NE(cloudSyncData.insData.record.size(), 0u);
963     for (const auto &item: cloudSyncData.insData.record) {
964         auto assert = item.find("assert");
965         auto asserts = item.find("asserts");
966         ASSERT_NE(assert, item.end());
967         ASSERT_NE(asserts, item.end());
968         EXPECT_EQ(assert->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
969         EXPECT_EQ(asserts->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
970     }
971     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
972 }
973 
974 /**
975  * @tc.name: GetCloudData005
976  * @tc.desc: Commit the transaction before getCloudData finished
977  * @tc.type: FUNC
978  * @tc.require:
979  * @tc.author: bty
980  */
981 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData005, TestSize.Level1)
982 {
983     CreateLogTable();
984     int64_t insCount = 1024;
985     int64_t photoSize = 1024 * 8;
986     InitLogData(insCount, insCount, insCount, insCount);
987     CreateAndInitUserTable(2 * insCount, photoSize); // 2 is insert,update type data
988 
989     SetDbSchema(g_tableSchema);
990     ContinueToken token = nullptr;
991     CloudSyncData cloudSyncData;
992     EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
993     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
994     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
995     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
996 
997     /**
998      * @tc.steps: GetCloudDataNext after the transaction ends, token will released internally
999      * @tc.expected: return -E_INVALID_DB.
1000      */
1001     ASSERT_EQ(g_cloudStore->GetCloudDataNext(token, cloudSyncData), -E_INVALID_DB);
1002 }
1003 
1004 /**
1005  * @tc.name: GetCloudData006
1006  * @tc.desc: Test get cloud data which contains invalid status asset
1007  * @tc.type: FUNC
1008  * @tc.require:
1009  * @tc.author: bty
1010  */
1011 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData006, TestSize.Level1)
1012 {
1013     /**
1014      * @tc.steps:step1. Init data and set asset status to invalid num
1015      * @tc.expected: step1. return ok.
1016      */
1017     CreateLogTable();
1018     int64_t insCount = 1024;
1019     int64_t photoSize = 1024;
1020     InitLogData(insCount, insCount, insCount, insCount);
1021     CreateAndInitUserTable(2 * insCount, photoSize); // 2 is insert,update type data
1022     Asset asset = g_localAsset;
1023     asset.status = static_cast<uint32_t>(AssetStatus::UPDATE) + 1;
1024     UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid
1025     SetDbSchema(g_tableSchema);
1026 
1027     /**
1028      * @tc.steps:step2. Get cloud data
1029      * @tc.expected: step2. return -E_CLOUD_INVALID_ASSET.
1030      */
1031     ContinueToken token = nullptr;
1032     CloudSyncData cloudSyncData;
1033     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1034     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_CLOUD_INVALID_ASSET);
1035     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
1036 }
1037 
1038 /**
1039  * @tc.name: GetInfoByPrimaryKeyOrGid001
1040  * @tc.desc: Test the query of the GetInfoByPrimaryKeyOrGid interface to obtain assets.
1041  * @tc.type: FUNC
1042  * @tc.require:
1043  * @tc.author: bty
1044  */
1045 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrGid001, TestSize.Level1)
1046 {
1047     int64_t insCount = 100;
1048     int64_t photoSize = 10;
1049     InitUserDataForAssetTest(insCount, photoSize);
1050     InitLogGid(insCount);
1051 
1052     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1053     for (int i = 1; i <= insCount; i++) {
1054         VBucket vBucket;
1055         vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
1056         VBucket assetInfo;
1057         DataInfoWithLog dataInfo;
1058         ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfo, assetInfo), E_OK);
1059         ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i));
1060         auto entry1 = assetInfo.find("assert");
1061         auto entry2 = assetInfo.find("asserts");
1062         ASSERT_NE(entry1, assetInfo.end());
1063         ASSERT_NE(entry2, assetInfo.end());
1064         Asset asset = std::get<Asset>(entry1->second);
1065         EXPECT_EQ(asset.name, "Phone");
1066         Assets assets = std::get<Assets>(entry2->second);
1067         int id = 0;
1068         for (const auto &item: assets) {
1069             EXPECT_EQ(item.name, "Phone" + std::to_string(id++));
1070         }
1071     }
1072     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1073 }
1074 
1075 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncData001, TestSize.Level1)
1076 {
1077     int64_t insCount = 10;
1078     int64_t photoSize = 10;
1079     InitUserDataForAssetTest(insCount, photoSize);
1080     InitLogGid(insCount);
1081 
1082     DownloadData downloadData;
1083     ConstructMultiDownloadData(insCount, downloadData);
1084     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1085     EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1086     ContinueToken token = nullptr;
1087     CloudSyncData cloudSyncData;
1088     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, 0L, token, cloudSyncData), E_OK);
1089     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1090 }
1091 
1092 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset001, TestSize.Level1)
1093 {
1094     int64_t insCount = 10;
1095     int64_t photoSize = 10;
1096     InitUserDataForAssetTest(insCount, photoSize);
1097     InitLogGid(insCount);
1098     fillCloudAssetTest(insCount, AssetStatus::NORMAL, false);
1099     fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, false);
1100     fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, false);
1101     fillCloudAssetTest(insCount, AssetStatus::NORMAL, true);
1102     fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, true);
1103     fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, true);
1104 }
1105 
1106 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, TestSize.Level1)
1107 {
1108     int64_t insCount = 10;
1109     int64_t photoSize = 10;
1110     InitUserDataForAssetTest(insCount, photoSize);
1111     InitLogGid(insCount);
1112 
1113     sqlite3 *db = nullptr;
1114     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1115     sqlite3_stmt *stmt = nullptr;
1116     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName)
1117         + " WHERE data_key = 1;", stmt), E_OK);
1118     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1119     int64_t timeStamp = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1120     int errCode;
1121     SQLiteUtils::ResetStatement(stmt, true, errCode);
1122 
1123     CloudSyncData syncData(g_tableName);
1124     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1125     ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK);
1126     syncData.updData.rowid.push_back(1L);
1127     VBucket bucket1;
1128     Asset asset = g_localAsset;
1129     asset.size = "888";
1130     asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
1131     asset.status = static_cast<uint32_t>(AssetStatus::DELETE);
1132     bucket1.insert_or_assign("assert", asset);
1133     Assets assets;
1134     assets.push_back(asset);
1135     assets.push_back(asset);
1136     bucket1.insert_or_assign("asserts", assets);
1137     syncData.updData.assets.push_back(bucket1);
1138     syncData.updData.timestamp.push_back(timeStamp);
1139     ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK);
1140     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1141 
1142     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT assert, asserts FROM " + g_tableName + " WHERE rowid = 1;",
1143         stmt), E_OK);
1144     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1145     ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_NULL);
1146     ASSERT_EQ(sqlite3_column_type(stmt, 1), SQLITE_NULL);
1147     SQLiteUtils::ResetStatement(stmt, true, errCode);
1148     sqlite3_close(db);
1149 }
1150 
1151 /**
1152  * @tc.name: FillCloudAsset003
1153  * @tc.desc: The twice fill have different assert columns
1154  * @tc.type: FUNC
1155  * @tc.require:
1156  * @tc.author: bty
1157  */
1158 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset003, TestSize.Level0)
1159 {
1160     int64_t insCount = 2;
1161     int64_t photoSize = 10;
1162     InitUserDataForAssetTest(insCount, photoSize);
1163     InitLogGid(insCount);
1164 
1165     sqlite3 *db = nullptr;
1166     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1167     sqlite3_stmt *stmt = nullptr;
1168     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1169         " WHERE data_key in ('1', '2');", stmt), E_OK);
1170     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1171     int64_t timeStamp1 = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1172     int64_t timeStamp2 = static_cast<int64_t>(sqlite3_column_int64(stmt, 1));
1173     int errCode;
1174     SQLiteUtils::ResetStatement(stmt, true, errCode);
1175     sqlite3_close(db);
1176 
1177     CloudSyncData syncData(g_tableName);
1178     syncData.updData.rowid.push_back(1L);
1179     syncData.updData.rowid.push_back(2L);
1180     VBucket bucket1, bucket2;
1181     Asset asset = g_localAsset;
1182     asset.size = "888";
1183     asset.status = static_cast<uint32_t>(AssetStatus::UPDATE);
1184     Assets assets;
1185     assets.push_back(asset);
1186     assets.push_back(asset);
1187     bucket1.insert_or_assign("assert", asset);
1188     bucket2.insert_or_assign("assert", asset);
1189     bucket2.insert_or_assign("asserts", assets);
1190     syncData.updData.assets.push_back(bucket1);
1191     syncData.updData.assets.push_back(bucket2);
1192     syncData.updData.timestamp.push_back(timeStamp1);
1193     syncData.updData.timestamp.push_back(timeStamp2);
1194     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1195     ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK);
1196     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1197 }
1198 
1199 /**
1200  * @tc.name: FillCloudAsset004
1201  * @tc.desc: Test fill asset for insert type
1202  * @tc.type: FUNC
1203  * @tc.require:
1204  * @tc.author: bty
1205  */
1206 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset004, TestSize.Level0)
1207 {
1208     int64_t insCount = 2;
1209     int64_t photoSize = 10;
1210     InitUserDataForAssetTest(insCount, photoSize);
1211 
1212     sqlite3 *db = nullptr;
1213     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1214     sqlite3_stmt *stmt = nullptr;
1215     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1216         " WHERE data_key in ('1', '2');", stmt), E_OK);
1217     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1218     std::vector<int64_t> timeVector;
1219     timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 0)));
1220     timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 1)));
1221     int errCode;
1222     SQLiteUtils::ResetStatement(stmt, true, errCode);
1223     sqlite3_close(db);
1224 
1225     CloudSyncData syncData(g_tableName);
1226     for (int64_t i = 1; i <= insCount; ++i) {
1227         syncData.insData.rowid.push_back(i);
1228         VBucket bucket1;
1229         bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i));
1230         syncData.insData.extend.push_back(bucket1);
1231 
1232         VBucket bucket2;
1233         Asset asset = g_localAsset;
1234         asset.size = "888";
1235         Assets assets;
1236         assets.push_back(asset);
1237         assets.push_back(asset);
1238         bucket2.insert_or_assign("assert", asset);
1239         bucket2.insert_or_assign("asserts", assets);
1240         syncData.insData.assets.push_back(bucket2);
1241         syncData.insData.timestamp.push_back(timeVector[i - 1]);
1242     }
1243     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1244     ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::INSERT, syncData), E_OK);
1245     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1246 }
1247 
1248 /*
1249  * @tc.name: CalPrimaryKeyHash001
1250  * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is string
1251  * @tc.type: FUNC
1252  * @tc.require:
1253  * @tc.author: zhuwentao
1254  */
1255 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash001, TestSize.Level0)
1256 {
1257     /**
1258      * @tc.steps: step1. local insert one data, primary key is string
1259      * @tc.expected: OK.
1260      */
1261     std::string tableName = "user2";
1262     const std::string CREATE_LOCAL_TABLE_SQL =
1263         "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1264         "name TEXT PRIMARY KEY, age INT);";
1265     sqlite3 *db = nullptr;
1266     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1267     EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1268     ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1269     std::string name = "Local0";
1270     std::map<std::string, Type> primaryKey = {{"name", name}};
1271     string sql = "INSERT OR REPLACE INTO user2(name, age) VALUES ('Local" + std::to_string(0) + "', '18');";
1272     EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1273     std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey);
1274     EXPECT_NE(result.size(), 0u);
1275     std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1276     /**
1277      * @tc.steps: step1. query timestamp use hashKey
1278      * @tc.expected: OK.
1279      */
1280     std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1281     sqlite3_stmt *statement = nullptr;
1282     int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1283     EXPECT_EQ(errCode, E_OK);
1284     errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1285     if (errCode != E_OK) {
1286         SQLiteUtils::ResetStatement(statement, true, errCode);
1287         return;
1288     }
1289     errCode = SQLiteUtils::StepWithRetry(statement, false);
1290     if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1291         Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1292         LOGD("get timestamp = %" PRIu64, timestamp);
1293         errCode = E_OK;
1294     } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1295         errCode = -E_NOT_FOUND;
1296     }
1297     EXPECT_EQ(errCode, E_OK);
1298     SQLiteUtils::ResetStatement(statement, true, errCode);
1299     sqlite3_close(db);
1300 }
1301 
1302 /*
1303  * @tc.name: CalPrimaryKeyHash002
1304  * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is int
1305  * @tc.type: FUNC
1306  * @tc.require:
1307  * @tc.author: zhuwentao
1308  */
1309 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash002, TestSize.Level0)
1310 {
1311     /**
1312      * @tc.steps: step1. local insert one data, primary key is int
1313      * @tc.expected: OK.
1314      */
1315     std::string tableName = "user3";
1316     const std::string CREATE_LOCAL_TABLE_SQL =
1317         "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1318         "id INT PRIMARY KEY, name TEXT);";
1319     sqlite3 *db = nullptr;
1320     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1321     EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1322     ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1323     int64_t id = 1;
1324     std::map<std::string, Type> primaryKey = {{"id", id}};
1325     std::string sql = "INSERT OR REPLACE INTO " + tableName + " (id, name) VALUES ('" + '1' + "', 'Local" +
1326         std::to_string(0) + "');";
1327     EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1328     std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey);
1329     EXPECT_NE(result.size(), 0u);
1330     std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1331     /**
1332      * @tc.steps: step1. query timestamp use hashKey
1333      * @tc.expected: OK.
1334      */
1335     std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1336     sqlite3_stmt *statement = nullptr;
1337     int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1338     EXPECT_EQ(errCode, E_OK);
1339     errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1340     if (errCode != E_OK) {
1341         SQLiteUtils::ResetStatement(statement, true, errCode);
1342         return;
1343     }
1344     errCode = SQLiteUtils::StepWithRetry(statement, false);
1345     if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1346         Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1347         LOGD("get timestamp = %" PRIu64, timestamp);
1348         errCode = E_OK;
1349     } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1350         errCode = -E_NOT_FOUND;
1351     }
1352     EXPECT_EQ(errCode, E_OK);
1353     SQLiteUtils::ResetStatement(statement, true, errCode);
1354     sqlite3_close(db);
1355 }
1356 }
1357 #endif // RELATIONAL_STORE