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 a8bae4650df73a8a26f92e016af68c889fdb1adf..862a42fb691a2cbaccf3b5de1406265ae16a5832 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 @@ -179,5 +179,127 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor001, TestSize.Level0) EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); cloudDB->ForkAfterQueryResult(nullptr); } + +/** + * @tc.name: ExpireCursor002 + * @tc.desc: Test sync with expire cursor. + * @tc.type: FUNC + * @tc.author: xiefengzhu + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor002, 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_); + ASSERT_EQ(ret, E_OK); + /** + * @tc.steps:step2. store1 push and store2 pull + * @tc.expected: step2. sync success and stringCol2 is null because store1 don't sync stringCol2. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_EQ(CountTableData(info2_, CLOUD_SYNC_TABLE_A, "uuidCol='uuid1'"), 1); + + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + /** + * @tc.steps:step2. store2 merge sync again, inject expried cursor and return empty gid + * @tc.expected: step3. sync success and local record deleted + */ + std::atomic count = 0; + cloudDB->SetRtnEmptyGID(true); + cloudDB->ForkAfterQueryResult([&count](VBucket &, std::vector &) { + count++; + return count == 1 ? DBStatus::EXPIRED_CURSOR : DBStatus::QUERY_END; + }); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_EQ(CountTableData(info2_, CLOUD_SYNC_TABLE_A, "uuidCol='uuid1'"), 0); + cloudDB->ForkAfterQueryResult(nullptr); +} + +/** + * @tc.name: ExpireCursor003 + * @tc.desc: Expire cursor -> return correct gid -> sync success and local record not deleted. + * @tc.type: FUNC + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor003, 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_); + ASSERT_EQ(ret, E_OK); + /** + * @tc.steps:step2. store1 and store2 merge sync + * @tc.expected: step2. sync success and store2 has the record. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_EQ(CountTableData(info2_, CLOUD_SYNC_TABLE_A, "uuidCol='uuid1'"), 1); + + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + /** + * @tc.steps:step3. store2 merge sync again, inject expired cursor but keep gid normal + * @tc.expected: step3. sync success and local record not deleted. + */ + std::atomic count = 0; + cloudDB->ForkAfterQueryResult([&count](VBucket &, std::vector &) { + count++; + return (count == 1) ? DBStatus::EXPIRED_CURSOR : DBStatus::QUERY_END; + }); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_EQ(CountTableData(info2_, CLOUD_SYNC_TABLE_A, "uuidCol='uuid1'"), 1); + cloudDB->ForkAfterQueryResult(nullptr); +} + +/** + * @tc.name: ExpireCursor004 + * @tc.desc: After expire-cursor sync, call RemoveDeviceData and ensure temp table removed. + * @tc.type: FUNC + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor004, TestSize.Level0) +{ + /** + * @tc.steps:step1. store1 insert one data and both sides merge sync + * @tc.expected: step1. sync success. + */ + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + ASSERT_EQ(ret, E_OK); + + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_EQ(CountTableData(info2_, CLOUD_SYNC_TABLE_A, "uuidCol='uuid1'"), 1); + /** + * @tc.steps:step2. store2 merge sync again with expired cursor injection to trigger gid-temp-table flow + * @tc.expected: step2. sync success. + */ + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + std::atomic count = 0; + cloudDB->ForkAfterQueryResult([&count](VBucket &, std::vector &) { + count++; + return (count == 1) ? DBStatus::EXPIRED_CURSOR : DBStatus::QUERY_END; + }); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + cloudDB->ForkAfterQueryResult(nullptr); + /** + * @tc.steps:step3. after sync finished, call RemoveDeviceData + * @tc.expected: step3. temp table removed. + */ + auto delegate = GetDelegate(info2_); + ASSERT_NE(delegate, nullptr); + EXPECT_EQ(CountTableData(info2_, DBCommon::GetTmpLogTableName(CLOUD_SYNC_TABLE_A), ""), 1); + EXPECT_EQ(delegate->RemoveDeviceData("", ClearMode::FLAG_ONLY), DBStatus::OK); + EXPECT_EQ(CountTableData(info2_, DBCommon::GetTmpLogTableName(CLOUD_SYNC_TABLE_A), ""), 0); +} } #endif \ No newline at end of file diff --git a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp index c60a674ca2b074f3c5010cbc742738dabeaff2ae..c833b2043fe53a49d1e3e94b73f45c88f3d30eaa 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp @@ -733,6 +733,14 @@ DBStatus VirtualCloudDb::QueryAllGid(const std::string &tableName, VBucket &exte TYPE_INDEX, cursor.c_str()); cursor = cursor.empty() ? "0" : cursor; GetCloudData(cursor, isIncreCursor, cloudData_[tableName], data, copyExtend); + if (emptyGID_) { + data.clear(); + } return (data.empty() || data.size() < static_cast(queryLimit_)) ? QUERY_END : OK; } + +void VirtualCloudDb::SetRtnEmptyGID(bool isEmptyGID) +{ + emptyGID_ = isEmptyGID; +} } \ No newline at end of file diff --git a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h index ac1f09f8096a2bea8e0f8f5ce972005d763ee5cb..f7031fd3116689710f72db668d7b6e2752f46951 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h +++ b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h @@ -110,6 +110,8 @@ public: void SetCloudAssetSpaceInsufficient(bool isInsufficient); void SetUploadRecordStatus(DBStatus status); + + void SetRtnEmptyGID(bool isEmptyGID); private: DBStatus InnerBatchInsert(const std::string &tableName, std::vector &&record, std::vector &extend); @@ -152,6 +154,7 @@ private: std::atomic lockCount_ = 0; std::atomic insertFailedCount_ = 0; std::atomic missingExtendCount_ = 0; + bool emptyGID_ = false; bool cloudSpaceInsufficient_ = false; std::mutex cloudDataMutex_; std::map> cloudData_;