diff --git a/datamgr_service/services/distributeddataservice/adapter/include/permission/permission_validator.h b/datamgr_service/services/distributeddataservice/adapter/include/permission/permission_validator.h index ab78f1990e0fd3df0a1680964e34aded0810d2cc..322d8b00257603b82440057df5da7488a33601a0 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/permission/permission_validator.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/permission/permission_validator.h @@ -27,9 +27,11 @@ public: // check whether the client process have enough privilege to share data with the other devices. // tokenId: client process tokenId API_EXPORT bool CheckSyncPermission(uint32_t tokenId); + API_EXPORT bool IsCloudConfigPermit(uint32_t tokenId); private: static constexpr const char *DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; + static constexpr const char *CLOUD_DATA_CONFIG = "ohos.permission.CLOUDDATA_CONFIG"; }; } // namespace DistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/permission/src/permission_validator.cpp b/datamgr_service/services/distributeddataservice/adapter/permission/src/permission_validator.cpp index 93218763ca61ba9e4d1a5ea35692fabb7ce5a8fd..7155a0fb8241727e636560af9df2e352e3a8c4c6 100644 --- a/datamgr_service/services/distributeddataservice/adapter/permission/src/permission_validator.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/permission/src/permission_validator.cpp @@ -42,5 +42,12 @@ bool PermissionValidator::CheckSyncPermission(uint32_t tokenId) ZLOGE("token:0x%{public}x", tokenId); return false; } + +bool PermissionValidator::IsCloudConfigPermit(uint32_t tokenId) +{ + auto permit = AccessTokenKit::VerifyAccessToken(tokenId, CLOUD_DATA_CONFIG); + ZLOGD("cloud permit: %{public}d", permit); + return permit == PERMISSION_GRANTED; +} } // namespace DistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h index 9d900cb98de9cc772114adca2bf4fd5cdeac896b..6090835553a208c22afc1797b0caebfbce659ec8 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h @@ -62,7 +62,6 @@ private: WORK_BUTT, }; - static constexpr int32_t SYSTEM_USER = 0; static constexpr int32_t RETRY_TIMES = 10; static constexpr int32_t RETRY_INTERVAL = 30; static constexpr int32_t EXPIRE_INTERVAL = 7 * 24; // 7 day diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp index b14485f4fb8b5056cd39286329f207ac6f557623..644d075069b8363f0ad4ea4932373ec26c44f161 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp @@ -20,6 +20,7 @@ #include "log_print.h" #include "utils/anonymous.h" #include "tokenid_kit.h" +#include "permission_validator.h" namespace OHOS::CloudData { using namespace DistributedData; using namespace OHOS::Security::AccessToken; @@ -52,6 +53,12 @@ int CloudServiceStub::OnRemoteRequest(uint32_t code, OHOS::MessageParcel &data, return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; } + if (!DistributedKv::PermissionValidator::GetInstance().IsCloudConfigPermit(IPCSkeleton::GetCallingTokenID())) { + ZLOGE("permission denied! code:%{public}u, BUTT:%{public}d", code, TRANS_BUTT); + auto result = static_cast(CLOUD_CONFIG_PERMISSION_DENIED); + return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; + } + std::string id; if (!ITypesUtil::Unmarshal(data, id)) { ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f79f4bb8ac80201795a83e58388932a35bc09ae9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "RdbCloud" +#include "rdb_cloud.h" +#include "log_print.h" +#include "value_proxy.h" + +namespace OHOS::DistributedRdb { +using namespace DistributedDB; +using namespace DistributedData; +RdbCloud::RdbCloud(std::shared_ptr cloudDB) + : cloudDB_(std::move(cloudDB)) +{ +} + +DBStatus RdbCloud::BatchInsert( + const std::string &tableName, std::vector &&record, std::vector &extend) +{ + DistributedData::VBuckets extends; + auto error = cloudDB_->BatchInsert(tableName, ValueProxy::Convert(std::move(record)), extends); + if (error == GeneralError::E_OK) { + extend = ValueProxy::Convert(std::move(extends)); + } + return ValueProxy::ConvertStatus(static_cast(error)); +} + +DBStatus RdbCloud::BatchUpdate( + const std::string &tableName, std::vector &&record, std::vector &extend) +{ + auto error = cloudDB_->BatchUpdate( + tableName, ValueProxy::Convert(std::move(record)), ValueProxy::Convert(std::move(extend))); + return ValueProxy::ConvertStatus(static_cast(error)); +} + +DBStatus RdbCloud::BatchDelete(const std::string &tableName, std::vector &extend) +{ + auto error = cloudDB_->BatchDelete(tableName, ValueProxy::Convert(std::move(extend))); + return ValueProxy::ConvertStatus(static_cast(error)); +} + +DBStatus RdbCloud::Query(const std::string &tableName, DBVBucket &extend, std::vector &data) +{ + auto cursor = cloudDB_->Query(tableName, ValueProxy::Convert(std::move(extend))); + if (cursor == nullptr) { + ZLOGE("cursor is null, table:%{public}s, extend:%{public}zu", tableName.c_str(), extend.size()); + return ValueProxy::ConvertStatus(static_cast(E_ERROR)); + } + int32_t count = cursor->GetCount(); + data.reserve(count); + auto err = cursor->MoveToFirst(); + while (err == E_OK && count > 0) { + DistributedData::VBucket entry; + err = cursor->GetEntry(entry); + if (err != E_OK) { + break; + } + data.emplace_back(ValueProxy::Convert(std::move(entry))); + err = cursor->MoveToNext(); + count--; + } + return ValueProxy::ConvertStatus(static_cast(err)); +} + +std::pair RdbCloud::Lock() +{ + auto error = cloudDB_->Lock(); + return std::make_pair(ValueProxy::ConvertStatus(static_cast(error)), 0); +} + +DBStatus RdbCloud::UnLock() +{ + auto error = cloudDB_->Unlock(); + return ValueProxy::ConvertStatus(static_cast(error)); +} + +DBStatus RdbCloud::HeartBeat() +{ + auto error = cloudDB_->Heartbeat(); + return ValueProxy::ConvertStatus(static_cast(error)); +} + +DBStatus RdbCloud::Close() +{ + auto error = cloudDB_->Close(); + return ValueProxy::ConvertStatus(static_cast(error)); +} +} // namespace OHOS::DistributedRdb \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h new file mode 100644 index 0000000000000000000000000000000000000000..4dcdca811de69c4d907003d29c0fef6428a9cfca --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_CLOUD_H +#define OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_CLOUD_H +#include "cloud/cloud_db.h" +#include "cloud/cloud_store_types.h" +#include "cloud/icloud_db.h" +#include "error/general_error.h" + +namespace OHOS::DistributedRdb { +class RdbCloud : public DistributedDB::ICloudDb { +public: + using DBStatus = DistributedDB::DBStatus; + using DBVBucket = DistributedDB::VBucket; + + RdbCloud(std::shared_ptr cloudDB); + ~RdbCloud() = default; + DBStatus BatchInsert(const std::string &tableName, std::vector &&record, + std::vector &extend) override; + DBStatus BatchUpdate(const std::string &tableName, std::vector &&record, + std::vector &extend) override; + DBStatus BatchDelete(const std::string &tableName, std::vector &extend) override; + DBStatus Query(const std::string &tableName, DBVBucket &extend, std::vector &data) override; + std::pair Lock() override; + DBStatus UnLock() override; + DBStatus HeartBeat() override; + DBStatus Close() override; + +private: + std::shared_ptr cloudDB_; +}; +} // namespace OHOS::DistributedRdb +#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_CLOUD_H diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp index 89f04736b1d384088dbe0638fd399a6984c201f6..277cbdf9ba3f99c0ec868b4c3a3dc5313bd937d6 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp @@ -22,6 +22,7 @@ #include "log_print.h" #include "metadata/meta_data_manager.h" #include "metadata/secret_key_meta_data.h" +#include "rdb_cloud.h" #include "rdb_cursor.h" #include "rdb_helper.h" #include "rdb_query.h" @@ -89,7 +90,11 @@ RdbGeneralStore::~RdbGeneralStore() int32_t RdbGeneralStore::Bind(const Database &database, BindInfo bindInfo) { bindInfo_ = std::move(bindInfo); - delegate_->SetCloudDB(nullptr); + if (bindInfo_.db_ == nullptr) { + ZLOGE("cloudDb is null"); + return GeneralError::E_ERROR; + } + delegate_->SetCloudDB(std::make_shared(bindInfo.db_)); DBSchema schema; schema.tables.resize(database.tables.size()); for (size_t i = 0; i < database.tables.size(); i++) { @@ -177,7 +182,7 @@ int32_t RdbGeneralStore::Sync(const Devices &devices, int32_t mode, GenQuery &qu ProgressDetails detail; detail.progress = process.process; detail.code = process.errCode == DBStatus::OK ? GeneralError::E_OK : GeneralError::E_ERROR; - for (auto [key, value] : process.tableProcess) { + for (auto &[key, value] : process.tableProcess) { TableDetails table; table.upload.total = value.upLoadInfo.total; table.upload.success = value.upLoadInfo.successCount; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp index 1d4c4e77948dcccfa2fc5a03e2700868c531a36b..07fae8991b2cb7da70491696aee367cb1d1d1fb6 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp @@ -13,8 +13,11 @@ * limitations under the License. */ +#define LOG_TAG "ValueProxy" +#include "log_print.h" #include "value_proxy.h" namespace OHOS::DistributedRdb { +using namespace OHOS::DistributedData; ValueProxy::Value ValueProxy::Convert(DistributedData::Value &&value) { Value proxy; @@ -29,6 +32,13 @@ ValueProxy::Value ValueProxy::Convert(NativeRdb::ValueObject &&value) return proxy; } +ValueProxy::Value ValueProxy::Convert(DistributedDB::Type &&value) +{ + Value proxy; + DistributedData::Convert(std::move(value), proxy.value_); + return proxy; +} + ValueProxy::Values ValueProxy::Convert(DistributedData::Values &&values) { Values proxy; @@ -67,6 +77,15 @@ ValueProxy::Bucket ValueProxy::Convert(NativeRdb::ValuesBucket &&bucket) return proxy; } +ValueProxy::Bucket ValueProxy::Convert(DistributedDB::VBucket &&bucket) +{ + ValueProxy::Bucket proxy; + for (auto &[key, value] : bucket) { + proxy.value_.insert_or_assign(key, Convert(std::move(value))); + } + return proxy; +} + ValueProxy::Buckets ValueProxy::Convert(std::vector &&buckets) { ValueProxy::Buckets proxy; @@ -77,6 +96,16 @@ ValueProxy::Buckets ValueProxy::Convert(std::vector &&b return proxy; } +ValueProxy::Buckets ValueProxy::Convert(std::vector &&buckets) +{ + ValueProxy::Buckets proxy; + proxy.value_.reserve(buckets.size()); + for (auto &bucket : buckets) { + proxy.value_.emplace_back(Convert(std::move(bucket))); + } + return proxy; +} + ValueProxy::Buckets ValueProxy::Convert(DistributedData::VBuckets &&buckets) { ValueProxy::Buckets proxy; @@ -257,9 +286,9 @@ ValueProxy::Value::operator DistributedData::Value() return value; } -ValueProxy::Value::operator DistributedDB::CloudValue() +ValueProxy::Value::operator DistributedDB::Type() { - DistributedDB::CloudValue value; + DistributedDB::Type value; DistributedData::Convert(std::move(value_), value); return value; } @@ -300,4 +329,27 @@ ValueProxy::Buckets &ValueProxy::Buckets::operator=(Buckets &&buckets) noexcept value_ = std::move(buckets.value_); return *this; } + +ValueProxy::DBStatus ValueProxy::ConvertStatus(DistributedData::GeneralError error) +{ + switch (error) { + case GeneralError::E_OK: + return DBStatus::OK; + case GeneralError::E_BUSY: + return DBStatus::BUSY; + case GeneralError::E_INVALID_ARGS: + return DBStatus::INVALID_ARGS; + case GeneralError::E_NOT_SUPPORT: + return DBStatus::NOT_SUPPORT; + case GeneralError::E_ERROR: // fallthrough + case GeneralError::E_NOT_INIT: + case GeneralError::E_ALREADY_CONSUMED: + case GeneralError::E_ALREADY_CLOSED: + return DBStatus::CLOUD_ERROR; + default: + ZLOGE("unknown error:0x%{public}x", error); + break; + } + return DBStatus::CLOUD_ERROR; +} } // namespace OHOS::DistributedRdb \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h index 3047e1cb83946a87f5076b37b56e3a90dc9868d4..861ff27e259db079e87ee240c08c9eca6e563bac 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h @@ -24,6 +24,7 @@ namespace OHOS::DistributedRdb { class ValueProxy final { public: using Bytes = DistributedData::Bytes; + using DBStatus = DistributedDB::DBStatus; class Asset { public: Asset() = default; @@ -83,7 +84,7 @@ public: Value &operator=(Value &&value) noexcept; operator NativeRdb::ValueObject(); operator DistributedData::Value(); - operator DistributedDB::CloudValue(); + operator DistributedDB::Type(); private: friend ValueProxy; @@ -170,6 +171,12 @@ public: static Buckets Convert(DistributedData::VBuckets &&buckets); static Buckets Convert(std::vector &&buckets); + static Value Convert(DistributedDB::Type &&value); + static Bucket Convert(DistributedDB::VBucket &&bucket); + static Buckets Convert(std::vector &&buckets); + + static DBStatus ConvertStatus(DistributedData::GeneralError error); + private: ValueProxy() = delete; ~ValueProxy() = delete; diff --git a/datamgr_service/services/distributeddataservice/service/test/cloud_data_test.cpp b/datamgr_service/services/distributeddataservice/service/test/cloud_data_test.cpp index 32057e30be51ce257bc54de3365e6917a5a773e0..7fb904fbde221dc33bfd5e412a70ea2010add73a 100644 --- a/datamgr_service/services/distributeddataservice/service/test/cloud_data_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/cloud_data_test.cpp @@ -80,7 +80,7 @@ CloudInfo CloudServerMock::GetServerInfo(int32_t userId) appInfo.version = 1; appInfo.cloudSwitch = true; - cloudInfo.apps.emplace_back(std::move(appInfo)); + cloudInfo.apps[TEST_CLOUD_BUNDLE] = std::move(appInfo); return cloudInfo; } diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/icloud_db.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/icloud_db.h index d9ca944511702535e721c0e1faee79a3c065d786..f5437a08bc792a8877b582258e27eebda1ab8db7 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/icloud_db.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/icloud_db.h @@ -33,8 +33,7 @@ public: std::vector &extend) = 0; virtual DBStatus BatchUpdate(const std::string &tableName, std::vector &&record, std::vector &extend) = 0; - virtual DBStatus BatchDelete(const std::string &tableName, std::vector &&record, - std::vector &extend) = 0; + virtual DBStatus BatchDelete(const std::string &tableName, std::vector &extend) = 0; /** ** param[out] data: query data **/ diff --git a/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h b/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h index 13b0fa66950da62771342b7847a2259518d830b5..84e854af67af94fede1116fa7a8ffdb86c7a1313 100644 --- a/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h +++ b/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h @@ -52,7 +52,8 @@ public: CLOUD_DISABLE_SWITCH, IPC_ERROR, IPC_PARCEL_ERROR, - PERMISSION_DENIED + PERMISSION_DENIED, + CLOUD_CONFIG_PERMISSION_DENIED }; virtual ~CloudService() = default; diff --git a/relational_store/test/native/rdb/unittest/rdb_store_subscribe_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_subscribe_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4853db4bba3ec25781520f245798d98b1893803f --- /dev/null +++ b/relational_store/test/native/rdb/unittest/rdb_store_subscribe_test.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include + +#include "common.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" +#include "rdb_store_manager.h" +#include "rdb_types.h" + +using namespace testing::ext; +using namespace OHOS::NativeRdb; +using namespace OHOS::DistributedRdb; + +class RdbStoreSubTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static const std::string MAIN_DATABASE_NAME; + static std::shared_ptr CreateRDB(int version); + static std::shared_ptr store; +}; + +const std::string RdbStoreSubTest::MAIN_DATABASE_NAME = RDB_TEST_PATH + "getrdb.db"; +std::shared_ptr RdbStoreSubTest::store = nullptr; + +void RdbStoreSubTest::SetUpTestCase(void) +{ + store = CreateRDB(1); +} + +void RdbStoreSubTest::TearDownTestCase(void) +{ +} + +void RdbStoreSubTest::SetUp() +{ +} + +void RdbStoreSubTest::TearDown() +{ +} + +class Callback : public RdbOpenCallback { +public: + int OnCreate(RdbStore &rdbStore) override; + int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override; +}; + +int Callback::OnCreate(RdbStore &store) +{ + return E_OK; +} + +int Callback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +class SubObserver : public RdbStoreObserver { +public: + virtual ~SubObserver() {} + void OnChange(const std::vector& devices) override; +}; + +void SubObserver::OnChange(const std::vector &devices) +{ +} + +std::shared_ptr RdbStoreSubTest::CreateRDB(int version) +{ + RdbStoreConfig config(RdbStoreSubTest::MAIN_DATABASE_NAME); + Callback helper; + int errCode = E_OK; + std::shared_ptr store = RdbHelper::GetRdbStore(config, version, helper, errCode); + EXPECT_NE(store, nullptr); + return store; +} + +/** + * @tc.name: RdbStoreSubscribeRemote + * @tc.desc: RdbStoreSubscribe + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(RdbStoreSubTest, RdbStoreSubscribeRemote, TestSize.Level1) +{ + EXPECT_NE(store, nullptr) << "store is nullptr"; + std::shared_ptr observer = std::make_shared(); + auto status = store->Subscribe({ SubscribeMode::REMOTE }, observer.get()); + EXPECT_EQ(status, E_OK); +} + +/** + * @tc.name: RdbStoreSubscribeCloud + * @tc.desc: RdbStoreSubscribe + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(RdbStoreSubTest, RdbStoreSubscribeCloud, TestSize.Level1) +{ + EXPECT_NE(store, nullptr) << "store is nullptr"; + std::shared_ptr observer = std::make_shared(); + auto status = store->Subscribe({ SubscribeMode::CLOUD }, observer.get()); + EXPECT_EQ(status, E_OK); +} + +/** + * @tc.name: RdbStoreSubscribeCloudDetail + * @tc.desc: RdbStoreSubscribe + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(RdbStoreSubTest, RdbStoreSubscribeCloudDetail, TestSize.Level1) +{ + EXPECT_NE(store, nullptr) << "store is nullptr"; + std::shared_ptr observer = std::make_shared(); + auto status = store->Subscribe({ SubscribeMode::CLOUD_DETAIL }, observer.get()); + EXPECT_EQ(status, E_OK); +} \ No newline at end of file