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