• 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 "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      */
__anonb3e9f8950202() 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     });
__anonb3e9f8950302() 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     CreateAndInitUserTable(0, 0, {});
770     CloudSyncData syncData(g_tableName);
771     SetDbSchema(g_tableSchema);
772 
773     /**
774      * @tc.steps: rowid set is empty
775      * @tc.expected: return -E_INVALID_ARGS.
776      */
777     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
778     syncData.insData.rowid.push_back(1);
779     syncData.insData.rowid.push_back(2); // 2 is random id
780 
781     /**
782      * @tc.steps: insData set is empty
783      * @tc.expected: return -E_INVALID_ARGS.
784      */
785     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
786     VBucket bucket1;
787     bucket1.insert_or_assign(g_tableName, g_tableName);
788     bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, 1L);
789     syncData.insData.extend.push_back(bucket1);
790 
791     /**
792      * @tc.steps: the size of rowid and insData is not equal
793      * @tc.expected: return -E_INVALID_ARGS.
794      */
795     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
796 
797     /**
798      * @tc.steps: table name is empty
799      * @tc.expected: return -SQLITE_ERROR.
800      */
801     VBucket bucket2;
802     bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, 2L); // 2L is random field
803     syncData.insData.extend.push_back(bucket2);
804     syncData.tableName = "";
805     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_NOT_FOUND);
806 
807     /**
808      * @tc.steps: the field type does not match
809      * @tc.expected: return -E_CLOUD_ERROR.
810      */
811     syncData.tableName = g_tableName;
812     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_CLOUD_ERROR);
813 
814     /**
815      * @tc.steps: missing field GID_FIELD
816      * @tc.expected: return -E_INVALID_ARGS.
817      */
818     syncData.insData.extend.clear();
819     Timestamp now = TimeHelper::GetSysCurrentTime();
820     bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("1"));
821     bucket2.insert_or_assign(CloudDbConstant::CREATE_FIELD, std::string("2"));
822     syncData.insData.timestamp.push_back((int64_t)now / CloudDbConstant::TEN_THOUSAND);
823     syncData.insData.timestamp.push_back((int64_t)now / CloudDbConstant::TEN_THOUSAND);
824     syncData.insData.extend.push_back(bucket1);
825     syncData.insData.extend.push_back(bucket2);
826     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_INVALID_ARGS);
827 
828     syncData.insData.extend.pop_back();
829     bucket2.insert_or_assign(CloudDbConstant::GID_FIELD, std::string("2"));
830     syncData.insData.extend.push_back(bucket2);
831     syncData.insData.hashKey.push_back({'3', '3'});
832     syncData.insData.hashKey.push_back({'3', '3'});
833     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), E_OK);
834 
835     /**
836      * @tc.steps: table name is not exists
837      * @tc.expected: return -SQLITE_ERROR.
838      */
839     syncData.tableName = "noneTable";
840     EXPECT_EQ(g_cloudStore->FillCloudLogAndAsset(OpType::INSERT, syncData, false, false), -E_NOT_FOUND);
841 }
842 
843 /**
844  * @tc.name: GetCloudData003
845  * @tc.desc: ReleaseContinueToken required when GetCloudDataNext interrupt
846  * @tc.type: FUNC
847  * @tc.require:
848  * @tc.author: bty
849  */
850 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData003, TestSize.Level0)
851 {
852     CreateLogTable(g_tableName);
853     int64_t insCount = 1024;
854     int64_t photoSize = 1024 * 8;
855     InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
856     CreateAndInitUserTable(2 * insCount, photoSize, g_localAsset); // 2 is insert,update type data
857 
858     SetDbSchema(g_tableSchema);
859     ContinueToken token = nullptr;
860     CloudSyncData cloudSyncData(g_tableName);
861     EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
862     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
863     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
864     ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
865     token = nullptr;
866     EXPECT_EQ(g_storageProxy->GetCloudDataNext(token, cloudSyncData), -E_INVALID_ARGS);
867     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
868 
869     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
870     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
871     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
872     ASSERT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
873 }
874 
875 /**
876  * @tc.name: GetCloudData004
877  * @tc.desc: Test get cloudData when asset or assets is NULL
878  * @tc.type: FUNC
879  * @tc.require:
880  * @tc.author: bty
881  */
882 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData004, TestSize.Level0)
883 {
884     CreateLogTable(g_tableName);
885     int64_t insCount = 10;
886     int64_t photoSize = 10;
887     InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
888     CreateAndInitUserTable(3 * insCount, photoSize, g_localAsset); // 3 is insert,update and delete type data
889 
890     SetDbSchema(g_tableSchema);
891     sqlite3 *db = nullptr;
892     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
893     ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, "UPDATE " + g_tableName + " SET assert = NULL, asserts = NULL;"), E_OK);
894     sqlite3_close(db);
895     ContinueToken token = nullptr;
896     CloudSyncData cloudSyncData(g_tableName);
897     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
898     EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK);
899     EXPECT_NE(cloudSyncData.insData.record.size(), 0u);
900     for (const auto &item: cloudSyncData.insData.record) {
901         auto assert = item.find("assert");
902         auto asserts = item.find("asserts");
903         ASSERT_NE(assert, item.end());
904         ASSERT_NE(asserts, item.end());
905         EXPECT_EQ(assert->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
906         EXPECT_EQ(asserts->second.index(), static_cast<size_t>(TYPE_INDEX<Nil>));
907     }
908     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
909 }
910 
911 /**
912  * @tc.name: GetCloudData005
913  * @tc.desc: Commit the transaction before getCloudData finished
914  * @tc.type: FUNC
915  * @tc.require:
916  * @tc.author: bty
917  */
918 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData005, TestSize.Level0)
919 {
920     CreateLogTable(g_tableName);
921     int64_t insCount = 1024;
922     int64_t photoSize = 1024 * 8;
923     InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
924     CreateAndInitUserTable(2 * insCount, photoSize, g_localAsset); // 2 is insert,update type data
925 
926     SetDbSchema(g_tableSchema);
927     ContinueToken token = nullptr;
928     CloudSyncData cloudSyncData(g_tableName);
929     EXPECT_EQ(g_storageProxy->ReleaseContinueToken(token), E_OK);
930     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
931     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
932     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
933 
934     /**
935      * @tc.steps: GetCloudDataNext after the transaction ends, token will released internally
936      * @tc.expected: return -E_INVALID_DB.
937      */
938     ASSERT_EQ(g_cloudStore->GetCloudDataNext(token, cloudSyncData), -E_INVALID_DB);
939 }
940 
941 /**
942  * @tc.name: GetCloudData006
943  * @tc.desc: Test get cloud data which contains invalid status asset
944  * @tc.type: FUNC
945  * @tc.require:
946  * @tc.author: bty
947  */
948 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData006, TestSize.Level0)
949 {
950     /**
951      * @tc.steps:step1. Init data and set asset status to invalid num
952      * @tc.expected: step1. return ok.
953      */
954     CreateLogTable(g_tableName);
955     int64_t insCount = 1024;
956     int64_t photoSize = 1024;
957     InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
958     CreateAndInitUserTable(2 * insCount, photoSize, g_localAsset); // 2 is insert,update type data
959     Asset asset = g_localAsset;
960     asset.status = static_cast<uint32_t>(AssetStatus::UPDATE) + 1;
961     UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid
962     SetDbSchema(g_tableSchema);
963 
964     /**
965      * @tc.steps:step2. Get cloud data
966      * @tc.expected: step2. return -E_CLOUD_ERROR.
967      */
968     ContinueToken token = nullptr;
969     CloudSyncData cloudSyncData;
970     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
971     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_CLOUD_ERROR);
972     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
973 }
974 
975 /**
976  * @tc.name: GetCloudData008
977  * @tc.desc: GetCloudGid other table after GetCloudData.
978  * @tc.type: FUNC
979  * @tc.require:
980  * @tc.author: liaoyonghuang
981  */
982 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData008, TestSize.Level0)
983 {
984     /**
985      * @tc.steps:step1. table1
986      * @tc.expected: step1. return ok.
987      */
988     CreateLogTable(g_tableName);
989     int64_t insCount = 10;
990     int64_t photoSize = 10;
991     InitLogData(insCount, insCount, insCount, insCount, g_logTblName);
992     CreateAndInitUserTable(3 * insCount, photoSize, g_localAsset); // 3 is insert,update and delete type data
993 
994     /**
995      * @tc.steps:step2. table2
996      * @tc.expected: step2. return ok.
997      */
998     std::string tableName2 = "cloudData2";
999     std::string logTblName2 = DBConstant::RELATIONAL_PREFIX + tableName2 + "_log";
1000     CreateLogTable(tableName2);
1001     InitLogData(insCount, insCount, insCount, insCount, logTblName2);
1002     sqlite3 *db = nullptr;
1003     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1004     std::string createTable2Sql = "CREATE TABLE IF NOT EXISTS " + tableName2 + "(name TEXT ,age INT);";
1005     ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, createTable2Sql), E_OK);
1006     sqlite3_close(db);
1007     const std::vector<Field> cloudField2 = {{"name", TYPE_INDEX<std::string>}, {"age", TYPE_INDEX<int64_t>}};
1008     TableSchema tableSchema2;
1009     tableSchema2.name = tableName2;
1010     tableSchema2.sharedTableName = tableName2 + "_shared";
1011     tableSchema2.fields = cloudField2;
1012     DataBaseSchema dataBaseSchema;
1013     dataBaseSchema.tables.push_back(g_tableSchema);
1014     dataBaseSchema.tables.push_back(tableSchema2);
1015     EXPECT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK);
1016 
1017     /**
1018      * @tc.steps:step3. GetCloudData from table1, then GetCloudGid from table2
1019      * @tc.expected: step3. return ok.
1020      */
1021     ContinueToken token = nullptr;
1022     CloudSyncData cloudSyncData(g_tableName);
1023     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1024     EXPECT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK);
1025     QuerySyncObject obj;
1026     obj.SetTableName(tableName2);
1027     std::vector<std::string> cloudGid;
1028     EXPECT_EQ(g_storageProxy->GetCloudGid(obj, false, false, cloudGid), E_OK);
1029     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1030 }
1031 
1032 /**
1033  * @tc.name: GetInfoByPrimaryKeyOrGid001
1034  * @tc.desc: Test the query of the GetInfoByPrimaryKeyOrGid interface to obtain assets.
1035  * @tc.type: FUNC
1036  * @tc.require:
1037  * @tc.author: bty
1038  */
1039 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrGid001, TestSize.Level0)
1040 {
1041     int64_t insCount = 100;
1042     int64_t photoSize = 10;
1043     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1044     InitLogGid(insCount);
1045 
1046     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1047     for (int i = 1; i <= insCount; i++) {
1048         VBucket vBucket;
1049         vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
1050         VBucket assetInfo;
1051         DataInfoWithLog dataInfo;
1052         ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfo, assetInfo), E_OK);
1053         ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i));
1054         auto entry1 = assetInfo.find("assert");
1055         auto entry2 = assetInfo.find("asserts");
1056         ASSERT_NE(entry1, assetInfo.end());
1057         ASSERT_NE(entry2, assetInfo.end());
1058         Asset asset = std::get<Asset>(entry1->second);
1059         EXPECT_EQ(asset.name, "Phone");
1060         Assets assets = std::get<Assets>(entry2->second);
1061         int id = 0;
1062         for (const auto &item: assets) {
1063             EXPECT_EQ(item.name, "Phone" + std::to_string(id++));
1064         }
1065     }
1066     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1067 }
1068 
1069 /**
1070  * @tc.name: GetInfoByPrimaryKeyOrGid002
1071  * @tc.desc: Test the query of the GetInfoByPrimaryKeyOrGid interface to obtain assets.
1072  * @tc.type: FUNC
1073  * @tc.require:
1074  * @tc.author: zqq
1075  */
1076 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrGid002, TestSize.Level0)
1077 {
1078     int64_t insCount = 5;
1079     int64_t photoSize = 1;
1080     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1081     InitLogGid(insCount);
1082     InitLogicDelete(insCount);
1083 
1084     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1085     for (int i = 1; i <= insCount; i++) {
1086         VBucket vBucket;
1087         vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i);
1088         VBucket assetInfo;
1089         DataInfoWithLog dataInfo;
1090         ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfo, assetInfo), E_OK);
1091         ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i));
1092         EXPECT_EQ(assetInfo.size(), 0u);
1093     }
1094     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1095 }
1096 
1097 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncData001, TestSize.Level0)
1098 {
1099     int64_t insCount = 10;
1100     int64_t photoSize = 10;
1101     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1102     InitLogGid(insCount);
1103 
1104     DownloadData downloadData;
1105     std::vector<OpType> opTypes = { OpType::DELETE, OpType::INSERT, OpType::UPDATE,
1106                                     OpType::UPDATE, OpType::NOT_HANDLE };
1107     ConstructMultiDownloadData(insCount, downloadData, opTypes);
1108     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1109     EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK);
1110     ContinueToken token = nullptr;
1111     CloudSyncData cloudSyncData;
1112     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, 0L, token, cloudSyncData), E_OK);
1113     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1114 }
1115 
1116 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset001, TestSize.Level0)
1117 {
1118     int64_t insCount = 10;
1119     int64_t photoSize = 10;
1120     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1121     InitLogGid(insCount);
1122     fillCloudAssetTest(insCount, AssetStatus::NORMAL, false);
1123     fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, false);
1124     fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, false);
1125     fillCloudAssetTest(insCount, AssetStatus::NORMAL, true);
1126     fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, true);
1127     fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, true);
1128 }
1129 
1130 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, TestSize.Level0)
1131 {
1132     int64_t insCount = 10;
1133     int64_t photoSize = 10;
1134     Asset asset1 = g_localAsset;
1135     asset1.status = static_cast<uint32_t>(AssetStatus::DELETE | AssetStatus::UPLOADING);
1136     InitUserDataForAssetTest(insCount, photoSize, asset1);
1137     InitLogGid(insCount);
1138 
1139     sqlite3 *db = nullptr;
1140     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1141     sqlite3_stmt *stmt = nullptr;
1142     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp, hash_key FROM " + DBCommon::GetLogTableName(g_tableName)
1143         + " WHERE data_key = 1;", stmt), E_OK);
1144     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1145     int64_t timeStamp = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1146     Bytes hashKey;
1147     int errCode = SQLiteUtils::GetColumnBlobValue(stmt, 1, hashKey); // 1 is hash_key index
1148     EXPECT_EQ(errCode, E_OK);
1149     SQLiteUtils::ResetStatement(stmt, true, errCode);
1150 
1151     CloudSyncData syncData(g_tableName);
1152     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1153     ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE, syncData), E_OK);
1154     syncData.updData.rowid.push_back(1L);
1155     VBucket bucket1;
1156     Asset asset = g_localAsset;
1157     asset.size = "888";
1158     asset.flag = static_cast<uint32_t>(AssetOpType::NO_CHANGE);
1159     asset.status = static_cast<uint32_t>(AssetStatus::DELETE | AssetStatus::UPLOADING);
1160     bucket1.insert_or_assign("assert", asset);
1161     int id = 0;
1162     Assets assets;
1163     asset.name = asset1.name + std::to_string(id++);
1164     assets.push_back(asset);
1165     asset.name = asset1.name + std::to_string(id++);
1166     assets.push_back(asset);
1167     bucket1.insert_or_assign("asserts", assets);
1168     syncData.updData.assets.push_back(bucket1);
1169     syncData.updData.extend.push_back(bucket1);
1170     syncData.updData.timestamp.push_back(timeStamp);
1171     syncData.updData.hashKey.push_back(hashKey);
1172     ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE, syncData), E_OK);
1173     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1174 
1175     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT assert, asserts FROM " + g_tableName + " WHERE rowid = 1;",
1176         stmt), E_OK);
1177     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1178     ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_NULL);
1179     ASSERT_EQ(sqlite3_column_type(stmt, 1), SQLITE_NULL);
1180     SQLiteUtils::ResetStatement(stmt, true, errCode);
1181     sqlite3_close(db);
1182 }
1183 
1184 /**
1185  * @tc.name: FillCloudAsset003
1186  * @tc.desc: The twice fill have different assert columns
1187  * @tc.type: FUNC
1188  * @tc.require:
1189  * @tc.author: bty
1190  */
1191 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset003, TestSize.Level0)
1192 {
1193     int64_t insCount = 2;
1194     int64_t photoSize = 10;
1195     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1196     InitLogGid(insCount);
1197 
1198     sqlite3 *db = nullptr;
1199     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1200     sqlite3_stmt *stmt = nullptr;
1201     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1202         " WHERE data_key in ('1', '2');", stmt), E_OK);
1203     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1204     int64_t timeStamp1 = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
1205     int64_t timeStamp2 = static_cast<int64_t>(sqlite3_column_int64(stmt, 1));
1206     int errCode;
1207     SQLiteUtils::ResetStatement(stmt, true, errCode);
1208     sqlite3_close(db);
1209 
1210     CloudSyncData syncData(g_tableName);
1211     syncData.updData.rowid.push_back(1L);
1212     syncData.updData.rowid.push_back(2L);
1213     VBucket bucket1, bucket2;
1214     Asset asset = g_localAsset;
1215     asset.size = "888";
1216     asset.status = static_cast<uint32_t>(AssetStatus::UPDATE);
1217     Assets assets;
1218     assets.push_back(asset);
1219     assets.push_back(asset);
1220     bucket1.insert_or_assign("assert", asset);
1221     bucket2.insert_or_assign("assert", asset);
1222     bucket2.insert_or_assign("asserts", assets);
1223     syncData.updData.assets.push_back(bucket1);
1224     syncData.updData.assets.push_back(bucket2);
1225     syncData.updData.extend.push_back(bucket1);
1226     syncData.updData.extend.push_back(bucket2);
1227     syncData.updData.timestamp.push_back(timeStamp1);
1228     syncData.updData.timestamp.push_back(timeStamp2);
1229     syncData.updData.hashKey.push_back({ 1 });
1230     syncData.updData.hashKey.push_back({ 2 });
1231     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1232     ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE, syncData), E_OK);
1233     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1234 }
1235 
1236 /**
1237  * @tc.name: FillCloudAsset004
1238  * @tc.desc: Test fill asset for insert type
1239  * @tc.type: FUNC
1240  * @tc.require:
1241  * @tc.author: bty
1242  */
1243 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset004, TestSize.Level0)
1244 {
1245     int64_t insCount = 2;
1246     int64_t photoSize = 10;
1247     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1248 
1249     sqlite3 *db = nullptr;
1250     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1251     sqlite3_stmt *stmt = nullptr;
1252     ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) +
1253         " WHERE data_key in ('1', '2');", stmt), E_OK);
1254     ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
1255     std::vector<int64_t> timeVector;
1256     timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 0)));
1257     timeVector.push_back(static_cast<int64_t>(sqlite3_column_int64(stmt, 1)));
1258     int errCode;
1259     SQLiteUtils::ResetStatement(stmt, true, errCode);
1260     sqlite3_close(db);
1261 
1262     CloudSyncData syncData(g_tableName);
1263     for (int64_t i = 1; i <= insCount; ++i) {
1264         syncData.insData.rowid.push_back(i);
1265         VBucket bucket1;
1266         bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i));
1267         syncData.insData.extend.push_back(bucket1);
1268 
1269         VBucket bucket2;
1270         Asset asset = g_localAsset;
1271         asset.size = "888";
1272         Assets assets;
1273         assets.push_back(asset);
1274         assets.push_back(asset);
1275         bucket2.insert_or_assign("assert", asset);
1276         bucket2.insert_or_assign("asserts", assets);
1277         syncData.insData.assets.push_back(bucket2);
1278         syncData.insData.timestamp.push_back(timeVector[i - 1]);
1279         syncData.insData.hashKey.push_back({ 1 });
1280     }
1281     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1282     ASSERT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::INSERT, syncData), E_OK);
1283     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1284 }
1285 
1286 /*
1287  * @tc.name: CalPrimaryKeyHash001
1288  * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is string
1289  * @tc.type: FUNC
1290  * @tc.require:
1291  * @tc.author: zhuwentao
1292  */
1293 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash001, TestSize.Level0)
1294 {
1295     /**
1296      * @tc.steps: step1. local insert one data, primary key is string
1297      * @tc.expected: OK.
1298      */
1299     std::string tableName = "user2";
1300     const std::string CREATE_LOCAL_TABLE_SQL =
1301         "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1302         "name TEXT PRIMARY KEY, age INT);";
1303     sqlite3 *db = nullptr;
1304     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1305     EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1306     ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1307     std::string name = "Local0";
1308     std::map<std::string, Type> primaryKey = {{"name", name}};
1309     std::map<std::string, CollateType> collateType = {{"name", CollateType::COLLATE_NONE}};
1310     string sql = "INSERT OR REPLACE INTO user2(name, age) VALUES ('Local" + std::to_string(0) + "', '18');";
1311     EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1312     std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey, collateType);
1313     EXPECT_NE(result.size(), 0u);
1314     std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1315     /**
1316      * @tc.steps: step1. query timestamp use hashKey
1317      * @tc.expected: OK.
1318      */
1319     std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1320     sqlite3_stmt *statement = nullptr;
1321     int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1322     EXPECT_EQ(errCode, E_OK);
1323     errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1324     ASSERT_EQ(errCode, E_OK);
1325     errCode = SQLiteUtils::StepWithRetry(statement, false);
1326     if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1327         Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1328         LOGD("get timestamp = %" PRIu64, timestamp);
1329         errCode = E_OK;
1330     } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1331         errCode = -E_NOT_FOUND;
1332     }
1333     EXPECT_EQ(errCode, E_OK);
1334     SQLiteUtils::ResetStatement(statement, true, errCode);
1335     sqlite3_close(db);
1336 }
1337 
1338 /*
1339  * @tc.name: CalPrimaryKeyHash002
1340  * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is int
1341  * @tc.type: FUNC
1342  * @tc.require:
1343  * @tc.author: zhuwentao
1344  */
1345 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, CalPrimaryKeyHash002, TestSize.Level0)
1346 {
1347     /**
1348      * @tc.steps: step1. local insert one data, primary key is int
1349      * @tc.expected: OK.
1350      */
1351     std::string tableName = "user3";
1352     const std::string CREATE_LOCAL_TABLE_SQL =
1353         "CREATE TABLE IF NOT EXISTS " + tableName + "(" \
1354         "id INT PRIMARY KEY, name TEXT);";
1355     sqlite3 *db = nullptr;
1356     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1357     EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_LOCAL_TABLE_SQL), SQLITE_OK);
1358     ASSERT_EQ(g_delegate->CreateDistributedTable(tableName, CLOUD_COOPERATION), DBStatus::OK);
1359     int64_t id = 1;
1360     std::map<std::string, Type> primaryKey = {{"id", id}};
1361     std::map<std::string, CollateType> collateType = {{"id", CollateType::COLLATE_NONE}};
1362     std::string sql = "INSERT OR REPLACE INTO " + tableName + " (id, name) VALUES ('" + '1' + "', 'Local" +
1363         std::to_string(0) + "');";
1364     EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK);
1365     std::vector<uint8_t> result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey, collateType);
1366     EXPECT_NE(result.size(), 0u);
1367     std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(tableName);
1368     /**
1369      * @tc.steps: step1. query timestamp use hashKey
1370      * @tc.expected: OK.
1371      */
1372     std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?";
1373     sqlite3_stmt *statement = nullptr;
1374     int errCode = SQLiteUtils::GetStatement(db, querysql, statement);
1375     EXPECT_EQ(errCode, E_OK);
1376     errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index
1377     ASSERT_EQ(errCode, E_OK);
1378     errCode = SQLiteUtils::StepWithRetry(statement, false);
1379     if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
1380         Timestamp timestamp = static_cast<Timestamp>(sqlite3_column_int64(statement, 0));
1381         LOGD("get timestamp = %" PRIu64, timestamp);
1382         errCode = E_OK;
1383     } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
1384         errCode = -E_NOT_FOUND;
1385     }
1386     EXPECT_EQ(errCode, E_OK);
1387     SQLiteUtils::ResetStatement(statement, true, errCode);
1388     sqlite3_close(db);
1389 }
1390 
1391 /*
1392  * @tc.name: FillCloudVersion001
1393  * @tc.desc: Test FillCloudLogAndAsset interface when opType is UPDATE_VERSION
1394  * @tc.type: FUNC
1395  * @tc.require:
1396  * @tc.author: bty
1397  */
1398 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudVersion001, TestSize.Level0)
1399 {
1400     /**
1401      * @tc.steps: step1. init data
1402      * @tc.expected: OK.
1403      */
1404     int64_t insCount = 100;
1405     int64_t photoSize = 10;
1406     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1407 
1408     /**
1409      * @tc.steps: step2. FillCloudLogAndAsset which isShared is false, but extend val is empty
1410      * @tc.expected: OK.
1411      */
1412     CloudSyncData syncData(g_tableName);
1413     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1414     EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1415 
1416     /**
1417      * @tc.steps: step3. FillCloudLogAndAsset which isShared is true, but extend val is empty
1418      * @tc.expected: OK.
1419      */
1420     syncData.isShared = true;
1421     EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1422 
1423     /**
1424      * @tc.steps: step4. the extend size is not equal to the hashKey size
1425      * @tc.expected: -E_INVALID_ARGS.
1426      */
1427     VBucket extend1;
1428     extend1.insert_or_assign(CloudDbConstant::VERSION_FIELD, std::string("1"));
1429     syncData.delData.extend.push_back(extend1);
1430     syncData.updData.extend.push_back(extend1);
1431     syncData.insData.extend.push_back(extend1);
1432     EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), -E_INVALID_ARGS);
1433 
1434     /**
1435      * @tc.steps: step5. the extend size is equal to the hashKey size
1436      * @tc.expected: OK.
1437      */
1438     std::string hashKeyStr = "1";
1439     Bytes hashKey(hashKeyStr.begin(), hashKeyStr.end());
1440     syncData.delData.hashKey.push_back(hashKey);
1441     syncData.updData.hashKey.push_back(hashKey);
1442     syncData.insData.hashKey.push_back(hashKey);
1443     EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1444 
1445     /**
1446      * @tc.steps: step6. insert not contain version no effect update
1447      * @tc.expected: OK.
1448      */
1449     syncData.insData.extend[0].erase(CloudDbConstant::VERSION_FIELD);
1450     EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::UPDATE_VERSION, syncData), E_OK);
1451 
1452     /**
1453      * @tc.steps: step7. insert not contain version effect insert
1454      * @tc.expected: E_OK.
1455      */
1456     EXPECT_EQ(g_storageProxy->FillCloudLogAndAsset(OpType::INSERT_VERSION, syncData), E_OK);
1457     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1458 }
1459 
1460 /*
1461  * @tc.name: PutCloudSyncVersion001
1462  * @tc.desc: Test PutCloudSyncData interface that table is share
1463  * @tc.type: FUNC
1464  * @tc.require:
1465  * @tc.author: bty
1466  */
1467 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncVersion001, TestSize.Level0)
1468 {
1469     /**
1470      * @tc.steps: step1. table type is shareTable, but downloadData is not contains version
1471      * @tc.expected: E_OK.
1472      */
1473     int64_t insCount = 10;
1474     int64_t photoSize = 10;
1475     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1476     InitLogGid(insCount);
1477     DownloadData downloadData;
1478     std::vector<OpType> opTypes = { OpType::INSERT, OpType::INSERT, OpType::DELETE, OpType::UPDATE,
1479         OpType::ONLY_UPDATE_GID, OpType::NOT_HANDLE };
1480     ConstructMultiDownloadData(insCount, downloadData, opTypes);
1481     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1482     EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1483     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
1484 
1485     /**
1486      * @tc.steps: step2. PutCloudSyncData and check table row num
1487      * @tc.expected: E_OK.
1488      */
1489     AddVersionToDownloadData(downloadData);
1490     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1491     EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1492     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1493     sqlite3 *db = nullptr;
1494     ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK);
1495     std::string querySql = "SELECT COUNT(*) FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + g_tableName +
1496         CloudDbConstant::SHARED + "_log";
1497     EXPECT_EQ(sqlite3_exec(db, querySql.c_str(),
1498         QueryCountCallback, reinterpret_cast<void *>(2L), nullptr), SQLITE_OK);
1499     sqlite3_close(db);
1500 }
1501 
1502 /*
1503  * @tc.name: PutCloudSyncVersion002
1504  * @tc.desc: Test PutCloudSyncData interface that download data is not contains version
1505  * @tc.type: FUNC
1506  * @tc.require:
1507  * @tc.author: bty
1508  */
1509 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncVersion002, TestSize.Level0)
1510 {
1511     /**
1512      * @tc.steps: step1. table type is shareTable, but downloadData is not contains version
1513      * @tc.expected: E_OK.
1514      */
1515     int64_t insCount = 10;
1516     int64_t photoSize = 10;
1517     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1518     InitLogGid(insCount);
1519     DownloadData downloadData;
1520     std::vector<OpType> opTypes = { OpType::INSERT, OpType::INSERT, OpType::INSERT };
1521     ConstructMultiDownloadData(insCount, downloadData, opTypes);
1522     AddVersionToDownloadData(downloadData);
1523     AddCloudOwnerToDownloadData(downloadData);
1524     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1525     EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1526 
1527     /**
1528      * @tc.steps: step2. test opType of DELETE,UPDATE_TIMESTAMP,and CLEAR_GID without version field
1529      * @tc.expected: E_OK.
1530      */
1531     downloadData.opType = { OpType::DELETE, OpType::UPDATE_TIMESTAMP, OpType::CLEAR_GID };
1532     for (size_t i = 0; i < downloadData.data.size(); i++) {
1533         downloadData.data[i].erase(CloudDbConstant::VERSION_FIELD);
1534     }
1535     EXPECT_EQ(g_storageProxy->PutCloudSyncData(g_tableName + CloudDbConstant::SHARED, downloadData), E_OK);
1536     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1537 }
1538 
1539 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize.Level0)
1540 {
1541     /**
1542      * @tc.steps: step1. both gid and hashKey are empty
1543      * @tc.expected: -E_INVALID_ARGS.
1544      */
1545     int64_t insCount = 10;
1546     int64_t photoSize = 10;
1547     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1548     UpdateLogGidAndHashKey(insCount);
1549     VBucket assets;
1550     std::string gid;
1551     Bytes hashKey;
1552     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1553     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_INVALID_ARGS);
1554     EXPECT_EQ(assets.size(), 0u);
1555 
1556     /**
1557      * @tc.steps: step2. gid is empty, but hashKey is 2
1558      * @tc.expected: E_OK.
1559      */
1560     Asset asset = g_localAsset;
1561     asset.status = static_cast<uint32_t>(AssetStatus::UPDATE);
1562     UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid
1563     std::string pk = "2";
1564     hashKey.assign(pk.begin(), pk.end());
1565     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK);
1566     CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::UPDATE));
1567 
1568     /**
1569      * @tc.steps: step3. gid is empty, but hashKey out of range
1570      * @tc.expected: -E_NOT_FOUND.
1571      */
1572     assets = {};
1573     pk = "11";
1574     hashKey.assign(pk.begin(), pk.end());
1575     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND);
1576     EXPECT_EQ(assets.size(), 0u);
1577 
1578     /**
1579      * @tc.steps: step4. hashKey is empty, but gid is 4
1580      * @tc.expected: E_OK.
1581      */
1582     gid = "2";
1583     pk = {};
1584     assets = {};
1585     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK);
1586     CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::UPDATE));
1587 
1588     /**
1589      * @tc.steps: step5. hashKey is empty, but gid is out of range
1590      * @tc.expected: -E_NOT_FOUND.
1591      */
1592     gid = "11";
1593     assets = {};
1594     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND);
1595     EXPECT_EQ(assets.size(), 0u);
1596     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1597 }
1598 
1599 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset002, TestSize.Level0)
1600 {
1601     /**
1602      * @tc.steps: step1. hashKey is 2, or gid is 4
1603      * @tc.expected: E_OK.
1604      */
1605     int64_t insCount = 10;
1606     int64_t photoSize = 10;
1607     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1608     UpdateLogGidAndHashKey(insCount);
1609     VBucket assets;
1610     Bytes hashKey;
1611     Asset asset = g_localAsset;
1612     asset.status = static_cast<uint32_t>(AssetStatus::INSERT);
1613     UpdateLocalAsset(g_tableName, asset, 4L); // 4 is rowid
1614     std::string gid = "4";
1615     std::string pk = "2";
1616     hashKey.assign(pk.begin(), pk.end());
1617     EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK);
1618     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK);
1619     CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::INSERT));
1620 
1621     /**
1622      * @tc.steps: step2. hashKey is 1, or gid is 11
1623      * @tc.expected: E_OK.
1624      */
1625     assets = {};
1626     gid = "11";
1627     pk = "1";
1628     hashKey.assign(pk.begin(), pk.end());
1629     EXPECT_EQ(
1630         g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_CLOUD_GID_MISMATCH);
1631     CheckGetAsset(assets, static_cast<uint32_t>(AssetStatus::NORMAL));
1632 
1633     /**
1634      * @tc.steps: step3. hashKey is 12, or gid is 11
1635      * @tc.expected: -E_NOT_FOUND.
1636      */
1637     assets = {};
1638     pk = "12";
1639     hashKey.assign(pk.begin(), pk.end());
1640     EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND);
1641     EXPECT_EQ(assets.size(), 0u);
1642     EXPECT_EQ(g_storageProxy->Commit(), E_OK);
1643 }
1644 
1645 /**
1646  * @tc.name: GetCloudData007
1647  * @tc.desc: Test get cloud data which contains abnormal status asset
1648  * @tc.type: FUNC
1649  * @tc.require:
1650  * @tc.author: bty
1651  */
1652 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData007, TestSize.Level0)
1653 {
1654     /**
1655      * @tc.steps:step1. Init data and set asset status to abnormal
1656      * @tc.expected: step1. return ok.
1657      */
1658     CreateLogTable(g_tableName);
1659     int64_t insCount = 10;
1660     int64_t photoSize = 1024 * 100;
1661     InitLogData(insCount * 3, insCount * 3, 1, insCount, g_logTblName); // 3 is multiple
1662     CreateAndInitUserTable(insCount, photoSize, g_localAsset); // 2 is insert,update type data
1663     Asset asset = g_localAsset;
1664     asset.status = static_cast<uint32_t>(AssetStatus::ABNORMAL);
1665     insCount = 50;
1666     CreateAndInitUserTable(insCount, photoSize, asset);
1667     SetDbSchema(g_tableSchema);
1668 
1669     /**
1670      * @tc.steps:step2. Get all cloud data at once
1671      * @tc.expected: step2. return E_OK.
1672      */
1673     ContinueToken token = nullptr;
1674     CloudSyncData cloudSyncData;
1675     EXPECT_EQ(g_storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK);
1676     ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), -E_UNFINISHED);
1677     EXPECT_EQ(g_storageProxy->Rollback(), E_OK);
1678 }
1679 
1680 /**
1681  * @tc.name: ContainAssetsTable001
1682  * @tc.desc: Test cloud schema contain asset table
1683  * @tc.type: FUNC
1684  * @tc.require:
1685  * @tc.author: zqq
1686  */
1687 HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, ContainAssetsTable001, TestSize.Level0)
1688 {
1689     ASSERT_NE(g_storageProxy, nullptr);
1690     EXPECT_FALSE(g_storageProxy->IsExistTableContainAssets());
1691     ASSERT_NE(g_cloudStore, nullptr);
1692     DataBaseSchema dataBaseSchema;
1693     dataBaseSchema.tables.push_back(g_tableSchema);
1694     EXPECT_EQ(g_cloudStore->SetCloudDbSchema(dataBaseSchema), E_OK);
1695     EXPECT_FALSE(g_storageProxy->IsExistTableContainAssets());
1696     int64_t insCount = 100;
1697     int64_t photoSize = 10;
1698     InitUserDataForAssetTest(insCount, photoSize, g_localAsset);
1699     EXPECT_TRUE(g_storageProxy->IsExistTableContainAssets());
1700 }
1701 }
1702 #endif // RELATIONAL_STORE
1703