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