diff --git a/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h b/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h index 233f766b90fa2aa67bef0cd5e485681699205842..a7e97916f67a4bbc907370c68f33d22643cd2929 100644 --- a/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h +++ b/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h @@ -103,6 +103,11 @@ enum class LockAction : uint32_t { DOWNLOAD = 0x8 }; +enum class SyncFlowType : uint32_t { + NORMAL = 0, + DOWNLOAD_ONLY = 1 +}; + struct CloudSyncOption { std::vector devices; SyncMode mode = SyncMode::SYNC_MODE_CLOUD_MERGE; @@ -117,6 +122,7 @@ struct CloudSyncOption { LockAction lockAction = LockAction::INSERT; std::string prepareTraceId; bool asyncDownloadAssets = false; + SyncFlowType syncFlowType = SyncFlowType::NORMAL; }; enum class QueryNodeType : uint32_t { diff --git a/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.cpp b/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.cpp index 3f22df1c842583f7ea9e9bc59925e0b6e73fb285..a31030fdbad697aa0d69df1d097630285195bf8e 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.cpp @@ -500,6 +500,12 @@ void RDBGeneralUt::CloudBlockSync(const StoreInfo &from, const Query &query, DBS void RDBGeneralUt::CloudBlockSync(const StoreInfo &from, const Query &query, SyncMode mode, DBStatus exceptStatus, DBStatus callbackExpect) +{ + CloudBlockSync(from, query, mode, SyncFlowType::NORMAL, exceptStatus, callbackExpect); +} + +void RDBGeneralUt::CloudBlockSync(const StoreInfo &from, const Query &query, SyncMode mode, SyncFlowType syncFlowType, + DBStatus exceptStatus, DBStatus callbackExpect) { LOGI("[RDBGeneralUt] Begin cloud sync, app %s store %s user %s", from.appId.c_str(), from.storeId.c_str(), from.userId.c_str()); @@ -511,6 +517,7 @@ void RDBGeneralUt::CloudBlockSync(const StoreInfo &from, const Query &query, Syn option.query = query; option.priorityTask = true; option.waitTime = DBConstant::MAX_TIMEOUT; + option.syncFlowType = syncFlowType; RelationalTestUtils::CloudBlockSync(option, delegate, exceptStatus, callbackExpect); } diff --git a/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.h b/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.h index 18da1f4064e2b2560328237c6018991120a4e15e..fbbe7004d59a03ea5c8440d50b0c47f124ee40d0 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.h +++ b/frameworks/libs/distributeddb/test/unittest/common/common/rdb_general_ut.h @@ -105,6 +105,9 @@ protected: void CloudBlockSync(const StoreInfo &from, const Query &query, SyncMode mode, DBStatus exceptStatus, DBStatus callbackExpect); + void CloudBlockSync(const StoreInfo &from, const Query &query, SyncMode mode, SyncFlowType syncFlowType, + DBStatus exceptStatus, DBStatus callbackExpect); + void SetCloudDbConfig(const StoreInfo &info) const; int GetCloudDataCount(const std::string &tableName) const; diff --git a/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp index 5316df6351f1790baf7d640bed9486a95a4d29cd..24988fbf6fcdf373d44fd966cee5709cd0fb9242 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp @@ -13,7 +13,12 @@ * limitations under the License. */ +#include "cloud/cloud_db_constant.h" +#include "cloud/cloud_storage_utils.h" +#include "db_common.h" #include "rdb_general_ut.h" +#include "sqlite_utils.h" +#include "time_helper.h" #ifdef USE_DISTRIBUTEDDB_CLOUD using namespace testing::ext; @@ -28,6 +33,8 @@ public: protected: static constexpr const char *CLOUD_SYNC_TABLE_A = "CLOUD_SYNC_TABLE_A"; static constexpr const char *CLOUD_SYNC_TABLE_B = "CLOUD_SYNC_TABLE_B"; + static constexpr int DATA_COUNT_PER_OP = 20; + static constexpr int ASSET_COUNT = 30; void InitTables(const std::string &table = CLOUD_SYNC_TABLE_A); void InitCompositeTable(const StoreInfo &info1, const StoreInfo &info2, const std::string &table = CLOUD_SYNC_TABLE_B); @@ -37,6 +44,17 @@ protected: const std::vector &tables = {CLOUD_SYNC_TABLE_A}); void ExpireCursorWithEmptyGid(bool isLogicDelete, SyncMode mode = SyncMode::SYNC_MODE_CLOUD_MERGE); int GetActualTableColumnCount(const StoreInfo &info, const std::string &table); + + void InsertCloudData(int64_t begin, int64_t count, const std::string &tableName); + void UpdateCloudData(int64_t begin, int64_t count, const std::string &tableName); + void DeleteCloudData(int64_t begin, int64_t count, const std::string &tableName); + void InsertLocalData(int64_t begin, int64_t count, const StoreInfo &info, const std::string &tableName); + void UpdateLocalData(int64_t begin, int64_t count, const StoreInfo &info, const std::string &tableName); + void DeleteLocalData(int64_t begin, int64_t count, const StoreInfo &info, const std::string &tableName); + void SetAssetsDownloadingStatus(int64_t begin, int64_t count, const StoreInfo &info, const std::string &tableName); + int GetLocalDataCount(const StoreInfo &info, const std::string &tableName); + int GetCloudDataCount(const std::string &tableName); + StoreInfo info1_ = {USER_ID, APP_ID, STORE_ID_1}; StoreInfo info2_ = {USER_ID, APP_ID, STORE_ID_2}; }; @@ -62,7 +80,8 @@ void DistributedDBRDBComplexCloudTest::InitTables(const std::string &table) { std::string sql = "CREATE TABLE IF NOT EXISTS " + table + "(" "id INTEGER PRIMARY KEY AUTOINCREMENT," - "intCol INTEGER, stringCol1 TEXT, stringCol2 TEXT, uuidCol TEXT)"; + "intCol INTEGER, stringCol1 TEXT, stringCol2 TEXT, uuidCol TEXT," + "assetCol ASSET, assetsCol ASSETS)"; EXPECT_EQ(ExecuteSQL(sql, info1_), E_OK); EXPECT_EQ(ExecuteSQL(sql, info2_), E_OK); } @@ -72,6 +91,7 @@ void DistributedDBRDBComplexCloudTest::InitCompositeTable(const StoreInfo &info1 { std::string sql = "CREATE TABLE IF NOT EXISTS " + table + "(" "id INTEGER, intCol INTEGER, stringCol1 TEXT, stringCol2 TEXT," + "assetCol ASSET, assetsCol ASSETS," "PRIMARY KEY (id, intCol))"; EXPECT_EQ(ExecuteSQL(sql, info1), E_OK); EXPECT_EQ(ExecuteSQL(sql, info2), E_OK); @@ -84,6 +104,8 @@ void DistributedDBRDBComplexCloudTest::InitSchema(const StoreInfo &info, const s {{"intCol", TYPE_INDEX, false, true}, false}, {{"stringCol1", TYPE_INDEX, false, true}, false}, {{"stringCol2", TYPE_INDEX, false, true}, false}, + {{"assetCol", TYPE_INDEX, false, true}, false}, + {{"assetsCol", TYPE_INDEX, false, true}, false}, }; UtDateBaseSchemaInfo schemaInfo = { .tablesInfo = { @@ -100,6 +122,8 @@ void DistributedDBRDBComplexCloudTest::InitCompositeSchema(const StoreInfo &info {{"intCol", TYPE_INDEX, true, true}, false}, {{"stringCol1", TYPE_INDEX, false, true}, false}, {{"stringCol2", TYPE_INDEX, false, true}, false}, + {{"assetCol", TYPE_INDEX, false, true}, false}, + {{"assetsCol", TYPE_INDEX, false, true}, false}, }; UtDateBaseSchemaInfo schemaInfo = { .tablesInfo = { @@ -156,7 +180,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor001, TestSize.Level0) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -188,7 +213,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor002, TestSize.Level2) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -217,7 +243,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor003, TestSize.Level2) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -250,7 +277,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor004, TestSize.Level2) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -278,9 +306,10 @@ void DistributedDBRDBComplexCloudTest::ExpireCursorWithEmptyGid(bool isLogicDele * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); - ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(2, 2, 'text3', 'text4', 'uuid2')", info2_); + ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(2, 2, 'text3', 'text4', 'uuid2', NULL, NULL)", info2_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -357,7 +386,7 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor007, TestSize.Level0) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_B VALUES(1, 1, 'text1', 'text2')", info1); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_B VALUES(1, 1, 'text1', 'text2', NULL, NULL)", info1); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -389,7 +418,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor008, TestSize.Level0) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push and store2 pull @@ -454,7 +484,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor011, TestSize.Level2) * @tc.steps:step1. store1 insert one data * @tc.expected: step1. insert success. */ - auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL)", + info1_); ASSERT_EQ(ret, E_OK); /** * @tc.steps:step2. store1 push @@ -489,7 +520,7 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, UpgradeDistributedTable001, TestSize. { /** * @tc.steps:step1. Get column count from actual database before modification - * @tc.expected: step1. Get original column count (4 columns: id, intCol, stringCol1, stringCol2). + * @tc.expected: step1. Get original column count (6 columns: id, intCol, stringCol1, stringCol2, assetCol, assetsCol). */ int originalColumnCount = GetActualTableColumnCount(info1_, CLOUD_SYNC_TABLE_A); EXPECT_GE(originalColumnCount, 0); @@ -514,7 +545,8 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, UpgradeDistributedTable001, TestSize. * @tc.steps:step4. Insert data with new column * @tc.expected: step4. insert success. */ - ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', 100)", info1_); + ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1', NULL, NULL, 100)", + info1_); EXPECT_EQ(ret, E_OK); /** @@ -540,5 +572,360 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, UpgradeDistributedTable001, TestSize. auto count = CountTableData(info1_, CLOUD_SYNC_TABLE_A); EXPECT_GE(count, 1); } + +void DistributedDBRDBComplexCloudTest::InsertCloudData(int64_t begin, int64_t count, const std::string &tableName) +{ + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + std::vector records; + std::vector extends; + for (int64_t i = begin; i < begin + count; ++i) { + VBucket record; + record["id"] = i; + record["intCol"] = i * 10; + record["stringCol1"] = "insert_" + std::to_string(i); + record["stringCol2"] = "insert_str2_" + std::to_string(i); + record["uuidCol"] = "uuid_" + std::to_string(i); + record["assetCol"] = Asset{}; + record["assetsCol"] = Assets{}; + records.push_back(std::move(record)); + + VBucket extend; + extend[CloudDbConstant::GID_FIELD] = std::to_string(i); + extend[CloudDbConstant::CREATE_FIELD] = static_cast(TimeHelper::GetSysCurrentTime() / + CloudDbConstant::TEN_THOUSAND); + extend[CloudDbConstant::MODIFY_FIELD] = static_cast(TimeHelper::GetSysCurrentTime() / + CloudDbConstant::TEN_THOUSAND); + extend[CloudDbConstant::DELETE_FIELD] = false; + extends.push_back(std::move(extend)); + } + EXPECT_EQ(cloudDB->BatchInsertWithGid(tableName, std::move(records), extends), DBStatus::OK); + LOGI("[DistributedDBRDBComplexCloudTest] InsertCloudData success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +void DistributedDBRDBComplexCloudTest::UpdateCloudData(int64_t begin, int64_t count, const std::string &tableName) +{ + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + std::vector records; + std::vector extends; + for (int64_t i = begin; i < begin + count; ++i) { + VBucket record; + record["id"] = i; + record["intCol"] = i * 100; + record["stringCol1"] = "update_" + std::to_string(i); + record["stringCol2"] = "update_str2_" + std::to_string(i); + record["uuidCol"] = "uuid_update_" + std::to_string(i); + record["assetCol"] = Asset{}; + record["assetsCol"] = Assets{}; + records.push_back(std::move(record)); + + VBucket extend; + extend[CloudDbConstant::GID_FIELD] = std::to_string(i); + extend[CloudDbConstant::VERSION_FIELD] = std::to_string(i + 1000); + extends.push_back(std::move(extend)); + } + EXPECT_EQ(cloudDB->BatchUpdate(tableName, std::move(records), extends), DBStatus::OK); + + LOGI("[DistributedDBRDBComplexCloudTest] UpdateCloudData success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +void DistributedDBRDBComplexCloudTest::DeleteCloudData(int64_t begin, int64_t count, const std::string &tableName) +{ + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + std::vector extends; + for (int64_t i = begin; i < begin + count; ++i) { + VBucket extend; + extend[CloudDbConstant::GID_FIELD] = std::to_string(i); + extends.push_back(std::move(extend)); + } + EXPECT_EQ(cloudDB->BatchDelete(tableName, extends), DBStatus::OK); + LOGI("[DistributedDBRDBComplexCloudTest] DeleteCloudData success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +void DistributedDBRDBComplexCloudTest::InsertLocalData(int64_t begin, int64_t count, const StoreInfo &info, + const std::string &tableName) +{ + for (int64_t i = begin; i < begin + count; ++i) { + std::string sql = "INSERT INTO " + tableName + " VALUES(" + std::to_string(i) + ", " + + std::to_string(i * 10) + ", 'local_insert_" + std::to_string(i) + "', 'local_str2_" + + std::to_string(i) + "', 'local_uuid_" + std::to_string(i) + "', NULL, NULL)"; + EXPECT_EQ(ExecuteSQL(sql, info), E_OK); + } + LOGI("[DistributedDBRDBComplexCloudTest] InsertLocalData success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +void DistributedDBRDBComplexCloudTest::UpdateLocalData(int64_t begin, int64_t count, const StoreInfo &info, + const std::string &tableName) +{ + for (int64_t i = begin; i < begin + count; ++i) { + std::string sql = "UPDATE " + tableName + " SET intCol=" + std::to_string(i * 100) + + ", stringCol1='local_update_" + std::to_string(i) + "' WHERE id=" + std::to_string(i); + EXPECT_EQ(ExecuteSQL(sql, info), E_OK); + } + LOGI("[DistributedDBRDBComplexCloudTest] UpdateLocalData success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +void DistributedDBRDBComplexCloudTest::DeleteLocalData(int64_t begin, int64_t count, const StoreInfo &info, + const std::string &tableName) +{ + for (int64_t i = begin; i < begin + count; ++i) { + std::string sql = "DELETE FROM " + tableName + " WHERE id=" + std::to_string(i); + EXPECT_EQ(ExecuteSQL(sql, info), E_OK); + } + LOGI("[DistributedDBRDBComplexCloudTest] DeleteLocalData success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +void DistributedDBRDBComplexCloudTest::SetAssetsDownloadingStatus(int64_t begin, int64_t count, const StoreInfo &info, + const std::string &tableName) +{ + auto db = GetSqliteHandle(info); + ASSERT_NE(db, nullptr); + std::string logTable = DBCommon::GetLogTableName(tableName); + std::string sql = "UPDATE " + logTable + " SET status=" + + std::to_string(static_cast(AssetStatus::DOWNLOADING)) + + " WHERE data_key >= " + std::to_string(begin) + + " AND data_key < " + std::to_string(begin + count); + EXPECT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK); + LOGI("[DistributedDBRDBComplexCloudTest] SetAssetsDownloadingStatus success, begin=%" PRId64 ", count=%" PRId64, + begin, count); +} + +int DistributedDBRDBComplexCloudTest::GetLocalDataCount(const StoreInfo &info, const std::string &tableName) +{ + return CountTableData(info, tableName); +} + +int DistributedDBRDBComplexCloudTest::GetCloudDataCount(const std::string &tableName) +{ + return RDBGeneralUt::GetCloudDataCount(tableName); +} + +/** + * @tc.name: DownloadOnlySync001 + * @tc.desc: Test downloadOnly sync with MERGE mode, local has no data, cloud has insert/update/delete data. + * @tc.type: FUNC + * @tc.author: xiefengzhu + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, DownloadOnlySync001, TestSize.Level0) +{ + /** + * @tc.steps:step1. Prepare cloud data: insert/update/delete 20 records each + * @tc.expected: step1. cloud data prepared successfully. + */ + InsertCloudData(1, DATA_COUNT_PER_OP, CLOUD_SYNC_TABLE_A); + UpdateCloudData(1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + DeleteCloudData(DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + + int cloudCountBefore = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + LOGI("[DownloadOnlySync001] Cloud data count before sync: %d", cloudCountBefore); + + /** + * @tc.steps:step2. Execute downloadOnly sync with MERGE mode + * @tc.expected: step2. sync success. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, + SyncFlowType::DOWNLOAD_ONLY, OK, OK)); + + /** + * @tc.steps:step3. Verify local data is consistent with cloud + * @tc.expected: step3. local data count matches cloud. + */ + int localCountAfter = GetLocalDataCount(info1_, CLOUD_SYNC_TABLE_A); + int cloudCountAfter = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + LOGI("[DownloadOnlySync001] Local count after sync: %d, Cloud count: %d", localCountAfter, cloudCountAfter); + EXPECT_EQ(localCountAfter, cloudCountAfter); +} + +/** + * @tc.name: DownloadOnlySync002 + * @tc.desc: Test downloadOnly sync with MERGE mode, both local and cloud have insert/update/delete data. + * @tc.expected: Local data not uploaded, local data correctly updated. + * @tc.type: FUNC + * @tc.author: xiefengzhu + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, DownloadOnlySync002, TestSize.Level0) +{ + /** + * @tc.steps:step1. Prepare local data: insert/update/delete 20 records each + * @tc.expected: step1. local data prepared successfully. + */ + InsertLocalData(1, DATA_COUNT_PER_OP, info1_, CLOUD_SYNC_TABLE_A); + UpdateLocalData(1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + DeleteLocalData(DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + + int localCountBefore = GetLocalDataCount(info1_, CLOUD_SYNC_TABLE_A); + LOGI("[DownloadOnlySync002] Local data count before sync: %d", localCountBefore); + + /** + * @tc.steps:step2. Prepare cloud data: insert/update/delete 20 records each (different range) + * @tc.expected: step2. cloud data prepared successfully. + */ + InsertCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP, CLOUD_SYNC_TABLE_A); + UpdateCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + DeleteCloudData(DATA_COUNT_PER_OP + DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + + int cloudCountBefore = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + LOGI("[DownloadOnlySync002] Cloud data count before sync: %d", cloudCountBefore); + + /** + * @tc.steps:step3. Execute downloadOnly sync with MERGE mode + * @tc.expected: step3. sync success. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, + SyncFlowType::DOWNLOAD_ONLY, OK, OK)); + + /** + * @tc.steps:step4. Verify local data not uploaded and correctly updated + * @tc.expected: step4. cloud data count unchanged, local data merged correctly. + */ + int cloudCountAfter = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + EXPECT_EQ(cloudCountAfter, cloudCountBefore); + + int localCountAfter = GetLocalDataCount(info1_, CLOUD_SYNC_TABLE_A); + LOGI("[DownloadOnlySync002] Local count after sync: %d", localCountAfter); + EXPECT_GE(localCountAfter, localCountBefore); +} + +/** + * @tc.name: DownloadOnlySync003 + * @tc.desc: Test downloadOnly sync with MERGE mode, local has DOWNLOADING status assets. + * @tc.expected: Local data not uploaded, local data correctly updated, assets downloaded. + * @tc.type: FUNC + * @tc.author: xiefengzhu + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, DownloadOnlySync003, TestSize.Level0) +{ + /** + * @tc.steps:step1. Prepare local data with DOWNLOADING status assets + * @tc.expected: step1. local data prepared successfully. + */ + InsertLocalData(1, DATA_COUNT_PER_OP, info1_, CLOUD_SYNC_TABLE_A); + UpdateLocalData(1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + DeleteLocalData(DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + SetAssetsDownloadingStatus(1, ASSET_COUNT, info1_, CLOUD_SYNC_TABLE_A); + + /** + * @tc.steps:step2. Prepare cloud data + * @tc.expected: step2. cloud data prepared successfully. + */ + InsertCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP, CLOUD_SYNC_TABLE_A); + UpdateCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + DeleteCloudData(DATA_COUNT_PER_OP + DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + + int cloudCountBefore = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + + /** + * @tc.steps:step3. Execute downloadOnly sync with MERGE mode + * @tc.expected: step3. sync success. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, + SyncFlowType::DOWNLOAD_ONLY, OK, OK)); + + /** + * @tc.steps:step4. Verify local data not uploaded and correctly updated + * @tc.expected: step4. cloud data count unchanged, local data merged correctly. + */ + int cloudCountAfter = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + EXPECT_EQ(cloudCountAfter, cloudCountBefore); +} + +/** + * @tc.name: DownloadOnlySync004 + * @tc.desc: Test downloadOnly sync with FORCE_PULL mode, local has DOWNLOADING status assets. + * @tc.expected: Local data not uploaded, local data correctly updated. + * @tc.type: FUNC + * @tc.author: xiefengzhu + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, DownloadOnlySync004, TestSize.Level0) +{ + /** + * @tc.steps:step1. Prepare local data with DOWNLOADING status assets + * @tc.expected: step1. local data prepared successfully. + */ + InsertLocalData(1, DATA_COUNT_PER_OP, info1_, CLOUD_SYNC_TABLE_A); + UpdateLocalData(1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + DeleteLocalData(DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + SetAssetsDownloadingStatus(1, ASSET_COUNT, info1_, CLOUD_SYNC_TABLE_A); + + /** + * @tc.steps:step2. Prepare cloud data + * @tc.expected: step2. cloud data prepared successfully. + */ + InsertCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP, CLOUD_SYNC_TABLE_A); + UpdateCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + DeleteCloudData(DATA_COUNT_PER_OP + DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + + int cloudCountBefore = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + + /** + * @tc.steps:step3. Execute downloadOnly sync with FORCE_PULL mode + * @tc.expected: step3. sync success. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, + SyncFlowType::DOWNLOAD_ONLY, OK, OK)); + + /** + * @tc.steps:step4. Verify local data not uploaded and correctly updated + * @tc.expected: step4. cloud data count unchanged, local data updated with cloud priority. + */ + int cloudCountAfter = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + EXPECT_EQ(cloudCountAfter, cloudCountBefore); +} + +/** + * @tc.name: DownloadOnlySync005 + * @tc.desc: Test downloadOnly sync with FORCE_PUSH mode, local has DOWNLOADING status assets. + * @tc.expected: Local data not uploaded, local data correctly updated. + * @tc.type: FUNC + * @tc.author: xiefengzhu + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, DownloadOnlySync005, TestSize.Level0) +{ + /** + * @tc.steps:step1. Prepare local data with DOWNLOADING status assets + * @tc.expected: step1. local data prepared successfully. + */ + InsertLocalData(1, DATA_COUNT_PER_OP, info1_, CLOUD_SYNC_TABLE_A); + UpdateLocalData(1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + DeleteLocalData(DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, info1_, CLOUD_SYNC_TABLE_A); + SetAssetsDownloadingStatus(1, ASSET_COUNT, info1_, CLOUD_SYNC_TABLE_A); + + /** + * @tc.steps:step2. Prepare cloud data + * @tc.expected: step2. cloud data prepared successfully. + */ + InsertCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP, CLOUD_SYNC_TABLE_A); + UpdateCloudData(DATA_COUNT_PER_OP + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + DeleteCloudData(DATA_COUNT_PER_OP + DATA_COUNT_PER_OP / 2 + 1, DATA_COUNT_PER_OP / 2, CLOUD_SYNC_TABLE_A); + + int cloudCountBefore = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + + /** + * @tc.steps:step3. Execute downloadOnly sync with FORCE_PUSH mode + * @tc.expected: step3. sync success. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_FORCE_PUSH, + SyncFlowType::DOWNLOAD_ONLY, OK, OK)); + + /** + * @tc.steps:step4. Verify local data not uploaded (downloadOnly skips upload) + * @tc.expected: step4. cloud data count unchanged, local data updated. + */ + int cloudCountAfter = GetCloudDataCount(CLOUD_SYNC_TABLE_A); + EXPECT_EQ(cloudCountAfter, cloudCountBefore); +} } #endif