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