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